1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * intel_rapl_tpmi: Intel RAPL driver via TPMI interface 4 * 5 * Copyright (c) 2023, Intel Corporation. 6 * All Rights Reserved. 7 * 8 */ 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11 #include <linux/auxiliary_bus.h> 12 #include <linux/io.h> 13 #include <linux/intel_tpmi.h> 14 #include <linux/intel_rapl.h> 15 #include <linux/module.h> 16 #include <linux/slab.h> 17 18 #define TPMI_RAPL_VERSION 1 19 20 /* 1 header + 10 registers + 5 reserved. 8 bytes for each. */ 21 #define TPMI_RAPL_DOMAIN_SIZE 128 22 23 enum tpmi_rapl_domain_type { 24 TPMI_RAPL_DOMAIN_INVALID, 25 TPMI_RAPL_DOMAIN_SYSTEM, 26 TPMI_RAPL_DOMAIN_PACKAGE, 27 TPMI_RAPL_DOMAIN_RESERVED, 28 TPMI_RAPL_DOMAIN_MEMORY, 29 TPMI_RAPL_DOMAIN_MAX, 30 }; 31 32 enum tpmi_rapl_register { 33 TPMI_RAPL_REG_HEADER, 34 TPMI_RAPL_REG_UNIT, 35 TPMI_RAPL_REG_PL1, 36 TPMI_RAPL_REG_PL2, 37 TPMI_RAPL_REG_PL3, 38 TPMI_RAPL_REG_PL4, 39 TPMI_RAPL_REG_RESERVED, 40 TPMI_RAPL_REG_ENERGY_STATUS, 41 TPMI_RAPL_REG_PERF_STATUS, 42 TPMI_RAPL_REG_POWER_INFO, 43 TPMI_RAPL_REG_INTERRUPT, 44 TPMI_RAPL_REG_MAX = 15, 45 }; 46 47 struct tpmi_rapl_package { 48 struct rapl_if_priv priv; 49 struct intel_tpmi_plat_info *tpmi_info; 50 struct rapl_package *rp; 51 void __iomem *base; 52 struct list_head node; 53 }; 54 55 static LIST_HEAD(tpmi_rapl_packages); 56 static DEFINE_MUTEX(tpmi_rapl_lock); 57 58 static struct powercap_control_type *tpmi_control_type; 59 60 static int tpmi_rapl_read_raw(int id, struct reg_action *ra) 61 { 62 if (!ra->reg) 63 return -EINVAL; 64 65 ra->value = readq((void __iomem *)ra->reg); 66 67 ra->value &= ra->mask; 68 return 0; 69 } 70 71 static int tpmi_rapl_write_raw(int id, struct reg_action *ra) 72 { 73 u64 val; 74 75 if (!ra->reg) 76 return -EINVAL; 77 78 val = readq((void __iomem *)ra->reg); 79 80 val &= ~ra->mask; 81 val |= ra->value; 82 83 writeq(val, (void __iomem *)ra->reg); 84 return 0; 85 } 86 87 static struct tpmi_rapl_package *trp_alloc(int pkg_id) 88 { 89 struct tpmi_rapl_package *trp; 90 int ret; 91 92 mutex_lock(&tpmi_rapl_lock); 93 94 if (list_empty(&tpmi_rapl_packages)) { 95 tpmi_control_type = powercap_register_control_type(NULL, "intel-rapl", NULL); 96 if (IS_ERR(tpmi_control_type)) { 97 ret = PTR_ERR(tpmi_control_type); 98 goto err_unlock; 99 } 100 } 101 102 trp = kzalloc(sizeof(*trp), GFP_KERNEL); 103 if (!trp) { 104 ret = -ENOMEM; 105 goto err_del_powercap; 106 } 107 108 list_add(&trp->node, &tpmi_rapl_packages); 109 110 mutex_unlock(&tpmi_rapl_lock); 111 return trp; 112 113 err_del_powercap: 114 if (list_empty(&tpmi_rapl_packages)) 115 powercap_unregister_control_type(tpmi_control_type); 116 err_unlock: 117 mutex_unlock(&tpmi_rapl_lock); 118 return ERR_PTR(ret); 119 } 120 121 static void trp_release(struct tpmi_rapl_package *trp) 122 { 123 mutex_lock(&tpmi_rapl_lock); 124 list_del(&trp->node); 125 126 if (list_empty(&tpmi_rapl_packages)) 127 powercap_unregister_control_type(tpmi_control_type); 128 129 kfree(trp); 130 mutex_unlock(&tpmi_rapl_lock); 131 } 132 133 static int parse_one_domain(struct tpmi_rapl_package *trp, u32 offset) 134 { 135 u8 tpmi_domain_version; 136 enum rapl_domain_type domain_type; 137 enum tpmi_rapl_domain_type tpmi_domain_type; 138 enum tpmi_rapl_register reg_index; 139 enum rapl_domain_reg_id reg_id; 140 int tpmi_domain_size, tpmi_domain_flags; 141 u64 *tpmi_rapl_regs = trp->base + offset; 142 u64 tpmi_domain_header = readq((void __iomem *)tpmi_rapl_regs); 143 144 /* Domain Parent bits are ignored for now */ 145 tpmi_domain_version = tpmi_domain_header & 0xff; 146 tpmi_domain_type = tpmi_domain_header >> 8 & 0xff; 147 tpmi_domain_size = tpmi_domain_header >> 16 & 0xff; 148 tpmi_domain_flags = tpmi_domain_header >> 32 & 0xffff; 149 150 if (tpmi_domain_version != TPMI_RAPL_VERSION) { 151 pr_warn(FW_BUG "Unsupported version:%d\n", tpmi_domain_version); 152 return -ENODEV; 153 } 154 155 /* Domain size: in unit of 128 Bytes */ 156 if (tpmi_domain_size != 1) { 157 pr_warn(FW_BUG "Invalid Domain size %d\n", tpmi_domain_size); 158 return -EINVAL; 159 } 160 161 /* Unit register and Energy Status register are mandatory for each domain */ 162 if (!(tpmi_domain_flags & BIT(TPMI_RAPL_REG_UNIT)) || 163 !(tpmi_domain_flags & BIT(TPMI_RAPL_REG_ENERGY_STATUS))) { 164 pr_warn(FW_BUG "Invalid Domain flag 0x%x\n", tpmi_domain_flags); 165 return -EINVAL; 166 } 167 168 switch (tpmi_domain_type) { 169 case TPMI_RAPL_DOMAIN_PACKAGE: 170 domain_type = RAPL_DOMAIN_PACKAGE; 171 break; 172 case TPMI_RAPL_DOMAIN_SYSTEM: 173 domain_type = RAPL_DOMAIN_PLATFORM; 174 break; 175 case TPMI_RAPL_DOMAIN_MEMORY: 176 domain_type = RAPL_DOMAIN_DRAM; 177 break; 178 default: 179 pr_warn(FW_BUG "Unsupported Domain type %d\n", tpmi_domain_type); 180 return -EINVAL; 181 } 182 183 if (trp->priv.regs[domain_type][RAPL_DOMAIN_REG_UNIT]) { 184 pr_warn(FW_BUG "Duplicate Domain type %d\n", tpmi_domain_type); 185 return -EINVAL; 186 } 187 188 reg_index = TPMI_RAPL_REG_HEADER; 189 while (++reg_index != TPMI_RAPL_REG_MAX) { 190 if (!(tpmi_domain_flags & BIT(reg_index))) 191 continue; 192 193 switch (reg_index) { 194 case TPMI_RAPL_REG_UNIT: 195 reg_id = RAPL_DOMAIN_REG_UNIT; 196 break; 197 case TPMI_RAPL_REG_PL1: 198 reg_id = RAPL_DOMAIN_REG_LIMIT; 199 trp->priv.limits[domain_type] |= BIT(POWER_LIMIT1); 200 break; 201 case TPMI_RAPL_REG_PL2: 202 reg_id = RAPL_DOMAIN_REG_PL2; 203 trp->priv.limits[domain_type] |= BIT(POWER_LIMIT2); 204 break; 205 case TPMI_RAPL_REG_PL4: 206 reg_id = RAPL_DOMAIN_REG_PL4; 207 trp->priv.limits[domain_type] |= BIT(POWER_LIMIT4); 208 break; 209 case TPMI_RAPL_REG_ENERGY_STATUS: 210 reg_id = RAPL_DOMAIN_REG_STATUS; 211 break; 212 case TPMI_RAPL_REG_PERF_STATUS: 213 reg_id = RAPL_DOMAIN_REG_PERF; 214 break; 215 case TPMI_RAPL_REG_POWER_INFO: 216 reg_id = RAPL_DOMAIN_REG_INFO; 217 break; 218 default: 219 continue; 220 } 221 trp->priv.regs[domain_type][reg_id] = (u64)&tpmi_rapl_regs[reg_index]; 222 } 223 224 return 0; 225 } 226 227 static int intel_rapl_tpmi_probe(struct auxiliary_device *auxdev, 228 const struct auxiliary_device_id *id) 229 { 230 struct tpmi_rapl_package *trp; 231 struct intel_tpmi_plat_info *info; 232 struct resource *res; 233 u32 offset; 234 int ret; 235 236 info = tpmi_get_platform_data(auxdev); 237 if (!info) 238 return -ENODEV; 239 240 trp = trp_alloc(info->package_id); 241 if (IS_ERR(trp)) 242 return PTR_ERR(trp); 243 244 if (tpmi_get_resource_count(auxdev) > 1) { 245 dev_err(&auxdev->dev, "does not support multiple resources\n"); 246 ret = -EINVAL; 247 goto err; 248 } 249 250 res = tpmi_get_resource_at_index(auxdev, 0); 251 if (!res) { 252 dev_err(&auxdev->dev, "can't fetch device resource info\n"); 253 ret = -EIO; 254 goto err; 255 } 256 257 trp->base = devm_ioremap_resource(&auxdev->dev, res); 258 if (IS_ERR(trp->base)) { 259 ret = PTR_ERR(trp->base); 260 goto err; 261 } 262 263 for (offset = 0; offset < resource_size(res); offset += TPMI_RAPL_DOMAIN_SIZE) { 264 ret = parse_one_domain(trp, offset); 265 if (ret) 266 goto err; 267 } 268 269 trp->tpmi_info = info; 270 trp->priv.type = RAPL_IF_TPMI; 271 trp->priv.read_raw = tpmi_rapl_read_raw; 272 trp->priv.write_raw = tpmi_rapl_write_raw; 273 trp->priv.control_type = tpmi_control_type; 274 275 /* RAPL TPMI I/F is per physical package */ 276 trp->rp = rapl_find_package_domain(info->package_id, &trp->priv, false); 277 if (trp->rp) { 278 dev_err(&auxdev->dev, "Domain for Package%d already exists\n", info->package_id); 279 ret = -EEXIST; 280 goto err; 281 } 282 283 trp->rp = rapl_add_package(info->package_id, &trp->priv, false); 284 if (IS_ERR(trp->rp)) { 285 dev_err(&auxdev->dev, "Failed to add RAPL Domain for Package%d, %ld\n", 286 info->package_id, PTR_ERR(trp->rp)); 287 ret = PTR_ERR(trp->rp); 288 goto err; 289 } 290 291 auxiliary_set_drvdata(auxdev, trp); 292 293 return 0; 294 err: 295 trp_release(trp); 296 return ret; 297 } 298 299 static void intel_rapl_tpmi_remove(struct auxiliary_device *auxdev) 300 { 301 struct tpmi_rapl_package *trp = auxiliary_get_drvdata(auxdev); 302 303 rapl_remove_package(trp->rp); 304 trp_release(trp); 305 } 306 307 static const struct auxiliary_device_id intel_rapl_tpmi_ids[] = { 308 {.name = "intel_vsec.tpmi-rapl" }, 309 { } 310 }; 311 312 MODULE_DEVICE_TABLE(auxiliary, intel_rapl_tpmi_ids); 313 314 static struct auxiliary_driver intel_rapl_tpmi_driver = { 315 .probe = intel_rapl_tpmi_probe, 316 .remove = intel_rapl_tpmi_remove, 317 .id_table = intel_rapl_tpmi_ids, 318 }; 319 320 module_auxiliary_driver(intel_rapl_tpmi_driver) 321 322 MODULE_IMPORT_NS(INTEL_TPMI); 323 324 MODULE_DESCRIPTION("Intel RAPL TPMI Driver"); 325 MODULE_LICENSE("GPL"); 326