1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel Platform Monitory Technology Telemetry driver 4 * 5 * Copyright (c) 2020, Intel Corporation. 6 * All Rights Reserved. 7 * 8 * Author: "David E. Box" <david.e.box@linux.intel.com> 9 */ 10 11 #include <linux/auxiliary_bus.h> 12 #include <linux/bitops.h> 13 #include <linux/cleanup.h> 14 #include <linux/err.h> 15 #include <linux/intel_pmt_features.h> 16 #include <linux/intel_vsec.h> 17 #include <linux/kernel.h> 18 #include <linux/kref.h> 19 #include <linux/module.h> 20 #include <linux/mutex.h> 21 #include <linux/overflow.h> 22 #include <linux/pci.h> 23 #include <linux/slab.h> 24 #include <linux/types.h> 25 #include <linux/uaccess.h> 26 #include <linux/xarray.h> 27 28 #include "class.h" 29 30 #define TELEM_SIZE_OFFSET 0x0 31 #define TELEM_GUID_OFFSET 0x4 32 #define TELEM_BASE_OFFSET 0x8 33 #define TELEM_ACCESS(v) ((v) & GENMASK(3, 0)) 34 #define TELEM_TYPE(v) (((v) & GENMASK(7, 4)) >> 4) 35 /* size is in bytes */ 36 #define TELEM_SIZE(v) (((v) & GENMASK(27, 12)) >> 10) 37 38 /* Used by client hardware to identify a fixed telemetry entry*/ 39 #define TELEM_CLIENT_FIXED_BLOCK_GUID 0x10000000 40 41 #define NUM_BYTES_QWORD(v) ((v) << 3) 42 #define SAMPLE_ID_OFFSET(v) ((v) << 3) 43 44 #define NUM_BYTES_DWORD(v) ((v) << 2) 45 #define SAMPLE_ID_OFFSET32(v) ((v) << 2) 46 47 /* Protects access to the xarray of telemetry endpoint handles */ 48 static DEFINE_MUTEX(ep_lock); 49 50 enum telem_type { 51 TELEM_TYPE_PUNIT = 0, 52 TELEM_TYPE_CRASHLOG, 53 TELEM_TYPE_PUNIT_FIXED, 54 }; 55 56 struct pmt_telem_priv { 57 int num_entries; 58 struct intel_pmt_entry entry[]; 59 }; 60 61 static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry, 62 struct device *dev) 63 { 64 u32 guid = readl(entry->disc_table + TELEM_GUID_OFFSET); 65 66 if (intel_pmt_is_early_client_hw(dev)) { 67 u32 type = TELEM_TYPE(readl(entry->disc_table)); 68 69 if ((type == TELEM_TYPE_PUNIT_FIXED) || 70 (guid == TELEM_CLIENT_FIXED_BLOCK_GUID)) 71 return true; 72 } 73 74 return false; 75 } 76 77 static int pmt_telem_header_decode(struct intel_pmt_entry *entry, 78 struct device *dev) 79 { 80 void __iomem *disc_table = entry->disc_table; 81 struct intel_pmt_header *header = &entry->header; 82 83 if (pmt_telem_region_overlaps(entry, dev)) 84 return 1; 85 86 header->access_type = TELEM_ACCESS(readl(disc_table)); 87 header->guid = readl(disc_table + TELEM_GUID_OFFSET); 88 header->base_offset = readl(disc_table + TELEM_BASE_OFFSET); 89 90 /* Size is measured in DWORDS, but accessor returns bytes */ 91 header->size = TELEM_SIZE(readl(disc_table)); 92 93 /* 94 * Some devices may expose non-functioning entries that are 95 * reserved for future use. They have zero size. Do not fail 96 * probe for these. Just ignore them. 97 */ 98 if (header->size == 0 || header->access_type == 0xF) 99 return 1; 100 101 return 0; 102 } 103 104 static int pmt_telem_add_endpoint(struct intel_vsec_device *ivdev, 105 struct intel_pmt_entry *entry) 106 { 107 struct telem_endpoint *ep; 108 109 /* Endpoint lifetimes are managed by kref, not devres */ 110 entry->ep = kzalloc(sizeof(*(entry->ep)), GFP_KERNEL); 111 if (!entry->ep) 112 return -ENOMEM; 113 114 ep = entry->ep; 115 ep->pcidev = ivdev->pcidev; 116 ep->header.access_type = entry->header.access_type; 117 ep->header.guid = entry->header.guid; 118 ep->header.base_offset = entry->header.base_offset; 119 ep->header.size = entry->header.size; 120 ep->base = entry->base; 121 ep->present = true; 122 ep->cb = ivdev->priv_data; 123 124 kref_init(&ep->kref); 125 126 return 0; 127 } 128 129 static DEFINE_XARRAY_ALLOC(telem_array); 130 static struct intel_pmt_namespace pmt_telem_ns = { 131 .name = "telem", 132 .xa = &telem_array, 133 .pmt_header_decode = pmt_telem_header_decode, 134 .pmt_add_endpoint = pmt_telem_add_endpoint, 135 }; 136 137 /* Called when all users unregister and the device is removed */ 138 static void pmt_telem_ep_release(struct kref *kref) 139 { 140 struct telem_endpoint *ep; 141 142 ep = container_of(kref, struct telem_endpoint, kref); 143 kfree(ep); 144 } 145 146 unsigned long pmt_telem_get_next_endpoint(unsigned long start) 147 { 148 struct intel_pmt_entry *entry; 149 unsigned long found_idx; 150 151 mutex_lock(&ep_lock); 152 xa_for_each_start(&telem_array, found_idx, entry, start) { 153 /* 154 * Return first found index after start. 155 * 0 is not valid id. 156 */ 157 if (found_idx > start) 158 break; 159 } 160 mutex_unlock(&ep_lock); 161 162 return found_idx == start ? 0 : found_idx; 163 } 164 EXPORT_SYMBOL_NS_GPL(pmt_telem_get_next_endpoint, "INTEL_PMT_TELEMETRY"); 165 166 struct telem_endpoint *pmt_telem_register_endpoint(int devid) 167 { 168 struct intel_pmt_entry *entry; 169 unsigned long index = devid; 170 171 mutex_lock(&ep_lock); 172 entry = xa_find(&telem_array, &index, index, XA_PRESENT); 173 if (!entry) { 174 mutex_unlock(&ep_lock); 175 return ERR_PTR(-ENXIO); 176 } 177 178 kref_get(&entry->ep->kref); 179 mutex_unlock(&ep_lock); 180 181 return entry->ep; 182 } 183 EXPORT_SYMBOL_NS_GPL(pmt_telem_register_endpoint, "INTEL_PMT_TELEMETRY"); 184 185 void pmt_telem_unregister_endpoint(struct telem_endpoint *ep) 186 { 187 kref_put(&ep->kref, pmt_telem_ep_release); 188 } 189 EXPORT_SYMBOL_NS_GPL(pmt_telem_unregister_endpoint, "INTEL_PMT_TELEMETRY"); 190 191 int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info) 192 { 193 struct intel_pmt_entry *entry; 194 unsigned long index = devid; 195 int err = 0; 196 197 if (!info) 198 return -EINVAL; 199 200 mutex_lock(&ep_lock); 201 entry = xa_find(&telem_array, &index, index, XA_PRESENT); 202 if (!entry) { 203 err = -ENXIO; 204 goto unlock; 205 } 206 207 info->pdev = entry->ep->pcidev; 208 info->header = entry->ep->header; 209 210 unlock: 211 mutex_unlock(&ep_lock); 212 return err; 213 214 } 215 EXPORT_SYMBOL_NS_GPL(pmt_telem_get_endpoint_info, "INTEL_PMT_TELEMETRY"); 216 217 static int pmt_copy_region(struct telemetry_region *region, 218 struct intel_pmt_entry *entry) 219 { 220 221 struct oobmsm_plat_info *plat_info; 222 223 plat_info = intel_vsec_get_mapping(entry->ep->pcidev); 224 if (IS_ERR(plat_info)) 225 return PTR_ERR(plat_info); 226 227 region->plat_info = *plat_info; 228 region->guid = entry->guid; 229 region->addr = entry->ep->base; 230 region->size = entry->size; 231 region->num_rmids = entry->num_rmids; 232 233 return 0; 234 } 235 236 static void pmt_feature_group_release(struct kref *kref) 237 { 238 struct pmt_feature_group *feature_group; 239 240 feature_group = container_of(kref, struct pmt_feature_group, kref); 241 kfree(feature_group); 242 } 243 244 struct pmt_feature_group *intel_pmt_get_regions_by_feature(enum pmt_feature_id id) 245 { 246 struct pmt_feature_group *feature_group __free(kfree) = NULL; 247 struct telemetry_region *region; 248 struct intel_pmt_entry *entry; 249 unsigned long idx; 250 int count = 0; 251 size_t size; 252 253 if (!pmt_feature_id_is_valid(id)) 254 return ERR_PTR(-EINVAL); 255 256 guard(mutex)(&ep_lock); 257 xa_for_each(&telem_array, idx, entry) { 258 if (entry->feature_flags & BIT(id)) 259 count++; 260 } 261 262 if (!count) 263 return ERR_PTR(-ENOENT); 264 265 size = struct_size(feature_group, regions, count); 266 feature_group = kzalloc(size, GFP_KERNEL); 267 if (!feature_group) 268 return ERR_PTR(-ENOMEM); 269 270 feature_group->count = count; 271 272 region = feature_group->regions; 273 xa_for_each(&telem_array, idx, entry) { 274 int ret; 275 276 if (!(entry->feature_flags & BIT(id))) 277 continue; 278 279 ret = pmt_copy_region(region, entry); 280 if (ret) 281 return ERR_PTR(ret); 282 283 region++; 284 } 285 286 kref_init(&feature_group->kref); 287 288 return no_free_ptr(feature_group); 289 } 290 EXPORT_SYMBOL(intel_pmt_get_regions_by_feature); 291 292 void intel_pmt_put_feature_group(struct pmt_feature_group *feature_group) 293 { 294 kref_put(&feature_group->kref, pmt_feature_group_release); 295 } 296 EXPORT_SYMBOL(intel_pmt_put_feature_group); 297 298 int pmt_telem_read(struct telem_endpoint *ep, u32 id, u64 *data, u32 count) 299 { 300 u32 offset, size; 301 302 if (!ep->present) 303 return -ENODEV; 304 305 offset = SAMPLE_ID_OFFSET(id); 306 size = ep->header.size; 307 308 if (offset + NUM_BYTES_QWORD(count) > size) 309 return -EINVAL; 310 311 pmt_telem_read_mmio(ep->pcidev, ep->cb, ep->header.guid, data, ep->base, offset, 312 NUM_BYTES_QWORD(count)); 313 314 return ep->present ? 0 : -EPIPE; 315 } 316 EXPORT_SYMBOL_NS_GPL(pmt_telem_read, "INTEL_PMT_TELEMETRY"); 317 318 int pmt_telem_read32(struct telem_endpoint *ep, u32 id, u32 *data, u32 count) 319 { 320 u32 offset, size; 321 322 if (!ep->present) 323 return -ENODEV; 324 325 offset = SAMPLE_ID_OFFSET32(id); 326 size = ep->header.size; 327 328 if (offset + NUM_BYTES_DWORD(count) > size) 329 return -EINVAL; 330 331 memcpy_fromio(data, ep->base + offset, NUM_BYTES_DWORD(count)); 332 333 return ep->present ? 0 : -EPIPE; 334 } 335 EXPORT_SYMBOL_NS_GPL(pmt_telem_read32, "INTEL_PMT_TELEMETRY"); 336 337 struct telem_endpoint * 338 pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev, u32 guid, u16 pos) 339 { 340 int devid = 0; 341 int inst = 0; 342 int err = 0; 343 344 while ((devid = pmt_telem_get_next_endpoint(devid))) { 345 struct telem_endpoint_info ep_info; 346 347 err = pmt_telem_get_endpoint_info(devid, &ep_info); 348 if (err) 349 return ERR_PTR(err); 350 351 if (ep_info.header.guid == guid && ep_info.pdev == pcidev) { 352 if (inst == pos) 353 return pmt_telem_register_endpoint(devid); 354 ++inst; 355 } 356 } 357 358 return ERR_PTR(-ENXIO); 359 } 360 EXPORT_SYMBOL_NS_GPL(pmt_telem_find_and_register_endpoint, "INTEL_PMT_TELEMETRY"); 361 362 static void pmt_telem_remove(struct auxiliary_device *auxdev) 363 { 364 struct pmt_telem_priv *priv = auxiliary_get_drvdata(auxdev); 365 int i; 366 367 mutex_lock(&ep_lock); 368 for (i = 0; i < priv->num_entries; i++) { 369 struct intel_pmt_entry *entry = &priv->entry[i]; 370 371 kref_put(&entry->ep->kref, pmt_telem_ep_release); 372 intel_pmt_dev_destroy(entry, &pmt_telem_ns); 373 } 374 mutex_unlock(&ep_lock); 375 }; 376 377 static int pmt_telem_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id) 378 { 379 struct intel_vsec_device *intel_vsec_dev = auxdev_to_ivdev(auxdev); 380 struct pmt_telem_priv *priv; 381 size_t size; 382 int i, ret; 383 384 size = struct_size(priv, entry, intel_vsec_dev->num_resources); 385 priv = devm_kzalloc(&auxdev->dev, size, GFP_KERNEL); 386 if (!priv) 387 return -ENOMEM; 388 389 auxiliary_set_drvdata(auxdev, priv); 390 391 for (i = 0; i < intel_vsec_dev->num_resources; i++) { 392 struct intel_pmt_entry *entry = &priv->entry[priv->num_entries]; 393 394 mutex_lock(&ep_lock); 395 ret = intel_pmt_dev_create(entry, &pmt_telem_ns, intel_vsec_dev, i); 396 mutex_unlock(&ep_lock); 397 if (ret < 0) 398 goto abort_probe; 399 if (ret) 400 continue; 401 402 priv->num_entries++; 403 404 intel_pmt_get_features(entry); 405 } 406 407 return 0; 408 abort_probe: 409 pmt_telem_remove(auxdev); 410 return ret; 411 } 412 413 static const struct auxiliary_device_id pmt_telem_id_table[] = { 414 { .name = "intel_vsec.telemetry" }, 415 {} 416 }; 417 MODULE_DEVICE_TABLE(auxiliary, pmt_telem_id_table); 418 419 static struct auxiliary_driver pmt_telem_aux_driver = { 420 .id_table = pmt_telem_id_table, 421 .remove = pmt_telem_remove, 422 .probe = pmt_telem_probe, 423 }; 424 425 static int __init pmt_telem_init(void) 426 { 427 return auxiliary_driver_register(&pmt_telem_aux_driver); 428 } 429 module_init(pmt_telem_init); 430 431 static void __exit pmt_telem_exit(void) 432 { 433 auxiliary_driver_unregister(&pmt_telem_aux_driver); 434 xa_destroy(&telem_array); 435 } 436 module_exit(pmt_telem_exit); 437 438 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); 439 MODULE_DESCRIPTION("Intel PMT Telemetry driver"); 440 MODULE_LICENSE("GPL v2"); 441 MODULE_IMPORT_NS("INTEL_PMT"); 442 MODULE_IMPORT_NS("INTEL_VSEC"); 443