linux/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Processor thermal device for newer processors
   4 * Copyright (c) 2020, Intel Corporation.
   5 */
   6
   7#include <linux/acpi.h>
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/pci.h>
  11#include <linux/thermal.h>
  12
  13#include "int340x_thermal_zone.h"
  14#include "processor_thermal_device.h"
  15
  16#define DRV_NAME "proc_thermal_pci"
  17
  18struct proc_thermal_pci {
  19        struct pci_dev *pdev;
  20        struct proc_thermal_device *proc_priv;
  21        struct thermal_zone_device *tzone;
  22        struct delayed_work work;
  23        int stored_thres;
  24        int no_legacy;
  25};
  26
  27enum proc_thermal_mmio_type {
  28        PROC_THERMAL_MMIO_TJMAX,
  29        PROC_THERMAL_MMIO_PP0_TEMP,
  30        PROC_THERMAL_MMIO_PP1_TEMP,
  31        PROC_THERMAL_MMIO_PKG_TEMP,
  32        PROC_THERMAL_MMIO_THRES_0,
  33        PROC_THERMAL_MMIO_THRES_1,
  34        PROC_THERMAL_MMIO_INT_ENABLE_0,
  35        PROC_THERMAL_MMIO_INT_ENABLE_1,
  36        PROC_THERMAL_MMIO_INT_STATUS_0,
  37        PROC_THERMAL_MMIO_INT_STATUS_1,
  38        PROC_THERMAL_MMIO_MAX
  39};
  40
  41struct proc_thermal_mmio_info {
  42        enum proc_thermal_mmio_type mmio_type;
  43        u64     mmio_addr;
  44        u64     shift;
  45        u64     mask;
  46};
  47
  48static struct proc_thermal_mmio_info proc_thermal_mmio_info[] = {
  49        { PROC_THERMAL_MMIO_TJMAX, 0x599c, 16, 0xff },
  50        { PROC_THERMAL_MMIO_PP0_TEMP, 0x597c, 0, 0xff },
  51        { PROC_THERMAL_MMIO_PP1_TEMP, 0x5980, 0, 0xff },
  52        { PROC_THERMAL_MMIO_PKG_TEMP, 0x5978, 0, 0xff },
  53        { PROC_THERMAL_MMIO_THRES_0, 0x5820, 8, 0x7F },
  54        { PROC_THERMAL_MMIO_THRES_1, 0x5820, 16, 0x7F },
  55        { PROC_THERMAL_MMIO_INT_ENABLE_0, 0x5820, 15, 0x01 },
  56        { PROC_THERMAL_MMIO_INT_ENABLE_1, 0x5820, 23, 0x01 },
  57        { PROC_THERMAL_MMIO_INT_STATUS_0, 0x7200, 6, 0x01 },
  58        { PROC_THERMAL_MMIO_INT_STATUS_1, 0x7200, 8, 0x01 },
  59};
  60
  61#define B0D4_THERMAL_NOTIFY_DELAY       1000
  62static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY;
  63
  64static void proc_thermal_mmio_read(struct proc_thermal_pci *pci_info,
  65                                    enum proc_thermal_mmio_type type,
  66                                    u32 *value)
  67{
  68        *value = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base +
  69                                proc_thermal_mmio_info[type].mmio_addr));
  70        *value >>= proc_thermal_mmio_info[type].shift;
  71        *value &= proc_thermal_mmio_info[type].mask;
  72}
  73
  74static void proc_thermal_mmio_write(struct proc_thermal_pci *pci_info,
  75                                     enum proc_thermal_mmio_type type,
  76                                     u32 value)
  77{
  78        u32 current_val;
  79        u32 mask;
  80
  81        current_val = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base +
  82                                proc_thermal_mmio_info[type].mmio_addr));
  83        mask = proc_thermal_mmio_info[type].mask << proc_thermal_mmio_info[type].shift;
  84        current_val &= ~mask;
  85
  86        value &= proc_thermal_mmio_info[type].mask;
  87        value <<= proc_thermal_mmio_info[type].shift;
  88
  89        current_val |= value;
  90        iowrite32(current_val, ((u8 __iomem *)pci_info->proc_priv->mmio_base +
  91                                proc_thermal_mmio_info[type].mmio_addr));
  92}
  93
  94/*
  95 * To avoid sending two many messages to user space, we have 1 second delay.
  96 * On interrupt we are disabling interrupt and enabling after 1 second.
  97 * This workload function is delayed by 1 second.
  98 */
  99static void proc_thermal_threshold_work_fn(struct work_struct *work)
 100{
 101        struct delayed_work *delayed_work = to_delayed_work(work);
 102        struct proc_thermal_pci *pci_info = container_of(delayed_work,
 103                                                struct proc_thermal_pci, work);
 104        struct thermal_zone_device *tzone = pci_info->tzone;
 105
 106        if (tzone)
 107                thermal_zone_device_update(tzone, THERMAL_TRIP_VIOLATED);
 108
 109        /* Enable interrupt flag */
 110        proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
 111}
 112
 113static void pkg_thermal_schedule_work(struct delayed_work *work)
 114{
 115        unsigned long ms = msecs_to_jiffies(notify_delay_ms);
 116
 117        schedule_delayed_work(work, ms);
 118}
 119
 120static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
 121{
 122        struct proc_thermal_pci *pci_info = devid;
 123        u32 status;
 124
 125        proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
 126
 127        /* Disable enable interrupt flag */
 128        proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
 129        pci_write_config_byte(pci_info->pdev, 0xdc, 0x01);
 130
 131        pkg_thermal_schedule_work(&pci_info->work);
 132
 133        return IRQ_HANDLED;
 134}
 135
 136static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
 137{
 138        struct proc_thermal_pci *pci_info = tzd->devdata;
 139        u32 _temp;
 140
 141        proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_PKG_TEMP, &_temp);
 142        *temp = (unsigned long)_temp * 1000;
 143
 144        return 0;
 145}
 146
 147static int sys_get_trip_temp(struct thermal_zone_device *tzd,
 148                             int trip, int *temp)
 149{
 150        struct proc_thermal_pci *pci_info = tzd->devdata;
 151        u32 _temp;
 152
 153        proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_THRES_0, &_temp);
 154        if (!_temp) {
 155                *temp = THERMAL_TEMP_INVALID;
 156        } else {
 157                int tjmax;
 158
 159                proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax);
 160                _temp = tjmax - _temp;
 161                *temp = (unsigned long)_temp * 1000;
 162        }
 163
 164        return 0;
 165}
 166
 167static int sys_get_trip_type(struct thermal_zone_device *tzd, int trip,
 168                              enum thermal_trip_type *type)
 169{
 170        *type = THERMAL_TRIP_PASSIVE;
 171
 172        return 0;
 173}
 174
 175static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
 176{
 177        struct proc_thermal_pci *pci_info = tzd->devdata;
 178        int tjmax, _temp;
 179
 180        if (temp <= 0) {
 181                cancel_delayed_work_sync(&pci_info->work);
 182                proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
 183                proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
 184                thermal_zone_device_disable(tzd);
 185                pci_info->stored_thres = 0;
 186                return 0;
 187        }
 188
 189        proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax);
 190        _temp = tjmax - (temp / 1000);
 191        if (_temp < 0)
 192                return -EINVAL;
 193
 194        proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, _temp);
 195        proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
 196
 197        thermal_zone_device_enable(tzd);
 198        pci_info->stored_thres = temp;
 199
 200        return 0;
 201}
 202
 203static struct thermal_zone_device_ops tzone_ops = {
 204        .get_temp = sys_get_curr_temp,
 205        .get_trip_temp = sys_get_trip_temp,
 206        .get_trip_type = sys_get_trip_type,
 207        .set_trip_temp  = sys_set_trip_temp,
 208};
 209
 210static struct thermal_zone_params tzone_params = {
 211        .governor_name = "user_space",
 212        .no_hwmon = true,
 213};
 214
 215static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 216{
 217        struct proc_thermal_device *proc_priv;
 218        struct proc_thermal_pci *pci_info;
 219        int irq_flag = 0, irq, ret;
 220
 221        proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
 222        if (!proc_priv)
 223                return -ENOMEM;
 224
 225        pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL);
 226        if (!pci_info)
 227                return -ENOMEM;
 228
 229        pci_info->pdev = pdev;
 230        ret = pcim_enable_device(pdev);
 231        if (ret < 0) {
 232                dev_err(&pdev->dev, "error: could not enable device\n");
 233                return ret;
 234        }
 235
 236        pci_set_master(pdev);
 237
 238        INIT_DELAYED_WORK(&pci_info->work, proc_thermal_threshold_work_fn);
 239
 240        ret = proc_thermal_add(&pdev->dev, proc_priv);
 241        if (ret) {
 242                dev_err(&pdev->dev, "error: proc_thermal_add, will continue\n");
 243                pci_info->no_legacy = 1;
 244        }
 245
 246        proc_priv->priv_data = pci_info;
 247        pci_info->proc_priv = proc_priv;
 248        pci_set_drvdata(pdev, proc_priv);
 249
 250        ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
 251        if (ret)
 252                goto err_ret_thermal;
 253
 254        pci_info->tzone = thermal_zone_device_register("TCPU_PCI", 1, 1, pci_info,
 255                                                        &tzone_ops,
 256                                                        &tzone_params, 0, 0);
 257        if (IS_ERR(pci_info->tzone)) {
 258                ret = PTR_ERR(pci_info->tzone);
 259                goto err_ret_mmio;
 260        }
 261
 262        /* request and enable interrupt */
 263        ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
 264        if (ret < 0) {
 265                dev_err(&pdev->dev, "Failed to allocate vectors!\n");
 266                goto err_ret_tzone;
 267        }
 268        if (!pdev->msi_enabled && !pdev->msix_enabled)
 269                irq_flag = IRQF_SHARED;
 270
 271        irq =  pci_irq_vector(pdev, 0);
 272        ret = devm_request_threaded_irq(&pdev->dev, irq,
 273                                        proc_thermal_irq_handler, NULL,
 274                                        irq_flag, KBUILD_MODNAME, pci_info);
 275        if (ret) {
 276                dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
 277                goto err_free_vectors;
 278        }
 279
 280        return 0;
 281
 282err_free_vectors:
 283        pci_free_irq_vectors(pdev);
 284err_ret_tzone:
 285        thermal_zone_device_unregister(pci_info->tzone);
 286err_ret_mmio:
 287        proc_thermal_mmio_remove(pdev, proc_priv);
 288err_ret_thermal:
 289        if (!pci_info->no_legacy)
 290                proc_thermal_remove(proc_priv);
 291        pci_disable_device(pdev);
 292
 293        return ret;
 294}
 295
 296static void proc_thermal_pci_remove(struct pci_dev *pdev)
 297{
 298        struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
 299        struct proc_thermal_pci *pci_info = proc_priv->priv_data;
 300
 301        cancel_delayed_work_sync(&pci_info->work);
 302
 303        proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
 304        proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
 305
 306        devm_free_irq(&pdev->dev, pdev->irq, pci_info);
 307        pci_free_irq_vectors(pdev);
 308
 309        thermal_zone_device_unregister(pci_info->tzone);
 310        proc_thermal_mmio_remove(pdev, pci_info->proc_priv);
 311        if (!pci_info->no_legacy)
 312                proc_thermal_remove(proc_priv);
 313        pci_disable_device(pdev);
 314}
 315
 316#ifdef CONFIG_PM_SLEEP
 317static int proc_thermal_pci_suspend(struct device *dev)
 318{
 319        struct pci_dev *pdev = to_pci_dev(dev);
 320        struct proc_thermal_device *proc_priv;
 321        struct proc_thermal_pci *pci_info;
 322
 323        proc_priv = pci_get_drvdata(pdev);
 324        pci_info = proc_priv->priv_data;
 325
 326        if (!pci_info->no_legacy)
 327                return proc_thermal_suspend(dev);
 328
 329        return 0;
 330}
 331static int proc_thermal_pci_resume(struct device *dev)
 332{
 333        struct pci_dev *pdev = to_pci_dev(dev);
 334        struct proc_thermal_device *proc_priv;
 335        struct proc_thermal_pci *pci_info;
 336
 337        proc_priv = pci_get_drvdata(pdev);
 338        pci_info = proc_priv->priv_data;
 339
 340        if (pci_info->stored_thres) {
 341                proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0,
 342                                         pci_info->stored_thres / 1000);
 343                proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
 344        }
 345
 346        if (!pci_info->no_legacy)
 347                return proc_thermal_resume(dev);
 348
 349        return 0;
 350}
 351#else
 352#define proc_thermal_pci_suspend NULL
 353#define proc_thermal_pci_resume NULL
 354#endif
 355
 356static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
 357                         proc_thermal_pci_resume);
 358
 359static const struct pci_device_id proc_thermal_pci_ids[] = {
 360        { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
 361        { PCI_DEVICE_DATA(INTEL, RPL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
 362        { },
 363};
 364
 365MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
 366
 367static struct pci_driver proc_thermal_pci_driver = {
 368        .name           = DRV_NAME,
 369        .probe          = proc_thermal_pci_probe,
 370        .remove = proc_thermal_pci_remove,
 371        .id_table       = proc_thermal_pci_ids,
 372        .driver.pm      = &proc_thermal_pci_pm,
 373};
 374
 375static int __init proc_thermal_init(void)
 376{
 377        return pci_register_driver(&proc_thermal_pci_driver);
 378}
 379
 380static void __exit proc_thermal_exit(void)
 381{
 382        pci_unregister_driver(&proc_thermal_pci_driver);
 383}
 384
 385module_init(proc_thermal_init);
 386module_exit(proc_thermal_exit);
 387
 388MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 389MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
 390MODULE_LICENSE("GPL v2");
 391