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