1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * processor thermal device RFIM control 4 * Copyright (c) 2020, Intel Corporation. 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/module.h> 9 #include <linux/pci.h> 10 #include "processor_thermal_device.h" 11 12 static struct rapl_if_priv rapl_mmio_priv; 13 14 static const struct rapl_mmio_regs rapl_mmio_default = { 15 .reg_unit = 0x5938, 16 .regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930}, 17 .regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0}, 18 .limits[RAPL_DOMAIN_PACKAGE] = 2, 19 .limits[RAPL_DOMAIN_DRAM] = 2, 20 }; 21 22 static int rapl_mmio_cpu_online(unsigned int cpu) 23 { 24 struct rapl_package *rp; 25 26 /* mmio rapl supports package 0 only for now */ 27 if (topology_physical_package_id(cpu)) 28 return 0; 29 30 rp = rapl_find_package_domain(cpu, &rapl_mmio_priv); 31 if (!rp) { 32 rp = rapl_add_package(cpu, &rapl_mmio_priv); 33 if (IS_ERR(rp)) 34 return PTR_ERR(rp); 35 } 36 cpumask_set_cpu(cpu, &rp->cpumask); 37 return 0; 38 } 39 40 static int rapl_mmio_cpu_down_prep(unsigned int cpu) 41 { 42 struct rapl_package *rp; 43 int lead_cpu; 44 45 rp = rapl_find_package_domain(cpu, &rapl_mmio_priv); 46 if (!rp) 47 return 0; 48 49 cpumask_clear_cpu(cpu, &rp->cpumask); 50 lead_cpu = cpumask_first(&rp->cpumask); 51 if (lead_cpu >= nr_cpu_ids) 52 rapl_remove_package(rp); 53 else if (rp->lead_cpu == cpu) 54 rp->lead_cpu = lead_cpu; 55 return 0; 56 } 57 58 static int rapl_mmio_read_raw(int cpu, struct reg_action *ra) 59 { 60 if (!ra->reg) 61 return -EINVAL; 62 63 ra->value = readq((void __iomem *)ra->reg); 64 ra->value &= ra->mask; 65 return 0; 66 } 67 68 static int rapl_mmio_write_raw(int cpu, struct reg_action *ra) 69 { 70 u64 val; 71 72 if (!ra->reg) 73 return -EINVAL; 74 75 val = readq((void __iomem *)ra->reg); 76 val &= ~ra->mask; 77 val |= ra->value; 78 writeq(val, (void __iomem *)ra->reg); 79 return 0; 80 } 81 82 int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 83 { 84 const struct rapl_mmio_regs *rapl_regs = &rapl_mmio_default; 85 enum rapl_domain_reg_id reg; 86 enum rapl_domain_type domain; 87 int ret; 88 89 if (!rapl_regs) 90 return 0; 91 92 for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) { 93 for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++) 94 if (rapl_regs->regs[domain][reg]) 95 rapl_mmio_priv.regs[domain][reg] = 96 (u64)proc_priv->mmio_base + 97 rapl_regs->regs[domain][reg]; 98 rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain]; 99 } 100 rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit; 101 102 rapl_mmio_priv.read_raw = rapl_mmio_read_raw; 103 rapl_mmio_priv.write_raw = rapl_mmio_write_raw; 104 105 rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL); 106 if (IS_ERR(rapl_mmio_priv.control_type)) { 107 pr_debug("failed to register powercap control_type.\n"); 108 return PTR_ERR(rapl_mmio_priv.control_type); 109 } 110 111 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online", 112 rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep); 113 if (ret < 0) { 114 powercap_unregister_control_type(rapl_mmio_priv.control_type); 115 rapl_mmio_priv.control_type = NULL; 116 return ret; 117 } 118 rapl_mmio_priv.pcap_rapl_online = ret; 119 120 return 0; 121 } 122 EXPORT_SYMBOL_GPL(proc_thermal_rapl_add); 123 124 void proc_thermal_rapl_remove(void) 125 { 126 if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type)) 127 return; 128 129 cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online); 130 powercap_unregister_control_type(rapl_mmio_priv.control_type); 131 } 132 EXPORT_SYMBOL_GPL(proc_thermal_rapl_remove); 133 134 MODULE_LICENSE("GPL v2"); 135