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