1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * PCIe cooling device 4 * 5 * Copyright (C) 2023-2024 Intel Corporation 6 */ 7 8 #include <linux/build_bug.h> 9 #include <linux/cleanup.h> 10 #include <linux/err.h> 11 #include <linux/module.h> 12 #include <linux/pci.h> 13 #include <linux/pci-bwctrl.h> 14 #include <linux/slab.h> 15 #include <linux/sprintf.h> 16 #include <linux/thermal.h> 17 18 #define COOLING_DEV_TYPE_PREFIX "PCIe_Port_Link_Speed_" 19 20 static int pcie_cooling_get_max_level(struct thermal_cooling_device *cdev, unsigned long *state) 21 { 22 struct pci_dev *port = cdev->devdata; 23 24 /* cooling state 0 is same as the maximum PCIe speed */ 25 *state = port->subordinate->max_bus_speed - PCIE_SPEED_2_5GT; 26 27 return 0; 28 } 29 30 static int pcie_cooling_get_cur_level(struct thermal_cooling_device *cdev, unsigned long *state) 31 { 32 struct pci_dev *port = cdev->devdata; 33 34 /* cooling state 0 is same as the maximum PCIe speed */ 35 *state = cdev->max_state - (port->subordinate->cur_bus_speed - PCIE_SPEED_2_5GT); 36 37 return 0; 38 } 39 40 static int pcie_cooling_set_cur_level(struct thermal_cooling_device *cdev, unsigned long state) 41 { 42 struct pci_dev *port = cdev->devdata; 43 enum pci_bus_speed speed; 44 45 /* cooling state 0 is same as the maximum PCIe speed */ 46 speed = (cdev->max_state - state) + PCIE_SPEED_2_5GT; 47 48 return pcie_set_target_speed(port, speed, true); 49 } 50 51 static struct thermal_cooling_device_ops pcie_cooling_ops = { 52 .get_max_state = pcie_cooling_get_max_level, 53 .get_cur_state = pcie_cooling_get_cur_level, 54 .set_cur_state = pcie_cooling_set_cur_level, 55 }; 56 57 struct thermal_cooling_device *pcie_cooling_device_register(struct pci_dev *port) 58 { 59 char *name __free(kfree) = 60 kasprintf(GFP_KERNEL, COOLING_DEV_TYPE_PREFIX "%s", pci_name(port)); 61 if (!name) 62 return ERR_PTR(-ENOMEM); 63 64 return thermal_cooling_device_register(name, port, &pcie_cooling_ops); 65 } 66 67 void pcie_cooling_device_unregister(struct thermal_cooling_device *cdev) 68 { 69 thermal_cooling_device_unregister(cdev); 70 } 71 72 /* For bus_speed <-> state arithmetic */ 73 static_assert(PCIE_SPEED_2_5GT + 1 == PCIE_SPEED_5_0GT); 74 static_assert(PCIE_SPEED_5_0GT + 1 == PCIE_SPEED_8_0GT); 75 static_assert(PCIE_SPEED_8_0GT + 1 == PCIE_SPEED_16_0GT); 76 static_assert(PCIE_SPEED_16_0GT + 1 == PCIE_SPEED_32_0GT); 77 static_assert(PCIE_SPEED_32_0GT + 1 == PCIE_SPEED_64_0GT); 78 79 MODULE_AUTHOR("Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>"); 80 MODULE_DESCRIPTION("PCIe cooling driver"); 81