linux/drivers/thermal/x86_pkg_temp_thermal.c
<<
>>
Prefs
   1/*
   2 * x86_pkg_temp_thermal driver
   3 * Copyright (c) 2013, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program; if not, write to the Free Software Foundation, Inc.
  16 *
  17 */
  18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  19
  20#include <linux/module.h>
  21#include <linux/init.h>
  22#include <linux/err.h>
  23#include <linux/param.h>
  24#include <linux/device.h>
  25#include <linux/platform_device.h>
  26#include <linux/cpu.h>
  27#include <linux/smp.h>
  28#include <linux/slab.h>
  29#include <linux/pm.h>
  30#include <linux/thermal.h>
  31#include <linux/debugfs.h>
  32#include <asm/cpu_device_id.h>
  33#include <asm/mce.h>
  34
  35/*
  36* Rate control delay: Idea is to introduce denounce effect
  37* This should be long enough to avoid reduce events, when
  38* threshold is set to a temperature, which is constantly
  39* violated, but at the short enough to take any action.
  40* The action can be remove threshold or change it to next
  41* interesting setting. Based on experiments, in around
  42* every 5 seconds under load will give us a significant
  43* temperature change.
  44*/
  45#define PKG_TEMP_THERMAL_NOTIFY_DELAY   5000
  46static int notify_delay_ms = PKG_TEMP_THERMAL_NOTIFY_DELAY;
  47module_param(notify_delay_ms, int, 0644);
  48MODULE_PARM_DESC(notify_delay_ms,
  49        "User space notification delay in milli seconds.");
  50
  51/* Number of trip points in thermal zone. Currently it can't
  52* be more than 2. MSR can allow setting and getting notifications
  53* for only 2 thresholds. This define enforces this, if there
  54* is some wrong values returned by cpuid for number of thresholds.
  55*/
  56#define MAX_NUMBER_OF_TRIPS     2
  57/* Limit number of package temp zones */
  58#define MAX_PKG_TEMP_ZONE_IDS   256
  59
  60struct phy_dev_entry {
  61        struct list_head list;
  62        u16 phys_proc_id;
  63        u16 first_cpu;
  64        u32 tj_max;
  65        int ref_cnt;
  66        u32 start_pkg_therm_low;
  67        u32 start_pkg_therm_high;
  68        struct thermal_zone_device *tzone;
  69};
  70
  71/* List maintaining number of package instances */
  72static LIST_HEAD(phy_dev_list);
  73static DEFINE_MUTEX(phy_dev_list_mutex);
  74
  75/* Interrupt to work function schedule queue */
  76static DEFINE_PER_CPU(struct delayed_work, pkg_temp_thermal_threshold_work);
  77
  78/* To track if the work is already scheduled on a package */
  79static u8 *pkg_work_scheduled;
  80
  81/* Spin lock to prevent races with pkg_work_scheduled */
  82static spinlock_t pkg_work_lock;
  83static u16 max_phy_id;
  84
  85/* Debug counters to show using debugfs */
  86static struct dentry *debugfs;
  87static unsigned int pkg_interrupt_cnt;
  88static unsigned int pkg_work_cnt;
  89
  90static int pkg_temp_debugfs_init(void)
  91{
  92        struct dentry *d;
  93
  94        debugfs = debugfs_create_dir("pkg_temp_thermal", NULL);
  95        if (!debugfs)
  96                return -ENOENT;
  97
  98        d = debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs,
  99                                (u32 *)&pkg_interrupt_cnt);
 100        if (!d)
 101                goto err_out;
 102
 103        d = debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs,
 104                                (u32 *)&pkg_work_cnt);
 105        if (!d)
 106                goto err_out;
 107
 108        return 0;
 109
 110err_out:
 111        debugfs_remove_recursive(debugfs);
 112        return -ENOENT;
 113}
 114
 115static struct phy_dev_entry
 116                        *pkg_temp_thermal_get_phy_entry(unsigned int cpu)
 117{
 118        u16 phys_proc_id = topology_physical_package_id(cpu);
 119        struct phy_dev_entry *phy_ptr;
 120
 121        mutex_lock(&phy_dev_list_mutex);
 122
 123        list_for_each_entry(phy_ptr, &phy_dev_list, list)
 124                if (phy_ptr->phys_proc_id == phys_proc_id) {
 125                        mutex_unlock(&phy_dev_list_mutex);
 126                        return phy_ptr;
 127                }
 128
 129        mutex_unlock(&phy_dev_list_mutex);
 130
 131        return NULL;
 132}
 133
 134/*
 135* tj-max is is interesting because threshold is set relative to this
 136* temperature.
 137*/
 138static int get_tj_max(int cpu, u32 *tj_max)
 139{
 140        u32 eax, edx;
 141        u32 val;
 142        int err;
 143
 144        err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
 145        if (err)
 146                goto err_ret;
 147        else {
 148                val = (eax >> 16) & 0xff;
 149                if (val)
 150                        *tj_max = val * 1000;
 151                else {
 152                        err = -EINVAL;
 153                        goto err_ret;
 154                }
 155        }
 156
 157        return 0;
 158err_ret:
 159        *tj_max = 0;
 160        return err;
 161}
 162
 163static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
 164{
 165        u32 eax, edx;
 166        struct phy_dev_entry *phy_dev_entry;
 167
 168        phy_dev_entry = tzd->devdata;
 169        rdmsr_on_cpu(phy_dev_entry->first_cpu, MSR_IA32_PACKAGE_THERM_STATUS,
 170                        &eax, &edx);
 171        if (eax & 0x80000000) {
 172                *temp = phy_dev_entry->tj_max -
 173                                ((eax >> 16) & 0x7f) * 1000;
 174                pr_debug("sys_get_curr_temp %ld\n", *temp);
 175                return 0;
 176        }
 177
 178        return -EINVAL;
 179}
 180
 181static int sys_get_trip_temp(struct thermal_zone_device *tzd,
 182                int trip, unsigned long *temp)
 183{
 184        u32 eax, edx;
 185        struct phy_dev_entry *phy_dev_entry;
 186        u32 mask, shift;
 187        unsigned long thres_reg_value;
 188        int ret;
 189
 190        if (trip >= MAX_NUMBER_OF_TRIPS)
 191                return -EINVAL;
 192
 193        phy_dev_entry = tzd->devdata;
 194
 195        if (trip) {
 196                mask = THERM_MASK_THRESHOLD1;
 197                shift = THERM_SHIFT_THRESHOLD1;
 198        } else {
 199                mask = THERM_MASK_THRESHOLD0;
 200                shift = THERM_SHIFT_THRESHOLD0;
 201        }
 202
 203        ret = rdmsr_on_cpu(phy_dev_entry->first_cpu,
 204                                MSR_IA32_PACKAGE_THERM_INTERRUPT, &eax, &edx);
 205        if (ret < 0)
 206                return -EINVAL;
 207
 208        thres_reg_value = (eax & mask) >> shift;
 209        if (thres_reg_value)
 210                *temp = phy_dev_entry->tj_max - thres_reg_value * 1000;
 211        else
 212                *temp = 0;
 213        pr_debug("sys_get_trip_temp %ld\n", *temp);
 214
 215        return 0;
 216}
 217
 218int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
 219                                                        unsigned long temp)
 220{
 221        u32 l, h;
 222        struct phy_dev_entry *phy_dev_entry;
 223        u32 mask, shift, intr;
 224        int ret;
 225
 226        phy_dev_entry = tzd->devdata;
 227
 228        if (trip >= MAX_NUMBER_OF_TRIPS || temp >= phy_dev_entry->tj_max)
 229                return -EINVAL;
 230
 231        ret = rdmsr_on_cpu(phy_dev_entry->first_cpu,
 232                                        MSR_IA32_PACKAGE_THERM_INTERRUPT,
 233                                        &l, &h);
 234        if (ret < 0)
 235                return -EINVAL;
 236
 237        if (trip) {
 238                mask = THERM_MASK_THRESHOLD1;
 239                shift = THERM_SHIFT_THRESHOLD1;
 240                intr = THERM_INT_THRESHOLD1_ENABLE;
 241        } else {
 242                mask = THERM_MASK_THRESHOLD0;
 243                shift = THERM_SHIFT_THRESHOLD0;
 244                intr = THERM_INT_THRESHOLD0_ENABLE;
 245        }
 246        l &= ~mask;
 247        /*
 248        * When users space sets a trip temperature == 0, which is indication
 249        * that, it is no longer interested in receiving notifications.
 250        */
 251        if (!temp)
 252                l &= ~intr;
 253        else {
 254                l |= (phy_dev_entry->tj_max - temp)/1000 << shift;
 255                l |= intr;
 256        }
 257
 258        return wrmsr_on_cpu(phy_dev_entry->first_cpu,
 259                                        MSR_IA32_PACKAGE_THERM_INTERRUPT,
 260                                        l, h);
 261}
 262
 263static int sys_get_trip_type(struct thermal_zone_device *thermal,
 264                int trip, enum thermal_trip_type *type)
 265{
 266
 267        *type = THERMAL_TRIP_PASSIVE;
 268
 269        return 0;
 270}
 271
 272/* Thermal zone callback registry */
 273static struct thermal_zone_device_ops tzone_ops = {
 274        .get_temp = sys_get_curr_temp,
 275        .get_trip_temp = sys_get_trip_temp,
 276        .get_trip_type = sys_get_trip_type,
 277        .set_trip_temp = sys_set_trip_temp,
 278};
 279
 280static bool pkg_temp_thermal_platform_thermal_rate_control(void)
 281{
 282        return true;
 283}
 284
 285/* Enable threshold interrupt on local package/cpu */
 286static inline void enable_pkg_thres_interrupt(void)
 287{
 288        u32 l, h;
 289        u8 thres_0, thres_1;
 290
 291        rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
 292        /* only enable/disable if it had valid threshold value */
 293        thres_0 = (l & THERM_MASK_THRESHOLD0) >> THERM_SHIFT_THRESHOLD0;
 294        thres_1 = (l & THERM_MASK_THRESHOLD1) >> THERM_SHIFT_THRESHOLD1;
 295        if (thres_0)
 296                l |= THERM_INT_THRESHOLD0_ENABLE;
 297        if (thres_1)
 298                l |= THERM_INT_THRESHOLD1_ENABLE;
 299        wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
 300}
 301
 302/* Disable threshold interrupt on local package/cpu */
 303static inline void disable_pkg_thres_interrupt(void)
 304{
 305        u32 l, h;
 306        rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
 307        wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
 308                        l & (~THERM_INT_THRESHOLD0_ENABLE) &
 309                                (~THERM_INT_THRESHOLD1_ENABLE), h);
 310}
 311
 312static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
 313{
 314        __u64 msr_val;
 315        int cpu = smp_processor_id();
 316        int phy_id = topology_physical_package_id(cpu);
 317        struct phy_dev_entry *phdev = pkg_temp_thermal_get_phy_entry(cpu);
 318        bool notify = false;
 319
 320        if (!phdev)
 321                return;
 322
 323        spin_lock(&pkg_work_lock);
 324        ++pkg_work_cnt;
 325        if (unlikely(phy_id > max_phy_id)) {
 326                spin_unlock(&pkg_work_lock);
 327                return;
 328        }
 329        pkg_work_scheduled[phy_id] = 0;
 330        spin_unlock(&pkg_work_lock);
 331
 332        enable_pkg_thres_interrupt();
 333        rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
 334        if (msr_val & THERM_LOG_THRESHOLD0) {
 335                wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS,
 336                                msr_val & ~THERM_LOG_THRESHOLD0);
 337                notify = true;
 338        }
 339        if (msr_val & THERM_LOG_THRESHOLD1) {
 340                wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS,
 341                                msr_val & ~THERM_LOG_THRESHOLD1);
 342                notify = true;
 343        }
 344        if (notify) {
 345                pr_debug("thermal_zone_device_update\n");
 346                thermal_zone_device_update(phdev->tzone);
 347        }
 348}
 349
 350static int pkg_temp_thermal_platform_thermal_notify(__u64 msr_val)
 351{
 352        unsigned long flags;
 353        int cpu = smp_processor_id();
 354        int phy_id = topology_physical_package_id(cpu);
 355
 356        /*
 357        * When a package is in interrupted state, all CPU's in that package
 358        * are in the same interrupt state. So scheduling on any one CPU in
 359        * the package is enough and simply return for others.
 360        */
 361        spin_lock_irqsave(&pkg_work_lock, flags);
 362        ++pkg_interrupt_cnt;
 363        if (unlikely(phy_id > max_phy_id) || unlikely(!pkg_work_scheduled) ||
 364                        pkg_work_scheduled[phy_id]) {
 365                disable_pkg_thres_interrupt();
 366                spin_unlock_irqrestore(&pkg_work_lock, flags);
 367                return -EINVAL;
 368        }
 369        pkg_work_scheduled[phy_id] = 1;
 370        spin_unlock_irqrestore(&pkg_work_lock, flags);
 371
 372        disable_pkg_thres_interrupt();
 373        schedule_delayed_work_on(cpu,
 374                                &per_cpu(pkg_temp_thermal_threshold_work, cpu),
 375                                msecs_to_jiffies(notify_delay_ms));
 376        return 0;
 377}
 378
 379static int find_siblings_cpu(int cpu)
 380{
 381        int i;
 382        int id = topology_physical_package_id(cpu);
 383
 384        for_each_online_cpu(i)
 385                if (i != cpu && topology_physical_package_id(i) == id)
 386                        return i;
 387
 388        return 0;
 389}
 390
 391static int pkg_temp_thermal_device_add(unsigned int cpu)
 392{
 393        int err;
 394        u32 tj_max;
 395        struct phy_dev_entry *phy_dev_entry;
 396        char buffer[30];
 397        int thres_count;
 398        u32 eax, ebx, ecx, edx;
 399        u8 *temp;
 400
 401        cpuid(6, &eax, &ebx, &ecx, &edx);
 402        thres_count = ebx & 0x07;
 403        if (!thres_count)
 404                return -ENODEV;
 405
 406        if (topology_physical_package_id(cpu) > MAX_PKG_TEMP_ZONE_IDS)
 407                return -ENODEV;
 408
 409        thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS);
 410
 411        err = get_tj_max(cpu, &tj_max);
 412        if (err)
 413                goto err_ret;
 414
 415        mutex_lock(&phy_dev_list_mutex);
 416
 417        phy_dev_entry = kzalloc(sizeof(*phy_dev_entry), GFP_KERNEL);
 418        if (!phy_dev_entry) {
 419                err = -ENOMEM;
 420                goto err_ret_unlock;
 421        }
 422
 423        spin_lock(&pkg_work_lock);
 424        if (topology_physical_package_id(cpu) > max_phy_id)
 425                max_phy_id = topology_physical_package_id(cpu);
 426        temp = krealloc(pkg_work_scheduled,
 427                        (max_phy_id+1) * sizeof(u8), GFP_ATOMIC);
 428        if (!temp) {
 429                spin_unlock(&pkg_work_lock);
 430                err = -ENOMEM;
 431                goto err_ret_free;
 432        }
 433        pkg_work_scheduled = temp;
 434        pkg_work_scheduled[topology_physical_package_id(cpu)] = 0;
 435        spin_unlock(&pkg_work_lock);
 436
 437        phy_dev_entry->phys_proc_id = topology_physical_package_id(cpu);
 438        phy_dev_entry->first_cpu = cpu;
 439        phy_dev_entry->tj_max = tj_max;
 440        phy_dev_entry->ref_cnt = 1;
 441        snprintf(buffer, sizeof(buffer), "pkg-temp-%d\n",
 442                                        phy_dev_entry->phys_proc_id);
 443        phy_dev_entry->tzone = thermal_zone_device_register(buffer,
 444                        thres_count,
 445                        (thres_count == MAX_NUMBER_OF_TRIPS) ?
 446                                0x03 : 0x01,
 447                        phy_dev_entry, &tzone_ops, NULL, 0, 0);
 448        if (IS_ERR(phy_dev_entry->tzone)) {
 449                err = PTR_ERR(phy_dev_entry->tzone);
 450                goto err_ret_free;
 451        }
 452        /* Store MSR value for package thermal interrupt, to restore at exit */
 453        rdmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
 454                                &phy_dev_entry->start_pkg_therm_low,
 455                                &phy_dev_entry->start_pkg_therm_high);
 456
 457        list_add_tail(&phy_dev_entry->list, &phy_dev_list);
 458        pr_debug("pkg_temp_thermal_device_add :phy_id %d cpu %d\n",
 459                        phy_dev_entry->phys_proc_id, cpu);
 460
 461        mutex_unlock(&phy_dev_list_mutex);
 462
 463        return 0;
 464
 465err_ret_free:
 466        kfree(phy_dev_entry);
 467err_ret_unlock:
 468        mutex_unlock(&phy_dev_list_mutex);
 469
 470err_ret:
 471        return err;
 472}
 473
 474static int pkg_temp_thermal_device_remove(unsigned int cpu)
 475{
 476        struct phy_dev_entry *n;
 477        u16 phys_proc_id = topology_physical_package_id(cpu);
 478        struct phy_dev_entry *phdev =
 479                        pkg_temp_thermal_get_phy_entry(cpu);
 480
 481        if (!phdev)
 482                return -ENODEV;
 483
 484        mutex_lock(&phy_dev_list_mutex);
 485        /* If we are loosing the first cpu for this package, we need change */
 486        if (phdev->first_cpu == cpu) {
 487                phdev->first_cpu = find_siblings_cpu(cpu);
 488                pr_debug("thermal_device_remove: first cpu switched %d\n",
 489                                        phdev->first_cpu);
 490        }
 491        /*
 492        * It is possible that no siblings left as this was the last cpu
 493        * going offline. We don't need to worry about this assignment
 494        * as the phydev entry will be removed in this case and
 495        * thermal zone is removed.
 496        */
 497        --phdev->ref_cnt;
 498        pr_debug("thermal_device_remove: pkg: %d cpu %d ref_cnt %d\n",
 499                                        phys_proc_id, cpu, phdev->ref_cnt);
 500        if (!phdev->ref_cnt)
 501                list_for_each_entry_safe(phdev, n, &phy_dev_list, list) {
 502                        if (phdev->phys_proc_id == phys_proc_id) {
 503                                thermal_zone_device_unregister(phdev->tzone);
 504                                list_del(&phdev->list);
 505                                kfree(phdev);
 506                                break;
 507                        }
 508                }
 509        mutex_unlock(&phy_dev_list_mutex);
 510
 511        return 0;
 512}
 513
 514static int get_core_online(unsigned int cpu)
 515{
 516        struct cpuinfo_x86 *c = &cpu_data(cpu);
 517        struct phy_dev_entry *phdev = pkg_temp_thermal_get_phy_entry(cpu);
 518
 519        /* Check if there is already an instance for this package */
 520        if (!phdev) {
 521                if (!cpu_has(c, X86_FEATURE_DTHERM) ||
 522                                        !cpu_has(c, X86_FEATURE_PTS))
 523                        return -ENODEV;
 524                if (pkg_temp_thermal_device_add(cpu))
 525                        return -ENODEV;
 526        } else {
 527                mutex_lock(&phy_dev_list_mutex);
 528                ++phdev->ref_cnt;
 529                pr_debug("get_core_online: cpu %d ref_cnt %d\n",
 530                                                cpu, phdev->ref_cnt);
 531                mutex_unlock(&phy_dev_list_mutex);
 532        }
 533        INIT_DELAYED_WORK(&per_cpu(pkg_temp_thermal_threshold_work, cpu),
 534                        pkg_temp_thermal_threshold_work_fn);
 535
 536        pr_debug("get_core_online: cpu %d successful\n", cpu);
 537
 538        return 0;
 539}
 540
 541static void put_core_offline(unsigned int cpu)
 542{
 543        if (!pkg_temp_thermal_device_remove(cpu))
 544                cancel_delayed_work_sync(
 545                        &per_cpu(pkg_temp_thermal_threshold_work, cpu));
 546
 547        pr_debug("put_core_offline: cpu %d\n", cpu);
 548}
 549
 550static int pkg_temp_thermal_cpu_callback(struct notifier_block *nfb,
 551                                 unsigned long action, void *hcpu)
 552{
 553        unsigned int cpu = (unsigned long) hcpu;
 554
 555        switch (action) {
 556        case CPU_ONLINE:
 557        case CPU_DOWN_FAILED:
 558                get_core_online(cpu);
 559                break;
 560        case CPU_DOWN_PREPARE:
 561                put_core_offline(cpu);
 562                break;
 563        }
 564        return NOTIFY_OK;
 565}
 566
 567static struct notifier_block pkg_temp_thermal_notifier __refdata = {
 568        .notifier_call = pkg_temp_thermal_cpu_callback,
 569};
 570
 571static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = {
 572        { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_PTS },
 573        {}
 574};
 575MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids);
 576
 577static int __init pkg_temp_thermal_init(void)
 578{
 579        int i;
 580
 581        if (!x86_match_cpu(pkg_temp_thermal_ids))
 582                return -ENODEV;
 583
 584        spin_lock_init(&pkg_work_lock);
 585        platform_thermal_package_notify =
 586                        pkg_temp_thermal_platform_thermal_notify;
 587        platform_thermal_package_rate_control =
 588                        pkg_temp_thermal_platform_thermal_rate_control;
 589
 590        get_online_cpus();
 591        for_each_online_cpu(i)
 592                if (get_core_online(i))
 593                        goto err_ret;
 594        register_hotcpu_notifier(&pkg_temp_thermal_notifier);
 595        put_online_cpus();
 596
 597        pkg_temp_debugfs_init(); /* Don't care if fails */
 598
 599        return 0;
 600
 601err_ret:
 602        for_each_online_cpu(i)
 603                put_core_offline(i);
 604        put_online_cpus();
 605        kfree(pkg_work_scheduled);
 606        platform_thermal_package_notify = NULL;
 607        platform_thermal_package_rate_control = NULL;
 608
 609        return -ENODEV;
 610}
 611
 612static void __exit pkg_temp_thermal_exit(void)
 613{
 614        struct phy_dev_entry *phdev, *n;
 615        int i;
 616
 617        get_online_cpus();
 618        unregister_hotcpu_notifier(&pkg_temp_thermal_notifier);
 619        mutex_lock(&phy_dev_list_mutex);
 620        list_for_each_entry_safe(phdev, n, &phy_dev_list, list) {
 621                /* Retore old MSR value for package thermal interrupt */
 622                wrmsr_on_cpu(phdev->first_cpu,
 623                        MSR_IA32_PACKAGE_THERM_INTERRUPT,
 624                        phdev->start_pkg_therm_low,
 625                        phdev->start_pkg_therm_high);
 626                thermal_zone_device_unregister(phdev->tzone);
 627                list_del(&phdev->list);
 628                kfree(phdev);
 629        }
 630        mutex_unlock(&phy_dev_list_mutex);
 631        platform_thermal_package_notify = NULL;
 632        platform_thermal_package_rate_control = NULL;
 633        for_each_online_cpu(i)
 634                cancel_delayed_work_sync(
 635                        &per_cpu(pkg_temp_thermal_threshold_work, i));
 636        put_online_cpus();
 637
 638        kfree(pkg_work_scheduled);
 639
 640        debugfs_remove_recursive(debugfs);
 641}
 642
 643module_init(pkg_temp_thermal_init)
 644module_exit(pkg_temp_thermal_exit)
 645
 646MODULE_DESCRIPTION("X86 PKG TEMP Thermal Driver");
 647MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 648MODULE_LICENSE("GPL v2");
 649
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.