.. | .. |
---|
| 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 | |
---|