| .. | .. |
|---|
| 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 | 553 | static int coretemp_probe(struct platform_device *pdev) |
|---|
| .. | .. |
|---|
| 544 | 555 | struct device *dev = &pdev->dev; |
|---|
| 545 | 556 | struct platform_data *pdata; |
|---|
| 546 | 557 | |
|---|
| 547 | | - /* Initialize the per-package data structures */ |
|---|
| 558 | + /* Initialize the per-zone data structures */ |
|---|
| 548 | 559 | pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL); |
|---|
| 549 | 560 | if (!pdata) |
|---|
| 550 | 561 | return -ENOMEM; |
|---|
| 551 | 562 | |
|---|
| 552 | 563 | pdata->pkg_id = pdev->id; |
|---|
| 564 | + ida_init(&pdata->ida); |
|---|
| 553 | 565 | platform_set_drvdata(pdev, pdata); |
|---|
| 554 | 566 | |
|---|
| 555 | 567 | pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME, |
|---|
| .. | .. |
|---|
| 566 | 578 | if (pdata->core_data[i]) |
|---|
| 567 | 579 | coretemp_remove_core(pdata, i); |
|---|
| 568 | 580 | |
|---|
| 581 | + ida_destroy(&pdata->ida); |
|---|
| 569 | 582 | return 0; |
|---|
| 570 | 583 | } |
|---|
| 571 | 584 | |
|---|
| .. | .. |
|---|
| 579 | 592 | |
|---|
| 580 | 593 | static struct platform_device *coretemp_device_add(unsigned int cpu) |
|---|
| 581 | 594 | { |
|---|
| 582 | | - int err, pkgid = topology_logical_package_id(cpu); |
|---|
| 595 | + int err, zoneid = topology_logical_die_id(cpu); |
|---|
| 583 | 596 | struct platform_device *pdev; |
|---|
| 584 | 597 | |
|---|
| 585 | | - if (pkgid < 0) |
|---|
| 598 | + if (zoneid < 0) |
|---|
| 586 | 599 | return ERR_PTR(-ENOMEM); |
|---|
| 587 | 600 | |
|---|
| 588 | | - pdev = platform_device_alloc(DRVNAME, pkgid); |
|---|
| 601 | + pdev = platform_device_alloc(DRVNAME, zoneid); |
|---|
| 589 | 602 | if (!pdev) |
|---|
| 590 | 603 | return ERR_PTR(-ENOMEM); |
|---|
| 591 | 604 | |
|---|
| .. | .. |
|---|
| 595 | 608 | return ERR_PTR(err); |
|---|
| 596 | 609 | } |
|---|
| 597 | 610 | |
|---|
| 598 | | - pkg_devices[pkgid] = pdev; |
|---|
| 611 | + zone_devices[zoneid] = pdev; |
|---|
| 599 | 612 | return pdev; |
|---|
| 600 | 613 | } |
|---|
| 601 | 614 | |
|---|
| .. | .. |
|---|
| 660 | 673 | struct platform_device *pdev = coretemp_get_pdev(cpu); |
|---|
| 661 | 674 | struct platform_data *pd; |
|---|
| 662 | 675 | struct temp_data *tdata; |
|---|
| 663 | | - int indx, target; |
|---|
| 676 | + int i, indx = -1, target; |
|---|
| 664 | 677 | |
|---|
| 665 | 678 | /* |
|---|
| 666 | 679 | * Don't execute this on suspend as the device remove locks |
|---|
| .. | .. |
|---|
| 673 | 686 | if (!pdev) |
|---|
| 674 | 687 | return 0; |
|---|
| 675 | 688 | |
|---|
| 676 | | - /* The core id is too big, just return */ |
|---|
| 677 | | - indx = TO_ATTR_NO(cpu); |
|---|
| 678 | | - if (indx > MAX_CORE_DATA - 1) |
|---|
| 689 | + pd = platform_get_drvdata(pdev); |
|---|
| 690 | + |
|---|
| 691 | + for (i = 0; i < NUM_REAL_CORES; i++) { |
|---|
| 692 | + if (pd->cpu_map[i] == topology_core_id(cpu)) { |
|---|
| 693 | + indx = i + BASE_SYSFS_ATTR_NO; |
|---|
| 694 | + break; |
|---|
| 695 | + } |
|---|
| 696 | + } |
|---|
| 697 | + |
|---|
| 698 | + /* Too many cores and this core is not populated, just return */ |
|---|
| 699 | + if (indx < 0) |
|---|
| 679 | 700 | return 0; |
|---|
| 680 | 701 | |
|---|
| 681 | | - pd = platform_get_drvdata(pdev); |
|---|
| 682 | 702 | tdata = pd->core_data[indx]; |
|---|
| 683 | 703 | |
|---|
| 684 | 704 | cpumask_clear_cpu(cpu, &pd->cpumask); |
|---|
| .. | .. |
|---|
| 703 | 723 | * the rest. |
|---|
| 704 | 724 | */ |
|---|
| 705 | 725 | if (cpumask_empty(&pd->cpumask)) { |
|---|
| 706 | | - pkg_devices[topology_logical_package_id(cpu)] = NULL; |
|---|
| 726 | + zone_devices[topology_logical_die_id(cpu)] = NULL; |
|---|
| 707 | 727 | platform_device_unregister(pdev); |
|---|
| 708 | 728 | return 0; |
|---|
| 709 | 729 | } |
|---|
| .. | .. |
|---|
| 722 | 742 | return 0; |
|---|
| 723 | 743 | } |
|---|
| 724 | 744 | static const struct x86_cpu_id __initconst coretemp_ids[] = { |
|---|
| 725 | | - { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM }, |
|---|
| 745 | + X86_MATCH_VENDOR_FEATURE(INTEL, X86_FEATURE_DTHERM, NULL), |
|---|
| 726 | 746 | {} |
|---|
| 727 | 747 | }; |
|---|
| 728 | 748 | MODULE_DEVICE_TABLE(x86cpu, coretemp_ids); |
|---|
| .. | .. |
|---|
| 741 | 761 | if (!x86_match_cpu(coretemp_ids)) |
|---|
| 742 | 762 | return -ENODEV; |
|---|
| 743 | 763 | |
|---|
| 744 | | - max_packages = topology_max_packages(); |
|---|
| 745 | | - pkg_devices = kcalloc(max_packages, sizeof(struct platform_device *), |
|---|
| 764 | + max_zones = topology_max_packages() * topology_max_die_per_package(); |
|---|
| 765 | + zone_devices = kcalloc(max_zones, sizeof(struct platform_device *), |
|---|
| 746 | 766 | GFP_KERNEL); |
|---|
| 747 | | - if (!pkg_devices) |
|---|
| 767 | + if (!zone_devices) |
|---|
| 748 | 768 | return -ENOMEM; |
|---|
| 749 | 769 | |
|---|
| 750 | 770 | err = platform_driver_register(&coretemp_driver); |
|---|
| 751 | 771 | if (err) |
|---|
| 752 | | - return err; |
|---|
| 772 | + goto outzone; |
|---|
| 753 | 773 | |
|---|
| 754 | 774 | err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online", |
|---|
| 755 | 775 | coretemp_cpu_online, coretemp_cpu_offline); |
|---|
| .. | .. |
|---|
| 760 | 780 | |
|---|
| 761 | 781 | outdrv: |
|---|
| 762 | 782 | platform_driver_unregister(&coretemp_driver); |
|---|
| 763 | | - kfree(pkg_devices); |
|---|
| 783 | +outzone: |
|---|
| 784 | + kfree(zone_devices); |
|---|
| 764 | 785 | return err; |
|---|
| 765 | 786 | } |
|---|
| 766 | 787 | module_init(coretemp_init) |
|---|
| .. | .. |
|---|
| 769 | 790 | { |
|---|
| 770 | 791 | cpuhp_remove_state(coretemp_hp_online); |
|---|
| 771 | 792 | platform_driver_unregister(&coretemp_driver); |
|---|
| 772 | | - kfree(pkg_devices); |
|---|
| 793 | + kfree(zone_devices); |
|---|
| 773 | 794 | } |
|---|
| 774 | 795 | module_exit(coretemp_exit) |
|---|
| 775 | 796 | |
|---|