| .. | .. |
|---|
| 131 | 131 | |
|---|
| 132 | 132 | struct dev_ch_attribute { |
|---|
| 133 | 133 | struct device_attribute attr; |
|---|
| 134 | | - int channel; |
|---|
| 134 | + unsigned int channel; |
|---|
| 135 | 135 | }; |
|---|
| 136 | 136 | |
|---|
| 137 | 137 | #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \ |
|---|
| .. | .. |
|---|
| 200 | 200 | char *data) |
|---|
| 201 | 201 | { |
|---|
| 202 | 202 | struct csrow_info *csrow = to_csrow(dev); |
|---|
| 203 | | - unsigned chan = to_channel(mattr); |
|---|
| 203 | + unsigned int chan = to_channel(mattr); |
|---|
| 204 | 204 | struct rank_info *rank = csrow->channels[chan]; |
|---|
| 205 | 205 | |
|---|
| 206 | 206 | /* if field has not been initialized, there is nothing to send */ |
|---|
| .. | .. |
|---|
| 216 | 216 | const char *data, size_t count) |
|---|
| 217 | 217 | { |
|---|
| 218 | 218 | struct csrow_info *csrow = to_csrow(dev); |
|---|
| 219 | | - unsigned chan = to_channel(mattr); |
|---|
| 219 | + unsigned int chan = to_channel(mattr); |
|---|
| 220 | 220 | struct rank_info *rank = csrow->channels[chan]; |
|---|
| 221 | 221 | size_t copy_count = count; |
|---|
| 222 | 222 | |
|---|
| .. | .. |
|---|
| 240 | 240 | struct device_attribute *mattr, char *data) |
|---|
| 241 | 241 | { |
|---|
| 242 | 242 | struct csrow_info *csrow = to_csrow(dev); |
|---|
| 243 | | - unsigned chan = to_channel(mattr); |
|---|
| 243 | + unsigned int chan = to_channel(mattr); |
|---|
| 244 | 244 | struct rank_info *rank = csrow->channels[chan]; |
|---|
| 245 | 245 | |
|---|
| 246 | 246 | return sprintf(data, "%u\n", rank->ce_count); |
|---|
| .. | .. |
|---|
| 274 | 274 | NULL |
|---|
| 275 | 275 | }; |
|---|
| 276 | 276 | |
|---|
| 277 | | -static void csrow_attr_release(struct device *dev) |
|---|
| 278 | | -{ |
|---|
| 279 | | - struct csrow_info *csrow = container_of(dev, struct csrow_info, dev); |
|---|
| 280 | | - |
|---|
| 281 | | - edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev)); |
|---|
| 282 | | - kfree(csrow); |
|---|
| 283 | | -} |
|---|
| 284 | | - |
|---|
| 285 | 277 | static const struct device_type csrow_attr_type = { |
|---|
| 286 | 278 | .groups = csrow_attr_groups, |
|---|
| 287 | | - .release = csrow_attr_release, |
|---|
| 288 | 279 | }; |
|---|
| 289 | 280 | |
|---|
| 290 | 281 | /* |
|---|
| .. | .. |
|---|
| 390 | 381 | NULL |
|---|
| 391 | 382 | }; |
|---|
| 392 | 383 | |
|---|
| 384 | +static void csrow_release(struct device *dev) |
|---|
| 385 | +{ |
|---|
| 386 | + /* |
|---|
| 387 | + * Nothing to do, just unregister sysfs here. The mci |
|---|
| 388 | + * device owns the data and will also release it. |
|---|
| 389 | + */ |
|---|
| 390 | +} |
|---|
| 391 | + |
|---|
| 393 | 392 | static inline int nr_pages_per_csrow(struct csrow_info *csrow) |
|---|
| 394 | 393 | { |
|---|
| 395 | 394 | int chan, nr_pages = 0; |
|---|
| .. | .. |
|---|
| 407 | 406 | int err; |
|---|
| 408 | 407 | |
|---|
| 409 | 408 | csrow->dev.type = &csrow_attr_type; |
|---|
| 410 | | - csrow->dev.bus = mci->bus; |
|---|
| 411 | 409 | csrow->dev.groups = csrow_dev_groups; |
|---|
| 410 | + csrow->dev.release = csrow_release; |
|---|
| 412 | 411 | device_initialize(&csrow->dev); |
|---|
| 413 | 412 | csrow->dev.parent = &mci->dev; |
|---|
| 414 | 413 | csrow->mci = mci; |
|---|
| 415 | 414 | dev_set_name(&csrow->dev, "csrow%d", index); |
|---|
| 416 | 415 | dev_set_drvdata(&csrow->dev, csrow); |
|---|
| 417 | 416 | |
|---|
| 418 | | - edac_dbg(0, "creating (virtual) csrow node %s\n", |
|---|
| 419 | | - dev_name(&csrow->dev)); |
|---|
| 420 | | - |
|---|
| 421 | 417 | err = device_add(&csrow->dev); |
|---|
| 422 | | - if (err) |
|---|
| 418 | + if (err) { |
|---|
| 419 | + edac_dbg(1, "failure: create device %s\n", dev_name(&csrow->dev)); |
|---|
| 423 | 420 | put_device(&csrow->dev); |
|---|
| 421 | + return err; |
|---|
| 422 | + } |
|---|
| 424 | 423 | |
|---|
| 425 | | - return err; |
|---|
| 424 | + edac_dbg(0, "device %s created\n", dev_name(&csrow->dev)); |
|---|
| 425 | + |
|---|
| 426 | + return 0; |
|---|
| 426 | 427 | } |
|---|
| 427 | 428 | |
|---|
| 428 | 429 | /* Create a CSROW object under specifed edac_mc_device */ |
|---|
| .. | .. |
|---|
| 436 | 437 | if (!nr_pages_per_csrow(csrow)) |
|---|
| 437 | 438 | continue; |
|---|
| 438 | 439 | err = edac_create_csrow_object(mci, mci->csrows[i], i); |
|---|
| 439 | | - if (err < 0) { |
|---|
| 440 | | - edac_dbg(1, |
|---|
| 441 | | - "failure: create csrow objects for csrow %d\n", |
|---|
| 442 | | - i); |
|---|
| 440 | + if (err < 0) |
|---|
| 443 | 441 | goto error; |
|---|
| 444 | | - } |
|---|
| 445 | 442 | } |
|---|
| 446 | 443 | return 0; |
|---|
| 447 | 444 | |
|---|
| 448 | 445 | error: |
|---|
| 449 | 446 | for (--i; i >= 0; i--) { |
|---|
| 450 | | - csrow = mci->csrows[i]; |
|---|
| 451 | | - if (!nr_pages_per_csrow(csrow)) |
|---|
| 452 | | - continue; |
|---|
| 453 | | - put_device(&mci->csrows[i]->dev); |
|---|
| 447 | + if (device_is_registered(&mci->csrows[i]->dev)) |
|---|
| 448 | + device_unregister(&mci->csrows[i]->dev); |
|---|
| 454 | 449 | } |
|---|
| 455 | 450 | |
|---|
| 456 | 451 | return err; |
|---|
| .. | .. |
|---|
| 459 | 454 | static void edac_delete_csrow_objects(struct mem_ctl_info *mci) |
|---|
| 460 | 455 | { |
|---|
| 461 | 456 | int i; |
|---|
| 462 | | - struct csrow_info *csrow; |
|---|
| 463 | 457 | |
|---|
| 464 | | - for (i = mci->nr_csrows - 1; i >= 0; i--) { |
|---|
| 465 | | - csrow = mci->csrows[i]; |
|---|
| 466 | | - if (!nr_pages_per_csrow(csrow)) |
|---|
| 467 | | - continue; |
|---|
| 468 | | - device_unregister(&mci->csrows[i]->dev); |
|---|
| 458 | + for (i = 0; i < mci->nr_csrows; i++) { |
|---|
| 459 | + if (device_is_registered(&mci->csrows[i]->dev)) |
|---|
| 460 | + device_unregister(&mci->csrows[i]->dev); |
|---|
| 469 | 461 | } |
|---|
| 470 | 462 | } |
|---|
| 463 | + |
|---|
| 471 | 464 | #endif |
|---|
| 472 | 465 | |
|---|
| 473 | 466 | /* |
|---|
| .. | .. |
|---|
| 481 | 474 | struct device_attribute *mattr, char *data) |
|---|
| 482 | 475 | { |
|---|
| 483 | 476 | struct dimm_info *dimm = to_dimm(dev); |
|---|
| 477 | + ssize_t count; |
|---|
| 484 | 478 | |
|---|
| 485 | | - return edac_dimm_info_location(dimm, data, PAGE_SIZE); |
|---|
| 479 | + count = edac_dimm_info_location(dimm, data, PAGE_SIZE); |
|---|
| 480 | + count += scnprintf(data + count, PAGE_SIZE - count, "\n"); |
|---|
| 481 | + |
|---|
| 482 | + return count; |
|---|
| 486 | 483 | } |
|---|
| 487 | 484 | |
|---|
| 488 | 485 | static ssize_t dimmdev_label_show(struct device *dev, |
|---|
| .. | .. |
|---|
| 558 | 555 | char *data) |
|---|
| 559 | 556 | { |
|---|
| 560 | 557 | struct dimm_info *dimm = to_dimm(dev); |
|---|
| 561 | | - u32 count; |
|---|
| 562 | | - int off; |
|---|
| 563 | 558 | |
|---|
| 564 | | - off = EDAC_DIMM_OFF(dimm->mci->layers, |
|---|
| 565 | | - dimm->mci->n_layers, |
|---|
| 566 | | - dimm->location[0], |
|---|
| 567 | | - dimm->location[1], |
|---|
| 568 | | - dimm->location[2]); |
|---|
| 569 | | - count = dimm->mci->ce_per_layer[dimm->mci->n_layers-1][off]; |
|---|
| 570 | | - return sprintf(data, "%u\n", count); |
|---|
| 559 | + return sprintf(data, "%u\n", dimm->ce_count); |
|---|
| 571 | 560 | } |
|---|
| 572 | 561 | |
|---|
| 573 | 562 | static ssize_t dimmdev_ue_count_show(struct device *dev, |
|---|
| .. | .. |
|---|
| 575 | 564 | char *data) |
|---|
| 576 | 565 | { |
|---|
| 577 | 566 | struct dimm_info *dimm = to_dimm(dev); |
|---|
| 578 | | - u32 count; |
|---|
| 579 | | - int off; |
|---|
| 580 | 567 | |
|---|
| 581 | | - off = EDAC_DIMM_OFF(dimm->mci->layers, |
|---|
| 582 | | - dimm->mci->n_layers, |
|---|
| 583 | | - dimm->location[0], |
|---|
| 584 | | - dimm->location[1], |
|---|
| 585 | | - dimm->location[2]); |
|---|
| 586 | | - count = dimm->mci->ue_per_layer[dimm->mci->n_layers-1][off]; |
|---|
| 587 | | - return sprintf(data, "%u\n", count); |
|---|
| 568 | + return sprintf(data, "%u\n", dimm->ue_count); |
|---|
| 588 | 569 | } |
|---|
| 589 | 570 | |
|---|
| 590 | 571 | /* dimm/rank attribute files */ |
|---|
| .. | .. |
|---|
| 620 | 601 | NULL |
|---|
| 621 | 602 | }; |
|---|
| 622 | 603 | |
|---|
| 623 | | -static void dimm_attr_release(struct device *dev) |
|---|
| 624 | | -{ |
|---|
| 625 | | - struct dimm_info *dimm = container_of(dev, struct dimm_info, dev); |
|---|
| 626 | | - |
|---|
| 627 | | - edac_dbg(1, "Releasing dimm device %s\n", dev_name(dev)); |
|---|
| 628 | | - kfree(dimm); |
|---|
| 629 | | -} |
|---|
| 630 | | - |
|---|
| 631 | 604 | static const struct device_type dimm_attr_type = { |
|---|
| 632 | 605 | .groups = dimm_attr_groups, |
|---|
| 633 | | - .release = dimm_attr_release, |
|---|
| 634 | 606 | }; |
|---|
| 607 | + |
|---|
| 608 | +static void dimm_release(struct device *dev) |
|---|
| 609 | +{ |
|---|
| 610 | + /* |
|---|
| 611 | + * Nothing to do, just unregister sysfs here. The mci |
|---|
| 612 | + * device owns the data and will also release it. |
|---|
| 613 | + */ |
|---|
| 614 | +} |
|---|
| 635 | 615 | |
|---|
| 636 | 616 | /* Create a DIMM object under specifed memory controller device */ |
|---|
| 637 | 617 | static int edac_create_dimm_object(struct mem_ctl_info *mci, |
|---|
| 638 | | - struct dimm_info *dimm, |
|---|
| 639 | | - int index) |
|---|
| 618 | + struct dimm_info *dimm) |
|---|
| 640 | 619 | { |
|---|
| 641 | 620 | int err; |
|---|
| 642 | 621 | dimm->mci = mci; |
|---|
| 643 | 622 | |
|---|
| 644 | 623 | dimm->dev.type = &dimm_attr_type; |
|---|
| 645 | | - dimm->dev.bus = mci->bus; |
|---|
| 624 | + dimm->dev.release = dimm_release; |
|---|
| 646 | 625 | device_initialize(&dimm->dev); |
|---|
| 647 | 626 | |
|---|
| 648 | 627 | dimm->dev.parent = &mci->dev; |
|---|
| 649 | 628 | if (mci->csbased) |
|---|
| 650 | | - dev_set_name(&dimm->dev, "rank%d", index); |
|---|
| 629 | + dev_set_name(&dimm->dev, "rank%d", dimm->idx); |
|---|
| 651 | 630 | else |
|---|
| 652 | | - dev_set_name(&dimm->dev, "dimm%d", index); |
|---|
| 631 | + dev_set_name(&dimm->dev, "dimm%d", dimm->idx); |
|---|
| 653 | 632 | dev_set_drvdata(&dimm->dev, dimm); |
|---|
| 654 | 633 | pm_runtime_forbid(&mci->dev); |
|---|
| 655 | 634 | |
|---|
| 656 | | - err = device_add(&dimm->dev); |
|---|
| 635 | + err = device_add(&dimm->dev); |
|---|
| 636 | + if (err) { |
|---|
| 637 | + edac_dbg(1, "failure: create device %s\n", dev_name(&dimm->dev)); |
|---|
| 638 | + put_device(&dimm->dev); |
|---|
| 639 | + return err; |
|---|
| 640 | + } |
|---|
| 657 | 641 | |
|---|
| 658 | | - edac_dbg(0, "creating rank/dimm device %s\n", dev_name(&dimm->dev)); |
|---|
| 642 | + if (IS_ENABLED(CONFIG_EDAC_DEBUG)) { |
|---|
| 643 | + char location[80]; |
|---|
| 659 | 644 | |
|---|
| 660 | | - return err; |
|---|
| 645 | + edac_dimm_info_location(dimm, location, sizeof(location)); |
|---|
| 646 | + edac_dbg(0, "device %s created at location %s\n", |
|---|
| 647 | + dev_name(&dimm->dev), location); |
|---|
| 648 | + } |
|---|
| 649 | + |
|---|
| 650 | + return 0; |
|---|
| 661 | 651 | } |
|---|
| 662 | 652 | |
|---|
| 663 | 653 | /* |
|---|
| .. | .. |
|---|
| 671 | 661 | const char *data, size_t count) |
|---|
| 672 | 662 | { |
|---|
| 673 | 663 | struct mem_ctl_info *mci = to_mci(dev); |
|---|
| 674 | | - int cnt, row, chan, i; |
|---|
| 664 | + struct dimm_info *dimm; |
|---|
| 665 | + int row, chan; |
|---|
| 666 | + |
|---|
| 675 | 667 | mci->ue_mc = 0; |
|---|
| 676 | 668 | mci->ce_mc = 0; |
|---|
| 677 | 669 | mci->ue_noinfo_count = 0; |
|---|
| .. | .. |
|---|
| 687 | 679 | ri->channels[chan]->ce_count = 0; |
|---|
| 688 | 680 | } |
|---|
| 689 | 681 | |
|---|
| 690 | | - cnt = 1; |
|---|
| 691 | | - for (i = 0; i < mci->n_layers; i++) { |
|---|
| 692 | | - cnt *= mci->layers[i].size; |
|---|
| 693 | | - memset(mci->ce_per_layer[i], 0, cnt * sizeof(u32)); |
|---|
| 694 | | - memset(mci->ue_per_layer[i], 0, cnt * sizeof(u32)); |
|---|
| 682 | + mci_for_each_dimm(mci, dimm) { |
|---|
| 683 | + dimm->ue_count = 0; |
|---|
| 684 | + dimm->ce_count = 0; |
|---|
| 695 | 685 | } |
|---|
| 696 | 686 | |
|---|
| 697 | 687 | mci->start_time = jiffies; |
|---|
| .. | .. |
|---|
| 827 | 817 | char *data) |
|---|
| 828 | 818 | { |
|---|
| 829 | 819 | struct mem_ctl_info *mci = to_mci(dev); |
|---|
| 830 | | - int i; |
|---|
| 820 | + int len = PAGE_SIZE; |
|---|
| 831 | 821 | char *p = data; |
|---|
| 822 | + int i, n; |
|---|
| 832 | 823 | |
|---|
| 833 | 824 | for (i = 0; i < mci->n_layers; i++) { |
|---|
| 834 | | - p += sprintf(p, "%s %d ", |
|---|
| 835 | | - edac_layer_name[mci->layers[i].type], |
|---|
| 836 | | - mci->layers[i].size - 1); |
|---|
| 825 | + n = scnprintf(p, len, "%s %d ", |
|---|
| 826 | + edac_layer_name[mci->layers[i].type], |
|---|
| 827 | + mci->layers[i].size - 1); |
|---|
| 828 | + len -= n; |
|---|
| 829 | + if (len <= 0) |
|---|
| 830 | + goto out; |
|---|
| 831 | + |
|---|
| 832 | + p += n; |
|---|
| 837 | 833 | } |
|---|
| 838 | 834 | |
|---|
| 835 | + p += scnprintf(p, len, "\n"); |
|---|
| 836 | +out: |
|---|
| 839 | 837 | return p - data; |
|---|
| 840 | 838 | } |
|---|
| 841 | 839 | |
|---|
| .. | .. |
|---|
| 896 | 894 | NULL |
|---|
| 897 | 895 | }; |
|---|
| 898 | 896 | |
|---|
| 899 | | -static void mci_attr_release(struct device *dev) |
|---|
| 900 | | -{ |
|---|
| 901 | | - struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev); |
|---|
| 902 | | - |
|---|
| 903 | | - edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev)); |
|---|
| 904 | | - kfree(mci); |
|---|
| 905 | | -} |
|---|
| 906 | | - |
|---|
| 907 | 897 | static const struct device_type mci_attr_type = { |
|---|
| 908 | 898 | .groups = mci_attr_groups, |
|---|
| 909 | | - .release = mci_attr_release, |
|---|
| 910 | 899 | }; |
|---|
| 911 | 900 | |
|---|
| 912 | 901 | /* |
|---|
| .. | .. |
|---|
| 920 | 909 | int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, |
|---|
| 921 | 910 | const struct attribute_group **groups) |
|---|
| 922 | 911 | { |
|---|
| 923 | | - char *name; |
|---|
| 924 | | - int i, err; |
|---|
| 925 | | - |
|---|
| 926 | | - /* |
|---|
| 927 | | - * The memory controller needs its own bus, in order to avoid |
|---|
| 928 | | - * namespace conflicts at /sys/bus/edac. |
|---|
| 929 | | - */ |
|---|
| 930 | | - name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); |
|---|
| 931 | | - if (!name) |
|---|
| 932 | | - return -ENOMEM; |
|---|
| 933 | | - |
|---|
| 934 | | - mci->bus->name = name; |
|---|
| 935 | | - |
|---|
| 936 | | - edac_dbg(0, "creating bus %s\n", mci->bus->name); |
|---|
| 937 | | - |
|---|
| 938 | | - err = bus_register(mci->bus); |
|---|
| 939 | | - if (err < 0) { |
|---|
| 940 | | - kfree(name); |
|---|
| 941 | | - return err; |
|---|
| 942 | | - } |
|---|
| 912 | + struct dimm_info *dimm; |
|---|
| 913 | + int err; |
|---|
| 943 | 914 | |
|---|
| 944 | 915 | /* get the /sys/devices/system/edac subsys reference */ |
|---|
| 945 | 916 | mci->dev.type = &mci_attr_type; |
|---|
| 946 | | - device_initialize(&mci->dev); |
|---|
| 947 | | - |
|---|
| 948 | 917 | mci->dev.parent = mci_pdev; |
|---|
| 949 | | - mci->dev.bus = mci->bus; |
|---|
| 950 | 918 | mci->dev.groups = groups; |
|---|
| 951 | 919 | dev_set_name(&mci->dev, "mc%d", mci->mc_idx); |
|---|
| 952 | 920 | dev_set_drvdata(&mci->dev, mci); |
|---|
| 953 | 921 | pm_runtime_forbid(&mci->dev); |
|---|
| 954 | 922 | |
|---|
| 955 | | - edac_dbg(0, "creating device %s\n", dev_name(&mci->dev)); |
|---|
| 956 | 923 | err = device_add(&mci->dev); |
|---|
| 957 | 924 | if (err < 0) { |
|---|
| 958 | 925 | edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev)); |
|---|
| 959 | | - goto fail_unregister_bus; |
|---|
| 926 | + /* no put_device() here, free mci with _edac_mc_free() */ |
|---|
| 927 | + return err; |
|---|
| 960 | 928 | } |
|---|
| 929 | + |
|---|
| 930 | + edac_dbg(0, "device %s created\n", dev_name(&mci->dev)); |
|---|
| 961 | 931 | |
|---|
| 962 | 932 | /* |
|---|
| 963 | 933 | * Create the dimm/rank devices |
|---|
| 964 | 934 | */ |
|---|
| 965 | | - for (i = 0; i < mci->tot_dimms; i++) { |
|---|
| 966 | | - struct dimm_info *dimm = mci->dimms[i]; |
|---|
| 935 | + mci_for_each_dimm(mci, dimm) { |
|---|
| 967 | 936 | /* Only expose populated DIMMs */ |
|---|
| 968 | 937 | if (!dimm->nr_pages) |
|---|
| 969 | 938 | continue; |
|---|
| 970 | 939 | |
|---|
| 971 | | -#ifdef CONFIG_EDAC_DEBUG |
|---|
| 972 | | - edac_dbg(1, "creating dimm%d, located at ", i); |
|---|
| 973 | | - if (edac_debug_level >= 1) { |
|---|
| 974 | | - int lay; |
|---|
| 975 | | - for (lay = 0; lay < mci->n_layers; lay++) |
|---|
| 976 | | - printk(KERN_CONT "%s %d ", |
|---|
| 977 | | - edac_layer_name[mci->layers[lay].type], |
|---|
| 978 | | - dimm->location[lay]); |
|---|
| 979 | | - printk(KERN_CONT "\n"); |
|---|
| 980 | | - } |
|---|
| 981 | | -#endif |
|---|
| 982 | | - err = edac_create_dimm_object(mci, dimm, i); |
|---|
| 983 | | - if (err) { |
|---|
| 984 | | - edac_dbg(1, "failure: create dimm %d obj\n", i); |
|---|
| 985 | | - goto fail_unregister_dimm; |
|---|
| 986 | | - } |
|---|
| 940 | + err = edac_create_dimm_object(mci, dimm); |
|---|
| 941 | + if (err) |
|---|
| 942 | + goto fail; |
|---|
| 987 | 943 | } |
|---|
| 988 | 944 | |
|---|
| 989 | 945 | #ifdef CONFIG_EDAC_LEGACY_SYSFS |
|---|
| 990 | 946 | err = edac_create_csrow_objects(mci); |
|---|
| 991 | 947 | if (err < 0) |
|---|
| 992 | | - goto fail_unregister_dimm; |
|---|
| 948 | + goto fail; |
|---|
| 993 | 949 | #endif |
|---|
| 994 | 950 | |
|---|
| 995 | 951 | edac_create_debugfs_nodes(mci); |
|---|
| 996 | 952 | return 0; |
|---|
| 997 | 953 | |
|---|
| 998 | | -fail_unregister_dimm: |
|---|
| 999 | | - for (i--; i >= 0; i--) { |
|---|
| 1000 | | - struct dimm_info *dimm = mci->dimms[i]; |
|---|
| 1001 | | - if (!dimm->nr_pages) |
|---|
| 1002 | | - continue; |
|---|
| 1003 | | - |
|---|
| 1004 | | - device_unregister(&dimm->dev); |
|---|
| 1005 | | - } |
|---|
| 1006 | | - device_unregister(&mci->dev); |
|---|
| 1007 | | -fail_unregister_bus: |
|---|
| 1008 | | - bus_unregister(mci->bus); |
|---|
| 1009 | | - kfree(name); |
|---|
| 954 | +fail: |
|---|
| 955 | + edac_remove_sysfs_mci_device(mci); |
|---|
| 1010 | 956 | |
|---|
| 1011 | 957 | return err; |
|---|
| 1012 | 958 | } |
|---|
| .. | .. |
|---|
| 1016 | 962 | */ |
|---|
| 1017 | 963 | void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) |
|---|
| 1018 | 964 | { |
|---|
| 1019 | | - int i; |
|---|
| 965 | + struct dimm_info *dimm; |
|---|
| 966 | + |
|---|
| 967 | + if (!device_is_registered(&mci->dev)) |
|---|
| 968 | + return; |
|---|
| 1020 | 969 | |
|---|
| 1021 | 970 | edac_dbg(0, "\n"); |
|---|
| 1022 | 971 | |
|---|
| .. | .. |
|---|
| 1027 | 976 | edac_delete_csrow_objects(mci); |
|---|
| 1028 | 977 | #endif |
|---|
| 1029 | 978 | |
|---|
| 1030 | | - for (i = 0; i < mci->tot_dimms; i++) { |
|---|
| 1031 | | - struct dimm_info *dimm = mci->dimms[i]; |
|---|
| 1032 | | - if (dimm->nr_pages == 0) |
|---|
| 979 | + mci_for_each_dimm(mci, dimm) { |
|---|
| 980 | + if (!device_is_registered(&dimm->dev)) |
|---|
| 1033 | 981 | continue; |
|---|
| 1034 | | - edac_dbg(0, "removing device %s\n", dev_name(&dimm->dev)); |
|---|
| 982 | + edac_dbg(1, "unregistering device %s\n", dev_name(&dimm->dev)); |
|---|
| 1035 | 983 | device_unregister(&dimm->dev); |
|---|
| 1036 | 984 | } |
|---|
| 1037 | | -} |
|---|
| 1038 | 985 | |
|---|
| 1039 | | -void edac_unregister_sysfs(struct mem_ctl_info *mci) |
|---|
| 1040 | | -{ |
|---|
| 1041 | | - struct bus_type *bus = mci->bus; |
|---|
| 1042 | | - const char *name = mci->bus->name; |
|---|
| 1043 | | - |
|---|
| 1044 | | - edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev)); |
|---|
| 1045 | | - device_unregister(&mci->dev); |
|---|
| 1046 | | - bus_unregister(bus); |
|---|
| 1047 | | - kfree(name); |
|---|
| 986 | + /* only remove the device, but keep mci */ |
|---|
| 987 | + device_del(&mci->dev); |
|---|
| 1048 | 988 | } |
|---|
| 1049 | 989 | |
|---|
| 1050 | 990 | static void mc_attr_release(struct device *dev) |
|---|
| .. | .. |
|---|
| 1054 | 994 | * parent device, used to create the /sys/devices/mc sysfs node. |
|---|
| 1055 | 995 | * So, there are no attributes on it. |
|---|
| 1056 | 996 | */ |
|---|
| 1057 | | - edac_dbg(1, "Releasing device %s\n", dev_name(dev)); |
|---|
| 997 | + edac_dbg(1, "device %s released\n", dev_name(dev)); |
|---|
| 1058 | 998 | kfree(dev); |
|---|
| 1059 | 999 | } |
|---|
| 1060 | 1000 | |
|---|
| 1061 | | -static const struct device_type mc_attr_type = { |
|---|
| 1062 | | - .release = mc_attr_release, |
|---|
| 1063 | | -}; |
|---|
| 1064 | 1001 | /* |
|---|
| 1065 | 1002 | * Init/exit code for the module. Basically, creates/removes /sys/class/rc |
|---|
| 1066 | 1003 | */ |
|---|
| .. | .. |
|---|
| 1069 | 1006 | int err; |
|---|
| 1070 | 1007 | |
|---|
| 1071 | 1008 | mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL); |
|---|
| 1072 | | - if (!mci_pdev) { |
|---|
| 1073 | | - err = -ENOMEM; |
|---|
| 1074 | | - goto out; |
|---|
| 1075 | | - } |
|---|
| 1009 | + if (!mci_pdev) |
|---|
| 1010 | + return -ENOMEM; |
|---|
| 1076 | 1011 | |
|---|
| 1077 | 1012 | mci_pdev->bus = edac_get_sysfs_subsys(); |
|---|
| 1078 | | - mci_pdev->type = &mc_attr_type; |
|---|
| 1079 | | - device_initialize(mci_pdev); |
|---|
| 1080 | | - dev_set_name(mci_pdev, "mc"); |
|---|
| 1013 | + mci_pdev->release = mc_attr_release; |
|---|
| 1014 | + mci_pdev->init_name = "mc"; |
|---|
| 1081 | 1015 | |
|---|
| 1082 | | - err = device_add(mci_pdev); |
|---|
| 1083 | | - if (err < 0) |
|---|
| 1084 | | - goto out_put_device; |
|---|
| 1016 | + err = device_register(mci_pdev); |
|---|
| 1017 | + if (err < 0) { |
|---|
| 1018 | + edac_dbg(1, "failure: create device %s\n", dev_name(mci_pdev)); |
|---|
| 1019 | + put_device(mci_pdev); |
|---|
| 1020 | + return err; |
|---|
| 1021 | + } |
|---|
| 1085 | 1022 | |
|---|
| 1086 | 1023 | edac_dbg(0, "device %s created\n", dev_name(mci_pdev)); |
|---|
| 1087 | 1024 | |
|---|
| 1088 | 1025 | return 0; |
|---|
| 1089 | | - |
|---|
| 1090 | | - out_put_device: |
|---|
| 1091 | | - put_device(mci_pdev); |
|---|
| 1092 | | - out: |
|---|
| 1093 | | - return err; |
|---|
| 1094 | 1026 | } |
|---|
| 1095 | 1027 | |
|---|
| 1096 | 1028 | void edac_mc_sysfs_exit(void) |
|---|