| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * coretemp.c - Linux kernel module for hardware monitoring |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz> |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Inspired from many hwmon drivers |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 10 | | - * the Free Software Foundation; version 2 of the License. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | | - * GNU General Public License for more details. |
|---|
| 16 | | - * |
|---|
| 17 | | - * You should have received a copy of the GNU General Public License |
|---|
| 18 | | - * along with this program; if not, write to the Free Software |
|---|
| 19 | | - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|---|
| 20 | | - * 02110-1301 USA. |
|---|
| 21 | 8 | */ |
|---|
| 22 | 9 | |
|---|
| 23 | 10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 58 | 45 | #define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */ |
|---|
| 59 | 46 | #define TOTAL_ATTRS (MAX_CORE_ATTRS + 1) |
|---|
| 60 | 47 | #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) |
|---|
| 61 | | - |
|---|
| 62 | | -#define TO_CORE_ID(cpu) (cpu_data(cpu).cpu_core_id) |
|---|
| 63 | | -#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) |
|---|
| 64 | 48 | |
|---|
| 65 | 49 | #ifdef CONFIG_SMP |
|---|
| 66 | 50 | #define for_each_sibling(i, cpu) \ |
|---|
| .. | .. |
|---|
| 104 | 88 | struct platform_data { |
|---|
| 105 | 89 | struct device *hwmon_dev; |
|---|
| 106 | 90 | u16 pkg_id; |
|---|
| 91 | + u16 cpu_map[NUM_REAL_CORES]; |
|---|
| 92 | + struct ida ida; |
|---|
| 107 | 93 | struct cpumask cpumask; |
|---|
| 108 | 94 | struct temp_data *core_data[MAX_CORE_DATA]; |
|---|
| 109 | 95 | struct device_attribute name_attr; |
|---|
| 110 | 96 | }; |
|---|
| 111 | 97 | |
|---|
| 112 | | -/* Keep track of how many package pointers we allocated in init() */ |
|---|
| 113 | | -static int max_packages __read_mostly; |
|---|
| 114 | | -/* Array of package pointers. Serialized by cpu hotplug lock */ |
|---|
| 115 | | -static struct platform_device **pkg_devices; |
|---|
| 98 | +/* Keep track of how many zone pointers we allocated in init() */ |
|---|
| 99 | +static int max_zones __read_mostly; |
|---|
| 100 | +/* Array of zone pointers. Serialized by cpu hotplug lock */ |
|---|
| 101 | +static struct platform_device **zone_devices; |
|---|
| 116 | 102 | |
|---|
| 117 | 103 | static ssize_t show_label(struct device *dev, |
|---|
| 118 | 104 | struct device_attribute *devattr, char *buf) |
|---|
| .. | .. |
|---|
| 256 | 242 | */ |
|---|
| 257 | 243 | if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL) { |
|---|
| 258 | 244 | for (i = 0; i < ARRAY_SIZE(tjmax_pci_table); i++) { |
|---|
| 259 | | - if (host_bridge->device == tjmax_pci_table[i].device) |
|---|
| 245 | + if (host_bridge->device == tjmax_pci_table[i].device) { |
|---|
| 246 | + pci_dev_put(host_bridge); |
|---|
| 260 | 247 | return tjmax_pci_table[i].tjmax; |
|---|
| 248 | + } |
|---|
| 261 | 249 | } |
|---|
| 262 | 250 | } |
|---|
| 251 | + pci_dev_put(host_bridge); |
|---|
| 263 | 252 | |
|---|
| 264 | 253 | for (i = 0; i < ARRAY_SIZE(tjmax_table); i++) { |
|---|
| 265 | 254 | if (strstr(c->x86_model_id, tjmax_table[i].id)) |
|---|
| .. | .. |
|---|
| 407 | 396 | "temp%d_%s", attr_no, suffixes[i]); |
|---|
| 408 | 397 | sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr); |
|---|
| 409 | 398 | tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i]; |
|---|
| 410 | | - tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO; |
|---|
| 399 | + tdata->sd_attrs[i].dev_attr.attr.mode = 0444; |
|---|
| 411 | 400 | tdata->sd_attrs[i].dev_attr.show = rd_ptr[i]; |
|---|
| 412 | 401 | tdata->sd_attrs[i].index = attr_no; |
|---|
| 413 | 402 | tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr; |
|---|
| .. | .. |
|---|
| 435 | 424 | |
|---|
| 436 | 425 | static struct platform_device *coretemp_get_pdev(unsigned int cpu) |
|---|
| 437 | 426 | { |
|---|
| 438 | | - int pkgid = topology_logical_package_id(cpu); |
|---|
| 427 | + int id = topology_logical_die_id(cpu); |
|---|
| 439 | 428 | |
|---|
| 440 | | - if (pkgid >= 0 && pkgid < max_packages) |
|---|
| 441 | | - return pkg_devices[pkgid]; |
|---|
| 429 | + if (id >= 0 && id < max_zones) |
|---|
| 430 | + return zone_devices[id]; |
|---|
| 442 | 431 | return NULL; |
|---|
| 443 | 432 | } |
|---|
| 444 | 433 | |
|---|
| .. | .. |
|---|
| 454 | 443 | MSR_IA32_THERM_STATUS; |
|---|
| 455 | 444 | tdata->is_pkg_data = pkg_flag; |
|---|
| 456 | 445 | tdata->cpu = cpu; |
|---|
| 457 | | - tdata->cpu_core_id = TO_CORE_ID(cpu); |
|---|
| 446 | + tdata->cpu_core_id = topology_core_id(cpu); |
|---|
| 458 | 447 | tdata->attr_size = MAX_CORE_ATTRS; |
|---|
| 459 | 448 | mutex_init(&tdata->update_lock); |
|---|
| 460 | 449 | return tdata; |
|---|
| .. | .. |
|---|
| 467 | 456 | struct platform_data *pdata = platform_get_drvdata(pdev); |
|---|
| 468 | 457 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
|---|
| 469 | 458 | u32 eax, edx; |
|---|
| 470 | | - int err, attr_no; |
|---|
| 459 | + int err, index, attr_no; |
|---|
| 471 | 460 | |
|---|
| 472 | 461 | /* |
|---|
| 473 | 462 | * Find attr number for sysfs: |
|---|
| .. | .. |
|---|
| 475 | 464 | * The attr number is always core id + 2 |
|---|
| 476 | 465 | * The Pkgtemp will always show up as temp1_*, if available |
|---|
| 477 | 466 | */ |
|---|
| 478 | | - attr_no = pkg_flag ? PKG_SYSFS_ATTR_NO : TO_ATTR_NO(cpu); |
|---|
| 467 | + if (pkg_flag) { |
|---|
| 468 | + attr_no = PKG_SYSFS_ATTR_NO; |
|---|
| 469 | + } else { |
|---|
| 470 | + index = ida_alloc(&pdata->ida, GFP_KERNEL); |
|---|
| 471 | + if (index < 0) |
|---|
| 472 | + return index; |
|---|
| 473 | + pdata->cpu_map[index] = topology_core_id(cpu); |
|---|
| 474 | + attr_no = index + BASE_SYSFS_ATTR_NO; |
|---|
| 475 | + } |
|---|
| 479 | 476 | |
|---|
| 480 | | - if (attr_no > MAX_CORE_DATA - 1) |
|---|
| 481 | | - return -ERANGE; |
|---|
| 477 | + if (attr_no > MAX_CORE_DATA - 1) { |
|---|
| 478 | + err = -ERANGE; |
|---|
| 479 | + goto ida_free; |
|---|
| 480 | + } |
|---|
| 482 | 481 | |
|---|
| 483 | 482 | tdata = init_temp_data(cpu, pkg_flag); |
|---|
| 484 | | - if (!tdata) |
|---|
| 485 | | - return -ENOMEM; |
|---|
| 483 | + if (!tdata) { |
|---|
| 484 | + err = -ENOMEM; |
|---|
| 485 | + goto ida_free; |
|---|
| 486 | + } |
|---|
| 486 | 487 | |
|---|
| 487 | 488 | /* Test if we can access the status register */ |
|---|
| 488 | 489 | err = rdmsr_safe_on_cpu(cpu, tdata->status_reg, &eax, &edx); |
|---|
| .. | .. |
|---|
| 518 | 519 | exit_free: |
|---|
| 519 | 520 | pdata->core_data[attr_no] = NULL; |
|---|
| 520 | 521 | kfree(tdata); |
|---|
| 522 | +ida_free: |
|---|
| 523 | + if (!pkg_flag) |
|---|
| 524 | + ida_free(&pdata->ida, index); |
|---|
| 521 | 525 | return err; |
|---|
| 522 | 526 | } |
|---|
| 523 | 527 | |
|---|
| .. | .. |
|---|
| 532 | 536 | { |
|---|
| 533 | 537 | struct temp_data *tdata = pdata->core_data[indx]; |
|---|
| 534 | 538 | |
|---|
| 539 | + /* if we errored on add then this is already gone */ |
|---|
| 540 | + if (!tdata) |
|---|
| 541 | + return; |
|---|
| 542 | + |
|---|
| 535 | 543 | /* Remove the sysfs attributes */ |
|---|
| 536 | 544 | sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group); |
|---|
| 537 | 545 | |
|---|
| 538 | 546 | kfree(pdata->core_data[indx]); |
|---|
| 539 | 547 | pdata->core_data[indx] = NULL; |
|---|
| 548 | + |
|---|
| 549 | + if (indx >= BASE_SYSFS_ATTR_NO) |
|---|
| 550 | + ida_free(&pdata->ida, indx - BASE_SYSFS_ATTR_NO); |
|---|
| 540 | 551 | } |
|---|
| 541 | 552 | |
|---|
| 542 | | -static int coretemp_probe(struct platform_device *pdev) |
|---|
| 553 | +static int coretemp_device_add(int zoneid) |
|---|
| 543 | 554 | { |
|---|
| 544 | | - struct device *dev = &pdev->dev; |
|---|
| 555 | + struct platform_device *pdev; |
|---|
| 545 | 556 | struct platform_data *pdata; |
|---|
| 557 | + int err; |
|---|
| 546 | 558 | |
|---|
| 547 | | - /* Initialize the per-package data structures */ |
|---|
| 548 | | - pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL); |
|---|
| 559 | + /* Initialize the per-zone data structures */ |
|---|
| 560 | + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); |
|---|
| 549 | 561 | if (!pdata) |
|---|
| 550 | 562 | return -ENOMEM; |
|---|
| 551 | 563 | |
|---|
| 552 | | - pdata->pkg_id = pdev->id; |
|---|
| 553 | | - platform_set_drvdata(pdev, pdata); |
|---|
| 564 | + pdata->pkg_id = zoneid; |
|---|
| 565 | + ida_init(&pdata->ida); |
|---|
| 554 | 566 | |
|---|
| 555 | | - pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME, |
|---|
| 556 | | - pdata, NULL); |
|---|
| 557 | | - return PTR_ERR_OR_ZERO(pdata->hwmon_dev); |
|---|
| 558 | | -} |
|---|
| 559 | | - |
|---|
| 560 | | -static int coretemp_remove(struct platform_device *pdev) |
|---|
| 561 | | -{ |
|---|
| 562 | | - struct platform_data *pdata = platform_get_drvdata(pdev); |
|---|
| 563 | | - int i; |
|---|
| 564 | | - |
|---|
| 565 | | - for (i = MAX_CORE_DATA - 1; i >= 0; --i) |
|---|
| 566 | | - if (pdata->core_data[i]) |
|---|
| 567 | | - coretemp_remove_core(pdata, i); |
|---|
| 568 | | - |
|---|
| 569 | | - return 0; |
|---|
| 570 | | -} |
|---|
| 571 | | - |
|---|
| 572 | | -static struct platform_driver coretemp_driver = { |
|---|
| 573 | | - .driver = { |
|---|
| 574 | | - .name = DRVNAME, |
|---|
| 575 | | - }, |
|---|
| 576 | | - .probe = coretemp_probe, |
|---|
| 577 | | - .remove = coretemp_remove, |
|---|
| 578 | | -}; |
|---|
| 579 | | - |
|---|
| 580 | | -static struct platform_device *coretemp_device_add(unsigned int cpu) |
|---|
| 581 | | -{ |
|---|
| 582 | | - int err, pkgid = topology_logical_package_id(cpu); |
|---|
| 583 | | - struct platform_device *pdev; |
|---|
| 584 | | - |
|---|
| 585 | | - if (pkgid < 0) |
|---|
| 586 | | - return ERR_PTR(-ENOMEM); |
|---|
| 587 | | - |
|---|
| 588 | | - pdev = platform_device_alloc(DRVNAME, pkgid); |
|---|
| 589 | | - if (!pdev) |
|---|
| 590 | | - return ERR_PTR(-ENOMEM); |
|---|
| 591 | | - |
|---|
| 592 | | - err = platform_device_add(pdev); |
|---|
| 593 | | - if (err) { |
|---|
| 594 | | - platform_device_put(pdev); |
|---|
| 595 | | - return ERR_PTR(err); |
|---|
| 567 | + pdev = platform_device_alloc(DRVNAME, zoneid); |
|---|
| 568 | + if (!pdev) { |
|---|
| 569 | + err = -ENOMEM; |
|---|
| 570 | + goto err_free_pdata; |
|---|
| 596 | 571 | } |
|---|
| 597 | 572 | |
|---|
| 598 | | - pkg_devices[pkgid] = pdev; |
|---|
| 599 | | - return pdev; |
|---|
| 573 | + err = platform_device_add(pdev); |
|---|
| 574 | + if (err) |
|---|
| 575 | + goto err_put_dev; |
|---|
| 576 | + |
|---|
| 577 | + platform_set_drvdata(pdev, pdata); |
|---|
| 578 | + zone_devices[zoneid] = pdev; |
|---|
| 579 | + return 0; |
|---|
| 580 | + |
|---|
| 581 | +err_put_dev: |
|---|
| 582 | + platform_device_put(pdev); |
|---|
| 583 | +err_free_pdata: |
|---|
| 584 | + kfree(pdata); |
|---|
| 585 | + return err; |
|---|
| 586 | +} |
|---|
| 587 | + |
|---|
| 588 | +static void coretemp_device_remove(int zoneid) |
|---|
| 589 | +{ |
|---|
| 590 | + struct platform_device *pdev = zone_devices[zoneid]; |
|---|
| 591 | + struct platform_data *pdata = platform_get_drvdata(pdev); |
|---|
| 592 | + |
|---|
| 593 | + ida_destroy(&pdata->ida); |
|---|
| 594 | + kfree(pdata); |
|---|
| 595 | + platform_device_unregister(pdev); |
|---|
| 600 | 596 | } |
|---|
| 601 | 597 | |
|---|
| 602 | 598 | static int coretemp_cpu_online(unsigned int cpu) |
|---|
| .. | .. |
|---|
| 620 | 616 | if (!cpu_has(c, X86_FEATURE_DTHERM)) |
|---|
| 621 | 617 | return -ENODEV; |
|---|
| 622 | 618 | |
|---|
| 623 | | - if (!pdev) { |
|---|
| 619 | + pdata = platform_get_drvdata(pdev); |
|---|
| 620 | + if (!pdata->hwmon_dev) { |
|---|
| 621 | + struct device *hwmon; |
|---|
| 622 | + |
|---|
| 624 | 623 | /* Check the microcode version of the CPU */ |
|---|
| 625 | 624 | if (chk_ucode_version(cpu)) |
|---|
| 626 | 625 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 631 | 630 | * online. So, initialize per-pkg data structures and |
|---|
| 632 | 631 | * then bring this core online. |
|---|
| 633 | 632 | */ |
|---|
| 634 | | - pdev = coretemp_device_add(cpu); |
|---|
| 635 | | - if (IS_ERR(pdev)) |
|---|
| 636 | | - return PTR_ERR(pdev); |
|---|
| 633 | + hwmon = hwmon_device_register_with_groups(&pdev->dev, DRVNAME, |
|---|
| 634 | + pdata, NULL); |
|---|
| 635 | + if (IS_ERR(hwmon)) |
|---|
| 636 | + return PTR_ERR(hwmon); |
|---|
| 637 | + pdata->hwmon_dev = hwmon; |
|---|
| 637 | 638 | |
|---|
| 638 | 639 | /* |
|---|
| 639 | 640 | * Check whether pkgtemp support is available. |
|---|
| .. | .. |
|---|
| 643 | 644 | coretemp_add_core(pdev, cpu, 1); |
|---|
| 644 | 645 | } |
|---|
| 645 | 646 | |
|---|
| 646 | | - pdata = platform_get_drvdata(pdev); |
|---|
| 647 | 647 | /* |
|---|
| 648 | 648 | * Check whether a thread sibling is already online. If not add the |
|---|
| 649 | 649 | * interface for this CPU core. |
|---|
| .. | .. |
|---|
| 660 | 660 | struct platform_device *pdev = coretemp_get_pdev(cpu); |
|---|
| 661 | 661 | struct platform_data *pd; |
|---|
| 662 | 662 | struct temp_data *tdata; |
|---|
| 663 | | - int indx, target; |
|---|
| 663 | + int i, indx = -1, target; |
|---|
| 664 | 664 | |
|---|
| 665 | | - /* |
|---|
| 666 | | - * Don't execute this on suspend as the device remove locks |
|---|
| 667 | | - * up the machine. |
|---|
| 668 | | - */ |
|---|
| 665 | + /* No need to tear down any interfaces for suspend */ |
|---|
| 669 | 666 | if (cpuhp_tasks_frozen) |
|---|
| 670 | 667 | return 0; |
|---|
| 671 | 668 | |
|---|
| 672 | 669 | /* If the physical CPU device does not exist, just return */ |
|---|
| 673 | | - if (!pdev) |
|---|
| 674 | | - return 0; |
|---|
| 675 | | - |
|---|
| 676 | | - /* The core id is too big, just return */ |
|---|
| 677 | | - indx = TO_ATTR_NO(cpu); |
|---|
| 678 | | - if (indx > MAX_CORE_DATA - 1) |
|---|
| 679 | | - return 0; |
|---|
| 680 | | - |
|---|
| 681 | 670 | pd = platform_get_drvdata(pdev); |
|---|
| 671 | + if (!pd->hwmon_dev) |
|---|
| 672 | + return 0; |
|---|
| 673 | + |
|---|
| 674 | + for (i = 0; i < NUM_REAL_CORES; i++) { |
|---|
| 675 | + if (pd->cpu_map[i] == topology_core_id(cpu)) { |
|---|
| 676 | + indx = i + BASE_SYSFS_ATTR_NO; |
|---|
| 677 | + break; |
|---|
| 678 | + } |
|---|
| 679 | + } |
|---|
| 680 | + |
|---|
| 681 | + /* Too many cores and this core is not populated, just return */ |
|---|
| 682 | + if (indx < 0) |
|---|
| 683 | + return 0; |
|---|
| 684 | + |
|---|
| 682 | 685 | tdata = pd->core_data[indx]; |
|---|
| 683 | 686 | |
|---|
| 684 | 687 | cpumask_clear_cpu(cpu, &pd->cpumask); |
|---|
| .. | .. |
|---|
| 698 | 701 | } |
|---|
| 699 | 702 | |
|---|
| 700 | 703 | /* |
|---|
| 701 | | - * If all cores in this pkg are offline, remove the device. This |
|---|
| 702 | | - * will invoke the platform driver remove function, which cleans up |
|---|
| 703 | | - * the rest. |
|---|
| 704 | + * If all cores in this pkg are offline, remove the interface. |
|---|
| 704 | 705 | */ |
|---|
| 706 | + tdata = pd->core_data[PKG_SYSFS_ATTR_NO]; |
|---|
| 705 | 707 | if (cpumask_empty(&pd->cpumask)) { |
|---|
| 706 | | - pkg_devices[topology_logical_package_id(cpu)] = NULL; |
|---|
| 707 | | - platform_device_unregister(pdev); |
|---|
| 708 | + if (tdata) |
|---|
| 709 | + coretemp_remove_core(pd, PKG_SYSFS_ATTR_NO); |
|---|
| 710 | + hwmon_device_unregister(pd->hwmon_dev); |
|---|
| 711 | + pd->hwmon_dev = NULL; |
|---|
| 708 | 712 | return 0; |
|---|
| 709 | 713 | } |
|---|
| 710 | 714 | |
|---|
| .. | .. |
|---|
| 712 | 716 | * Check whether this core is the target for the package |
|---|
| 713 | 717 | * interface. We need to assign it to some other cpu. |
|---|
| 714 | 718 | */ |
|---|
| 715 | | - tdata = pd->core_data[PKG_SYSFS_ATTR_NO]; |
|---|
| 716 | 719 | if (tdata && tdata->cpu == cpu) { |
|---|
| 717 | 720 | target = cpumask_first(&pd->cpumask); |
|---|
| 718 | 721 | mutex_lock(&tdata->update_lock); |
|---|
| .. | .. |
|---|
| 722 | 725 | return 0; |
|---|
| 723 | 726 | } |
|---|
| 724 | 727 | static const struct x86_cpu_id __initconst coretemp_ids[] = { |
|---|
| 725 | | - { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM }, |
|---|
| 728 | + X86_MATCH_VENDOR_FEATURE(INTEL, X86_FEATURE_DTHERM, NULL), |
|---|
| 726 | 729 | {} |
|---|
| 727 | 730 | }; |
|---|
| 728 | 731 | MODULE_DEVICE_TABLE(x86cpu, coretemp_ids); |
|---|
| .. | .. |
|---|
| 731 | 734 | |
|---|
| 732 | 735 | static int __init coretemp_init(void) |
|---|
| 733 | 736 | { |
|---|
| 734 | | - int err; |
|---|
| 737 | + int i, err; |
|---|
| 735 | 738 | |
|---|
| 736 | 739 | /* |
|---|
| 737 | 740 | * CPUID.06H.EAX[0] indicates whether the CPU has thermal |
|---|
| .. | .. |
|---|
| 741 | 744 | if (!x86_match_cpu(coretemp_ids)) |
|---|
| 742 | 745 | return -ENODEV; |
|---|
| 743 | 746 | |
|---|
| 744 | | - max_packages = topology_max_packages(); |
|---|
| 745 | | - pkg_devices = kcalloc(max_packages, sizeof(struct platform_device *), |
|---|
| 747 | + max_zones = topology_max_packages() * topology_max_die_per_package(); |
|---|
| 748 | + zone_devices = kcalloc(max_zones, sizeof(struct platform_device *), |
|---|
| 746 | 749 | GFP_KERNEL); |
|---|
| 747 | | - if (!pkg_devices) |
|---|
| 750 | + if (!zone_devices) |
|---|
| 748 | 751 | return -ENOMEM; |
|---|
| 749 | 752 | |
|---|
| 750 | | - err = platform_driver_register(&coretemp_driver); |
|---|
| 751 | | - if (err) |
|---|
| 752 | | - return err; |
|---|
| 753 | + for (i = 0; i < max_zones; i++) { |
|---|
| 754 | + err = coretemp_device_add(i); |
|---|
| 755 | + if (err) |
|---|
| 756 | + goto outzone; |
|---|
| 757 | + } |
|---|
| 753 | 758 | |
|---|
| 754 | 759 | err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online", |
|---|
| 755 | 760 | coretemp_cpu_online, coretemp_cpu_offline); |
|---|
| 756 | 761 | if (err < 0) |
|---|
| 757 | | - goto outdrv; |
|---|
| 762 | + goto outzone; |
|---|
| 758 | 763 | coretemp_hp_online = err; |
|---|
| 759 | 764 | return 0; |
|---|
| 760 | 765 | |
|---|
| 761 | | -outdrv: |
|---|
| 762 | | - platform_driver_unregister(&coretemp_driver); |
|---|
| 763 | | - kfree(pkg_devices); |
|---|
| 766 | +outzone: |
|---|
| 767 | + while (i--) |
|---|
| 768 | + coretemp_device_remove(i); |
|---|
| 769 | + kfree(zone_devices); |
|---|
| 764 | 770 | return err; |
|---|
| 765 | 771 | } |
|---|
| 766 | 772 | module_init(coretemp_init) |
|---|
| 767 | 773 | |
|---|
| 768 | 774 | static void __exit coretemp_exit(void) |
|---|
| 769 | 775 | { |
|---|
| 776 | + int i; |
|---|
| 777 | + |
|---|
| 770 | 778 | cpuhp_remove_state(coretemp_hp_online); |
|---|
| 771 | | - platform_driver_unregister(&coretemp_driver); |
|---|
| 772 | | - kfree(pkg_devices); |
|---|
| 779 | + for (i = 0; i < max_zones; i++) |
|---|
| 780 | + coretemp_device_remove(i); |
|---|
| 781 | + kfree(zone_devices); |
|---|
| 773 | 782 | } |
|---|
| 774 | 783 | module_exit(coretemp_exit) |
|---|
| 775 | 784 | |
|---|