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.mmio) 63 return -EINVAL; 64 65 ra->value = readq(ra->reg.mmio); 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.mmio) 76 return -EINVAL; 77 78 val = readq(ra->reg.mmio); 79 80 val &= ~ra->mask; 81 val |= ra->value; 82 83 writeq(val, ra->reg.mmio); 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_domain_header = readq(trp->base + offset); 142 143 /* Domain Parent bits are ignored for now */ 144 tpmi_domain_version = tpmi_domain_header & 0xff; 145 tpmi_domain_type = tpmi_domain_header >> 8 & 0xff; 146 tpmi_domain_size = tpmi_domain_header >> 16 & 0xff; 147 tpmi_domain_flags = tpmi_domain_header >> 32 & 0xffff; 148 149 if (tpmi_domain_version != TPMI_RAPL_VERSION) { 150 pr_warn(FW_BUG "Unsupported version:%d\n", tpmi_domain_version); 151 return -ENODEV; 152 } 153 154 /* Domain size: in unit of 128 Bytes */ 155 if (tpmi_domain_size != 1) { 156 pr_warn(FW_BUG "Invalid Domain size %d\n", tpmi_domain_size); 157 return -EINVAL; 158 } 159 160 /* Unit register and Energy Status register are mandatory for each domain */ 161 if (!(tpmi_domain_flags & BIT(TPMI_RAPL_REG_UNIT)) || 162 !(tpmi_domain_flags & BIT(TPMI_RAPL_REG_ENERGY_STATUS))) { 163 pr_warn(FW_BUG "Invalid Domain flag 0x%x\n", tpmi_domain_flags); 164 return -EINVAL; 165 } 166 167 switch (tpmi_domain_type) { 168 case TPMI_RAPL_DOMAIN_PACKAGE: 169 domain_type = RAPL_DOMAIN_PACKAGE; 170 break; 171 case TPMI_RAPL_DOMAIN_SYSTEM: 172 domain_type = RAPL_DOMAIN_PLATFORM; 173 break; 174 case TPMI_RAPL_DOMAIN_MEMORY: 175 domain_type = RAPL_DOMAIN_DRAM; 176 break; 177 default: 178 pr_warn(FW_BUG "Unsupported Domain type %d\n", tpmi_domain_type); 179 return -EINVAL; 180 } 181 182 if (trp->priv.regs[domain_type][RAPL_DOMAIN_REG_UNIT].mmio) { 183 pr_warn(FW_BUG "Duplicate Domain type %d\n", tpmi_domain_type); 184 return -EINVAL; 185 } 186 187 reg_index = TPMI_RAPL_REG_HEADER; 188 while (++reg_index != TPMI_RAPL_REG_MAX) { 189 if (!(tpmi_domain_flags & BIT(reg_index))) 190 continue; 191 192 switch (reg_index) { 193 case TPMI_RAPL_REG_UNIT: 194 reg_id = RAPL_DOMAIN_REG_UNIT; 195 break; 196 case TPMI_RAPL_REG_PL1: 197 reg_id = RAPL_DOMAIN_REG_LIMIT; 198 trp->priv.limits[domain_type] |= BIT(POWER_LIMIT1); 199 break; 200 case TPMI_RAPL_REG_PL2: 201 reg_id = RAPL_DOMAIN_REG_PL2; 202 trp->priv.limits[domain_type] |= BIT(POWER_LIMIT2); 203 break; 204 case TPMI_RAPL_REG_PL4: 205 reg_id = RAPL_DOMAIN_REG_PL4; 206 trp->priv.limits[domain_type] |= BIT(POWER_LIMIT4); 207 break; 208 case TPMI_RAPL_REG_ENERGY_STATUS: 209 reg_id = RAPL_DOMAIN_REG_STATUS; 210 break; 211 case TPMI_RAPL_REG_PERF_STATUS: 212 reg_id = RAPL_DOMAIN_REG_PERF; 213 break; 214 case TPMI_RAPL_REG_POWER_INFO: 215 reg_id = RAPL_DOMAIN_REG_INFO; 216 break; 217 default: 218 continue; 219 } 220 trp->priv.regs[domain_type][reg_id].mmio = trp->base + offset + reg_index * 8; 221 } 222 223 return 0; 224 } 225 226 static int intel_rapl_tpmi_probe(struct auxiliary_device *auxdev, 227 const struct auxiliary_device_id *id) 228 { 229 struct tpmi_rapl_package *trp; 230 struct intel_tpmi_plat_info *info; 231 struct resource *res; 232 u32 offset; 233 int ret; 234 235 info = tpmi_get_platform_data(auxdev); 236 if (!info) 237 return -ENODEV; 238 239 trp = trp_alloc(info->package_id); 240 if (IS_ERR(trp)) 241 return PTR_ERR(trp); 242 243 if (tpmi_get_resource_count(auxdev) > 1) { 244 dev_err(&auxdev->dev, "does not support multiple resources\n"); 245 ret = -EINVAL; 246 goto err; 247 } 248 249 res = tpmi_get_resource_at_index(auxdev, 0); 250 if (!res) { 251 dev_err(&auxdev->dev, "can't fetch device resource info\n"); 252 ret = -EIO; 253 goto err; 254 } 255 256 trp->base = devm_ioremap_resource(&auxdev->dev, res); 257 if (IS_ERR(trp->base)) { 258 ret = PTR_ERR(trp->base); 259 goto err; 260 } 261 262 for (offset = 0; offset < resource_size(res); offset += TPMI_RAPL_DOMAIN_SIZE) { 263 ret = parse_one_domain(trp, offset); 264 if (ret) 265 goto err; 266 } 267 268 trp->tpmi_info = info; 269 trp->priv.type = RAPL_IF_TPMI; 270 trp->priv.read_raw = tpmi_rapl_read_raw; 271 trp->priv.write_raw = tpmi_rapl_write_raw; 272 trp->priv.control_type = tpmi_control_type; 273 274 /* RAPL TPMI I/F is per physical package */ 275 trp->rp = rapl_find_package_domain(info->package_id, &trp->priv, false); 276 if (trp->rp) { 277 dev_err(&auxdev->dev, "Domain for Package%d already exists\n", info->package_id); 278 ret = -EEXIST; 279 goto err; 280 } 281 282 trp->rp = rapl_add_package(info->package_id, &trp->priv, false); 283 if (IS_ERR(trp->rp)) { 284 dev_err(&auxdev->dev, "Failed to add RAPL Domain for Package%d, %ld\n", 285 info->package_id, PTR_ERR(trp->rp)); 286 ret = PTR_ERR(trp->rp); 287 goto err; 288 } 289 290 auxiliary_set_drvdata(auxdev, trp); 291 292 return 0; 293 err: 294 trp_release(trp); 295 return ret; 296 } 297 298 static void intel_rapl_tpmi_remove(struct auxiliary_device *auxdev) 299 { 300 struct tpmi_rapl_package *trp = auxiliary_get_drvdata(auxdev); 301 302 rapl_remove_package(trp->rp); 303 trp_release(trp); 304 } 305 306 static const struct auxiliary_device_id intel_rapl_tpmi_ids[] = { 307 {.name = "intel_vsec.tpmi-rapl" }, 308 { } 309 }; 310 311 MODULE_DEVICE_TABLE(auxiliary, intel_rapl_tpmi_ids); 312 313 static struct auxiliary_driver intel_rapl_tpmi_driver = { 314 .probe = intel_rapl_tpmi_probe, 315 .remove = intel_rapl_tpmi_remove, 316 .id_table = intel_rapl_tpmi_ids, 317 }; 318 319 module_auxiliary_driver(intel_rapl_tpmi_driver) 320 321 MODULE_IMPORT_NS(INTEL_TPMI); 322 323 MODULE_DESCRIPTION("Intel RAPL TPMI Driver"); 324 MODULE_LICENSE("GPL"); 325