1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Processor thermal device module for registering and processing 4 * power floor. When the hardware reduces the power to the minimum 5 * possible, the power floor is notified via an interrupt. 6 * 7 * Operation: 8 * When user space enables power floor reporting: 9 * - Use mailbox to: 10 * Enable processor thermal device interrupt 11 * 12 * - Current status of power floor is read from offset 0x5B18 13 * bit 39. 14 * 15 * Two interface functions are provided to call when there is a 16 * thermal device interrupt: 17 * - proc_thermal_power_floor_intr(): 18 * Check if the interrupt is for change in power floor. 19 * Called from interrupt context. 20 * 21 * - proc_thermal_power_floor_intr_callback(): 22 * Callback for interrupt processing in thread context. This involves 23 * sending notification to user space that there is a change in the 24 * power floor status. 25 * 26 * Copyright (c) 2023, Intel Corporation. 27 */ 28 29 #include <linux/pci.h> 30 #include "processor_thermal_device.h" 31 32 #define SOC_POWER_FLOOR_STATUS BIT(39) 33 #define SOC_POWER_FLOOR_SHIFT 39 34 35 #define SOC_POWER_FLOOR_INT_ENABLE_BIT 31 36 #define SOC_POWER_FLOOR_INT_ACTIVE BIT(3) 37 38 int proc_thermal_read_power_floor_status(struct proc_thermal_device *proc_priv) 39 { 40 u64 status = 0; 41 42 status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET); 43 return (status & SOC_POWER_FLOOR_STATUS) >> SOC_POWER_FLOOR_SHIFT; 44 } 45 EXPORT_SYMBOL_NS_GPL(proc_thermal_read_power_floor_status, "INT340X_THERMAL"); 46 47 static bool enable_state; 48 static DEFINE_MUTEX(pf_lock); 49 50 int proc_thermal_power_floor_set_state(struct proc_thermal_device *proc_priv, bool enable) 51 { 52 int ret = 0; 53 54 mutex_lock(&pf_lock); 55 if (enable_state == enable) 56 goto pf_unlock; 57 58 /* 59 * Time window parameter is not applicable to power floor interrupt configuration. 60 * Hence use -1 for time window. 61 */ 62 ret = processor_thermal_mbox_interrupt_config(to_pci_dev(proc_priv->dev), enable, 63 SOC_POWER_FLOOR_INT_ENABLE_BIT, -1); 64 if (!ret) 65 enable_state = enable; 66 67 pf_unlock: 68 mutex_unlock(&pf_lock); 69 70 return ret; 71 } 72 EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_set_state, "INT340X_THERMAL"); 73 74 bool proc_thermal_power_floor_get_state(struct proc_thermal_device *proc_priv) 75 { 76 return enable_state; 77 } 78 EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_get_state, "INT340X_THERMAL"); 79 80 /** 81 * proc_thermal_check_power_floor_intr() - Check power floor interrupt. 82 * @proc_priv: Processor thermal device instance. 83 * 84 * Callback to check if the interrupt for power floor is active. 85 * 86 * Context: Called from interrupt context. 87 * 88 * Return: true if power floor is active, false when not active. 89 */ 90 bool proc_thermal_check_power_floor_intr(struct proc_thermal_device *proc_priv) 91 { 92 u64 int_status; 93 94 int_status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET); 95 return !!(int_status & SOC_POWER_FLOOR_INT_ACTIVE); 96 } 97 EXPORT_SYMBOL_NS_GPL(proc_thermal_check_power_floor_intr, "INT340X_THERMAL"); 98 99 /** 100 * proc_thermal_power_floor_intr_callback() - Process power floor notification 101 * @pdev: PCI device instance 102 * @proc_priv: Processor thermal device instance. 103 * 104 * Check if the power floor interrupt is active, if active send notification to 105 * user space for the attribute "power_limits", so that user can read the attribute 106 * and take action. 107 * 108 * Context: Called from interrupt thread context. 109 * 110 * Return: None. 111 */ 112 void proc_thermal_power_floor_intr_callback(struct pci_dev *pdev, 113 struct proc_thermal_device *proc_priv) 114 { 115 u64 status; 116 117 status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET); 118 if (!(status & SOC_POWER_FLOOR_INT_ACTIVE)) 119 return; 120 121 sysfs_notify(&pdev->dev.kobj, "power_limits", "power_floor_status"); 122 } 123 EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_intr_callback, "INT340X_THERMAL"); 124 125 MODULE_IMPORT_NS("INT340X_THERMAL"); 126 MODULE_LICENSE("GPL"); 127 MODULE_DESCRIPTION("Processor Thermal power floor notification Interface"); 128