LCOV - code coverage report
Current view: top level - drivers/acpi - processor_driver.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 48 141 34.0 %
Date: 2022-03-28 15:32:58 Functions: 4 10 40.0 %
Branches: 16 80 20.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * processor_driver.c - ACPI Processor Driver
       4                 :            :  *
       5                 :            :  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
       6                 :            :  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
       7                 :            :  *  Copyright (C) 2004       Dominik Brodowski <linux@brodo.de>
       8                 :            :  *  Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
       9                 :            :  *                      - Added processor hotplug support
      10                 :            :  *  Copyright (C) 2013, Intel Corporation
      11                 :            :  *                      Rafael J. Wysocki <rafael.j.wysocki@intel.com>
      12                 :            :  */
      13                 :            : 
      14                 :            : #include <linux/kernel.h>
      15                 :            : #include <linux/module.h>
      16                 :            : #include <linux/init.h>
      17                 :            : #include <linux/cpufreq.h>
      18                 :            : #include <linux/cpu.h>
      19                 :            : #include <linux/cpuidle.h>
      20                 :            : #include <linux/slab.h>
      21                 :            : #include <linux/acpi.h>
      22                 :            : 
      23                 :            : #include <acpi/processor.h>
      24                 :            : 
      25                 :            : #include "internal.h"
      26                 :            : 
      27                 :            : #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
      28                 :            : #define ACPI_PROCESSOR_NOTIFY_POWER     0x81
      29                 :            : #define ACPI_PROCESSOR_NOTIFY_THROTTLING        0x82
      30                 :            : 
      31                 :            : #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
      32                 :            : ACPI_MODULE_NAME("processor_driver");
      33                 :            : 
      34                 :            : MODULE_AUTHOR("Paul Diefenbaugh");
      35                 :            : MODULE_DESCRIPTION("ACPI Processor Driver");
      36                 :            : MODULE_LICENSE("GPL");
      37                 :            : 
      38                 :            : static int acpi_processor_start(struct device *dev);
      39                 :            : static int acpi_processor_stop(struct device *dev);
      40                 :            : 
      41                 :            : static const struct acpi_device_id processor_device_ids[] = {
      42                 :            :         {ACPI_PROCESSOR_OBJECT_HID, 0},
      43                 :            :         {ACPI_PROCESSOR_DEVICE_HID, 0},
      44                 :            :         {"", 0},
      45                 :            : };
      46                 :            : MODULE_DEVICE_TABLE(acpi, processor_device_ids);
      47                 :            : 
      48                 :            : static struct device_driver acpi_processor_driver = {
      49                 :            :         .name = "processor",
      50                 :            :         .bus = &cpu_subsys,
      51                 :            :         .acpi_match_table = processor_device_ids,
      52                 :            :         .probe = acpi_processor_start,
      53                 :            :         .remove = acpi_processor_stop,
      54                 :            : };
      55                 :            : 
      56                 :          0 : static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
      57                 :            : {
      58                 :          0 :         struct acpi_device *device = data;
      59                 :          0 :         struct acpi_processor *pr;
      60                 :          0 :         int saved;
      61                 :            : 
      62         [ #  # ]:          0 :         if (device->handle != handle)
      63                 :            :                 return;
      64                 :            : 
      65         [ #  # ]:          0 :         pr = acpi_driver_data(device);
      66         [ #  # ]:          0 :         if (!pr)
      67                 :            :                 return;
      68                 :            : 
      69   [ #  #  #  # ]:          0 :         switch (event) {
      70                 :          0 :         case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
      71                 :          0 :                 saved = pr->performance_platform_limit;
      72                 :          0 :                 acpi_processor_ppc_has_changed(pr, 1);
      73         [ #  # ]:          0 :                 if (saved == pr->performance_platform_limit)
      74                 :            :                         break;
      75         [ #  # ]:          0 :                 acpi_bus_generate_netlink_event(device->pnp.device_class,
      76                 :            :                                                   dev_name(&device->dev), event,
      77                 :            :                                                   pr->performance_platform_limit);
      78                 :          0 :                 break;
      79                 :          0 :         case ACPI_PROCESSOR_NOTIFY_POWER:
      80                 :          0 :                 acpi_processor_power_state_has_changed(pr);
      81         [ #  # ]:          0 :                 acpi_bus_generate_netlink_event(device->pnp.device_class,
      82                 :            :                                                   dev_name(&device->dev), event, 0);
      83                 :          0 :                 break;
      84                 :          0 :         case ACPI_PROCESSOR_NOTIFY_THROTTLING:
      85                 :          0 :                 acpi_processor_tstate_has_changed(pr);
      86         [ #  # ]:          0 :                 acpi_bus_generate_netlink_event(device->pnp.device_class,
      87                 :            :                                                   dev_name(&device->dev), event, 0);
      88                 :          0 :                 break;
      89                 :            :         default:
      90                 :            :                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
      91                 :            :                                   "Unsupported event [0x%x]\n", event));
      92                 :            :                 break;
      93                 :            :         }
      94                 :            : 
      95                 :          0 :         return;
      96                 :            : }
      97                 :            : 
      98                 :            : static int __acpi_processor_start(struct acpi_device *device);
      99                 :            : 
     100                 :          0 : static int acpi_soft_cpu_online(unsigned int cpu)
     101                 :            : {
     102                 :          0 :         struct acpi_processor *pr = per_cpu(processors, cpu);
     103                 :          0 :         struct acpi_device *device;
     104                 :            : 
     105   [ #  #  #  # ]:          0 :         if (!pr || acpi_bus_get_device(pr->handle, &device))
     106                 :          0 :                 return 0;
     107                 :            :         /*
     108                 :            :          * CPU got physically hotplugged and onlined for the first time:
     109                 :            :          * Initialize missing things.
     110                 :            :          */
     111         [ #  # ]:          0 :         if (pr->flags.need_hotplug_init) {
     112                 :          0 :                 int ret;
     113                 :            : 
     114                 :          0 :                 pr_info("Will online and init hotplugged CPU: %d\n",
     115                 :            :                         pr->id);
     116                 :          0 :                 pr->flags.need_hotplug_init = 0;
     117                 :          0 :                 ret = __acpi_processor_start(device);
     118         [ #  # ]:          0 :                 WARN(ret, "Failed to start CPU: %d\n", pr->id);
     119                 :            :         } else {
     120                 :            :                 /* Normal CPU soft online event. */
     121                 :          0 :                 acpi_processor_ppc_has_changed(pr, 0);
     122                 :          0 :                 acpi_processor_hotplug(pr);
     123                 :          0 :                 acpi_processor_reevaluate_tstate(pr, false);
     124                 :          0 :                 acpi_processor_tstate_has_changed(pr);
     125                 :            :         }
     126                 :            :         return 0;
     127                 :            : }
     128                 :            : 
     129                 :          0 : static int acpi_soft_cpu_dead(unsigned int cpu)
     130                 :            : {
     131                 :          0 :         struct acpi_processor *pr = per_cpu(processors, cpu);
     132                 :          0 :         struct acpi_device *device;
     133                 :            : 
     134   [ #  #  #  # ]:          0 :         if (!pr || acpi_bus_get_device(pr->handle, &device))
     135                 :          0 :                 return 0;
     136                 :            : 
     137                 :          0 :         acpi_processor_reevaluate_tstate(pr, true);
     138                 :          0 :         return 0;
     139                 :            : }
     140                 :            : 
     141                 :            : #ifdef CONFIG_ACPI_CPU_FREQ_PSS
     142                 :         28 : static int acpi_pss_perf_init(struct acpi_processor *pr,
     143                 :            :                 struct acpi_device *device)
     144                 :            : {
     145                 :         28 :         int result = 0;
     146                 :            : 
     147                 :         28 :         acpi_processor_ppc_has_changed(pr, 0);
     148                 :            : 
     149                 :         28 :         acpi_processor_get_throttling_info(pr);
     150                 :            : 
     151         [ -  + ]:         28 :         if (pr->flags.throttling)
     152                 :          0 :                 pr->flags.limit = 1;
     153                 :            : 
     154                 :         28 :         pr->cdev = thermal_cooling_device_register("Processor", device,
     155                 :            :                                                    &processor_cooling_ops);
     156         [ -  + ]:         28 :         if (IS_ERR(pr->cdev)) {
     157                 :          0 :                 result = PTR_ERR(pr->cdev);
     158                 :          0 :                 return result;
     159                 :            :         }
     160                 :            : 
     161                 :         28 :         dev_dbg(&device->dev, "registered as cooling_device%d\n",
     162                 :            :                 pr->cdev->id);
     163                 :            : 
     164                 :         28 :         result = sysfs_create_link(&device->dev.kobj,
     165                 :            :                                    &pr->cdev->device.kobj,
     166                 :            :                                    "thermal_cooling");
     167         [ -  + ]:         28 :         if (result) {
     168                 :          0 :                 dev_err(&device->dev,
     169                 :            :                         "Failed to create sysfs link 'thermal_cooling'\n");
     170                 :          0 :                 goto err_thermal_unregister;
     171                 :            :         }
     172                 :            : 
     173                 :         28 :         result = sysfs_create_link(&pr->cdev->device.kobj,
     174                 :            :                                    &device->dev.kobj,
     175                 :            :                                    "device");
     176         [ -  + ]:         28 :         if (result) {
     177                 :          0 :                 dev_err(&pr->cdev->device,
     178                 :            :                         "Failed to create sysfs link 'device'\n");
     179                 :          0 :                 goto err_remove_sysfs_thermal;
     180                 :            :         }
     181                 :            : 
     182                 :            :         return 0;
     183                 :            : 
     184                 :            :  err_remove_sysfs_thermal:
     185                 :          0 :         sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
     186                 :          0 :  err_thermal_unregister:
     187                 :          0 :         thermal_cooling_device_unregister(pr->cdev);
     188                 :            : 
     189                 :          0 :         return result;
     190                 :            : }
     191                 :            : 
     192                 :            : static void acpi_pss_perf_exit(struct acpi_processor *pr,
     193                 :            :                 struct acpi_device *device)
     194                 :            : {
     195                 :            :         if (pr->cdev) {
     196                 :            :                 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
     197                 :            :                 sysfs_remove_link(&pr->cdev->device.kobj, "device");
     198                 :            :                 thermal_cooling_device_unregister(pr->cdev);
     199                 :            :                 pr->cdev = NULL;
     200                 :            :         }
     201                 :            : }
     202                 :            : #else
     203                 :            : static inline int acpi_pss_perf_init(struct acpi_processor *pr,
     204                 :            :                 struct acpi_device *device)
     205                 :            : {
     206                 :            :         return 0;
     207                 :            : }
     208                 :            : 
     209                 :            : static inline void acpi_pss_perf_exit(struct acpi_processor *pr,
     210                 :            :                 struct acpi_device *device) {}
     211                 :            : #endif /* CONFIG_ACPI_CPU_FREQ_PSS */
     212                 :            : 
     213                 :         28 : static int __acpi_processor_start(struct acpi_device *device)
     214                 :            : {
     215         [ +  - ]:         28 :         struct acpi_processor *pr = acpi_driver_data(device);
     216                 :         28 :         acpi_status status;
     217                 :         28 :         int result = 0;
     218                 :            : 
     219         [ +  - ]:         28 :         if (!pr)
     220                 :            :                 return -ENODEV;
     221                 :            : 
     222         [ +  - ]:         28 :         if (pr->flags.need_hotplug_init)
     223                 :            :                 return 0;
     224                 :            : 
     225                 :         28 :         result = acpi_cppc_processor_probe(pr);
     226                 :         28 :         if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS))
     227                 :            :                 dev_dbg(&device->dev, "CPPC data invalid or not present\n");
     228                 :            : 
     229   [ -  +  -  - ]:         28 :         if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
     230                 :         28 :                 acpi_processor_power_init(pr);
     231                 :            : 
     232                 :         28 :         result = acpi_pss_perf_init(pr, device);
     233         [ -  + ]:         28 :         if (result)
     234                 :          0 :                 goto err_power_exit;
     235                 :            : 
     236                 :         28 :         status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
     237                 :            :                                              acpi_processor_notify, device);
     238         [ -  + ]:         28 :         if (ACPI_SUCCESS(status))
     239                 :            :                 return 0;
     240                 :            : 
     241                 :          0 :         result = -ENODEV;
     242                 :          0 :         acpi_pss_perf_exit(pr, device);
     243                 :            : 
     244                 :          0 : err_power_exit:
     245                 :          0 :         acpi_processor_power_exit(pr);
     246                 :          0 :         return result;
     247                 :            : }
     248                 :            : 
     249                 :         28 : static int acpi_processor_start(struct device *dev)
     250                 :            : {
     251         [ +  - ]:         28 :         struct acpi_device *device = ACPI_COMPANION(dev);
     252                 :         28 :         int ret;
     253                 :            : 
     254         [ +  - ]:         28 :         if (!device)
     255                 :            :                 return -ENODEV;
     256                 :            : 
     257                 :            :         /* Protect against concurrent CPU hotplug operations */
     258                 :         28 :         cpu_hotplug_disable();
     259                 :         28 :         ret = __acpi_processor_start(device);
     260                 :         28 :         cpu_hotplug_enable();
     261                 :         28 :         return ret;
     262                 :            : }
     263                 :            : 
     264                 :          0 : static int acpi_processor_stop(struct device *dev)
     265                 :            : {
     266         [ #  # ]:          0 :         struct acpi_device *device = ACPI_COMPANION(dev);
     267                 :          0 :         struct acpi_processor *pr;
     268                 :            : 
     269         [ #  # ]:          0 :         if (!device)
     270                 :            :                 return 0;
     271                 :            : 
     272                 :          0 :         acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
     273                 :            :                                    acpi_processor_notify);
     274                 :            : 
     275         [ #  # ]:          0 :         pr = acpi_driver_data(device);
     276         [ #  # ]:          0 :         if (!pr)
     277                 :            :                 return 0;
     278                 :          0 :         acpi_processor_power_exit(pr);
     279                 :            : 
     280                 :          0 :         acpi_pss_perf_exit(pr, device);
     281                 :            : 
     282                 :          0 :         acpi_cppc_processor_exit(pr);
     283                 :            : 
     284                 :          0 :         return 0;
     285                 :            : }
     286                 :            : 
     287                 :            : bool acpi_processor_cpufreq_init;
     288                 :            : 
     289                 :          0 : static int acpi_processor_notifier(struct notifier_block *nb,
     290                 :            :                                    unsigned long event, void *data)
     291                 :            : {
     292                 :          0 :         struct cpufreq_policy *policy = data;
     293                 :            : 
     294         [ #  # ]:          0 :         if (event == CPUFREQ_CREATE_POLICY) {
     295                 :          0 :                 acpi_thermal_cpufreq_init(policy);
     296                 :          0 :                 acpi_processor_ppc_init(policy);
     297         [ #  # ]:          0 :         } else if (event == CPUFREQ_REMOVE_POLICY) {
     298                 :          0 :                 acpi_processor_ppc_exit(policy);
     299                 :          0 :                 acpi_thermal_cpufreq_exit(policy);
     300                 :            :         }
     301                 :            : 
     302                 :          0 :         return 0;
     303                 :            : }
     304                 :            : 
     305                 :            : static struct notifier_block acpi_processor_notifier_block = {
     306                 :            :         .notifier_call = acpi_processor_notifier,
     307                 :            : };
     308                 :            : 
     309                 :            : /*
     310                 :            :  * We keep the driver loaded even when ACPI is not running.
     311                 :            :  * This is needed for the powernow-k8 driver, that works even without
     312                 :            :  * ACPI, but needs symbols from this driver
     313                 :            :  */
     314                 :            : static enum cpuhp_state hp_online;
     315                 :         28 : static int __init acpi_processor_driver_init(void)
     316                 :            : {
     317                 :         28 :         int result = 0;
     318                 :            : 
     319         [ +  - ]:         28 :         if (acpi_disabled)
     320                 :            :                 return 0;
     321                 :            : 
     322                 :         28 :         result = driver_register(&acpi_processor_driver);
     323         [ +  - ]:         28 :         if (result < 0)
     324                 :            :                 return result;
     325                 :            : 
     326                 :         28 :         result = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
     327                 :            :                                            "acpi/cpu-drv:online",
     328                 :            :                                            acpi_soft_cpu_online, NULL);
     329         [ -  + ]:         28 :         if (result < 0)
     330                 :          0 :                 goto err;
     331                 :         28 :         hp_online = result;
     332                 :         28 :         cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead",
     333                 :            :                                   NULL, acpi_soft_cpu_dead);
     334                 :            : 
     335         [ +  - ]:         28 :         if (!cpufreq_register_notifier(&acpi_processor_notifier_block,
     336                 :            :                                        CPUFREQ_POLICY_NOTIFIER)) {
     337                 :         28 :                 acpi_processor_cpufreq_init = true;
     338                 :         28 :                 acpi_processor_ignore_ppc_init();
     339                 :            :         }
     340                 :            : 
     341                 :         28 :         acpi_processor_throttling_init();
     342                 :         28 :         return 0;
     343                 :            : err:
     344                 :          0 :         driver_unregister(&acpi_processor_driver);
     345                 :          0 :         return result;
     346                 :            : }
     347                 :            : 
     348                 :          0 : static void __exit acpi_processor_driver_exit(void)
     349                 :            : {
     350         [ #  # ]:          0 :         if (acpi_disabled)
     351                 :            :                 return;
     352                 :            : 
     353         [ #  # ]:          0 :         if (acpi_processor_cpufreq_init) {
     354                 :          0 :                 cpufreq_unregister_notifier(&acpi_processor_notifier_block,
     355                 :            :                                             CPUFREQ_POLICY_NOTIFIER);
     356                 :          0 :                 acpi_processor_cpufreq_init = false;
     357                 :            :         }
     358                 :            : 
     359                 :          0 :         cpuhp_remove_state_nocalls(hp_online);
     360                 :          0 :         cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD);
     361                 :          0 :         driver_unregister(&acpi_processor_driver);
     362                 :            : }
     363                 :            : 
     364                 :            : module_init(acpi_processor_driver_init);
     365                 :            : module_exit(acpi_processor_driver_exit);
     366                 :            : 
     367                 :            : MODULE_ALIAS("processor");

Generated by: LCOV version 1.14