1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel Vendor Specific Extended Capabilities auxiliary bus driver 4 * 5 * Copyright (c) 2021, Intel Corporation. 6 * All Rights Reserved. 7 * 8 * Author: David E. Box <david.e.box@linux.intel.com> 9 * 10 * This driver discovers and creates auxiliary devices for Intel defined PCIe 11 * "Vendor Specific" and "Designated Vendor Specific" Extended Capabilities, 12 * VSEC and DVSEC respectively. The driver supports features on specific PCIe 13 * endpoints that exist primarily to expose them. 14 */ 15 16 #include <linux/auxiliary_bus.h> 17 #include <linux/bits.h> 18 #include <linux/cleanup.h> 19 #include <linux/delay.h> 20 #include <linux/kernel.h> 21 #include <linux/idr.h> 22 #include <linux/module.h> 23 #include <linux/pci.h> 24 #include <linux/types.h> 25 26 #include "vsec.h" 27 28 #define PMT_XA_START 0 29 #define PMT_XA_MAX INT_MAX 30 #define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX) 31 32 static DEFINE_IDA(intel_vsec_ida); 33 static DEFINE_IDA(intel_vsec_sdsi_ida); 34 static DEFINE_XARRAY_ALLOC(auxdev_array); 35 36 static const char *intel_vsec_name(enum intel_vsec_id id) 37 { 38 switch (id) { 39 case VSEC_ID_TELEMETRY: 40 return "telemetry"; 41 42 case VSEC_ID_WATCHER: 43 return "watcher"; 44 45 case VSEC_ID_CRASHLOG: 46 return "crashlog"; 47 48 case VSEC_ID_SDSI: 49 return "sdsi"; 50 51 case VSEC_ID_TPMI: 52 return "tpmi"; 53 54 default: 55 return NULL; 56 } 57 } 58 59 static bool intel_vsec_supported(u16 id, unsigned long caps) 60 { 61 switch (id) { 62 case VSEC_ID_TELEMETRY: 63 return !!(caps & VSEC_CAP_TELEMETRY); 64 case VSEC_ID_WATCHER: 65 return !!(caps & VSEC_CAP_WATCHER); 66 case VSEC_ID_CRASHLOG: 67 return !!(caps & VSEC_CAP_CRASHLOG); 68 case VSEC_ID_SDSI: 69 return !!(caps & VSEC_CAP_SDSI); 70 case VSEC_ID_TPMI: 71 return !!(caps & VSEC_CAP_TPMI); 72 default: 73 return false; 74 } 75 } 76 77 static void intel_vsec_remove_aux(void *data) 78 { 79 auxiliary_device_delete(data); 80 auxiliary_device_uninit(data); 81 } 82 83 static DEFINE_MUTEX(vsec_ida_lock); 84 85 static void intel_vsec_dev_release(struct device *dev) 86 { 87 struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev); 88 89 xa_erase(&auxdev_array, intel_vsec_dev->id); 90 91 mutex_lock(&vsec_ida_lock); 92 ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id); 93 mutex_unlock(&vsec_ida_lock); 94 95 kfree(intel_vsec_dev->resource); 96 kfree(intel_vsec_dev); 97 } 98 99 int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, 100 struct intel_vsec_device *intel_vsec_dev, 101 const char *name) 102 { 103 struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev; 104 int ret, id; 105 106 if (!parent) 107 return -EINVAL; 108 109 ret = xa_alloc(&auxdev_array, &intel_vsec_dev->id, intel_vsec_dev, 110 PMT_XA_LIMIT, GFP_KERNEL); 111 if (ret < 0) { 112 kfree(intel_vsec_dev->resource); 113 kfree(intel_vsec_dev); 114 return ret; 115 } 116 117 mutex_lock(&vsec_ida_lock); 118 id = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL); 119 mutex_unlock(&vsec_ida_lock); 120 if (id < 0) { 121 xa_erase(&auxdev_array, intel_vsec_dev->id); 122 kfree(intel_vsec_dev->resource); 123 kfree(intel_vsec_dev); 124 return id; 125 } 126 127 auxdev->id = id; 128 auxdev->name = name; 129 auxdev->dev.parent = parent; 130 auxdev->dev.release = intel_vsec_dev_release; 131 132 ret = auxiliary_device_init(auxdev); 133 if (ret < 0) { 134 intel_vsec_dev_release(&auxdev->dev); 135 return ret; 136 } 137 138 ret = auxiliary_device_add(auxdev); 139 if (ret < 0) { 140 auxiliary_device_uninit(auxdev); 141 return ret; 142 } 143 144 return devm_add_action_or_reset(parent, intel_vsec_remove_aux, 145 auxdev); 146 } 147 EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, INTEL_VSEC); 148 149 static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, 150 struct intel_vsec_platform_info *info) 151 { 152 struct intel_vsec_device __free(kfree) *intel_vsec_dev = NULL; 153 struct resource __free(kfree) *res = NULL; 154 struct resource *tmp; 155 struct device *parent; 156 unsigned long quirks = info->quirks; 157 u64 base_addr; 158 int i; 159 160 if (info->parent) 161 parent = info->parent; 162 else 163 parent = &pdev->dev; 164 165 if (!intel_vsec_supported(header->id, info->caps)) 166 return -EINVAL; 167 168 if (!header->num_entries) { 169 dev_dbg(&pdev->dev, "Invalid 0 entry count for header id %d\n", header->id); 170 return -EINVAL; 171 } 172 173 if (!header->entry_size) { 174 dev_dbg(&pdev->dev, "Invalid 0 entry size for header id %d\n", header->id); 175 return -EINVAL; 176 } 177 178 intel_vsec_dev = kzalloc(sizeof(*intel_vsec_dev), GFP_KERNEL); 179 if (!intel_vsec_dev) 180 return -ENOMEM; 181 182 res = kcalloc(header->num_entries, sizeof(*res), GFP_KERNEL); 183 if (!res) 184 return -ENOMEM; 185 186 if (quirks & VSEC_QUIRK_TABLE_SHIFT) 187 header->offset >>= TABLE_OFFSET_SHIFT; 188 189 if (info->base_addr) 190 base_addr = info->base_addr; 191 else 192 base_addr = pdev->resource[header->tbir].start; 193 194 /* 195 * The DVSEC/VSEC contains the starting offset and count for a block of 196 * discovery tables. Create a resource array of these tables to the 197 * auxiliary device driver. 198 */ 199 for (i = 0, tmp = res; i < header->num_entries; i++, tmp++) { 200 tmp->start = base_addr + header->offset + i * (header->entry_size * sizeof(u32)); 201 tmp->end = tmp->start + (header->entry_size * sizeof(u32)) - 1; 202 tmp->flags = IORESOURCE_MEM; 203 204 /* Check resource is not in use */ 205 if (!request_mem_region(tmp->start, resource_size(tmp), "")) 206 return -EBUSY; 207 208 release_mem_region(tmp->start, resource_size(tmp)); 209 } 210 211 intel_vsec_dev->pcidev = pdev; 212 intel_vsec_dev->resource = no_free_ptr(res); 213 intel_vsec_dev->num_resources = header->num_entries; 214 intel_vsec_dev->quirks = info->quirks; 215 intel_vsec_dev->base_addr = info->base_addr; 216 217 if (header->id == VSEC_ID_SDSI) 218 intel_vsec_dev->ida = &intel_vsec_sdsi_ida; 219 else 220 intel_vsec_dev->ida = &intel_vsec_ida; 221 222 /* 223 * Pass the ownership of intel_vsec_dev and resource within it to 224 * intel_vsec_add_aux() 225 */ 226 return intel_vsec_add_aux(pdev, parent, no_free_ptr(intel_vsec_dev), 227 intel_vsec_name(header->id)); 228 } 229 230 static bool intel_vsec_walk_header(struct pci_dev *pdev, 231 struct intel_vsec_platform_info *info) 232 { 233 struct intel_vsec_header **header = info->headers; 234 bool have_devices = false; 235 int ret; 236 237 for ( ; *header; header++) { 238 ret = intel_vsec_add_dev(pdev, *header, info); 239 if (ret) 240 dev_info(&pdev->dev, "Could not add device for VSEC id %d\n", 241 (*header)->id); 242 else 243 have_devices = true; 244 } 245 246 return have_devices; 247 } 248 249 static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, 250 struct intel_vsec_platform_info *info) 251 { 252 bool have_devices = false; 253 int pos = 0; 254 255 do { 256 struct intel_vsec_header header; 257 u32 table, hdr; 258 u16 vid; 259 int ret; 260 261 pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC); 262 if (!pos) 263 break; 264 265 pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER1, &hdr); 266 vid = PCI_DVSEC_HEADER1_VID(hdr); 267 if (vid != PCI_VENDOR_ID_INTEL) 268 continue; 269 270 /* Support only revision 1 */ 271 header.rev = PCI_DVSEC_HEADER1_REV(hdr); 272 if (header.rev != 1) { 273 dev_info(&pdev->dev, "Unsupported DVSEC revision %d\n", header.rev); 274 continue; 275 } 276 277 header.length = PCI_DVSEC_HEADER1_LEN(hdr); 278 279 pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES, &header.num_entries); 280 pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE, &header.entry_size); 281 pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE, &table); 282 283 header.tbir = INTEL_DVSEC_TABLE_BAR(table); 284 header.offset = INTEL_DVSEC_TABLE_OFFSET(table); 285 286 pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER2, &hdr); 287 header.id = PCI_DVSEC_HEADER2_ID(hdr); 288 289 ret = intel_vsec_add_dev(pdev, &header, info); 290 if (ret) 291 continue; 292 293 have_devices = true; 294 } while (true); 295 296 return have_devices; 297 } 298 299 static bool intel_vsec_walk_vsec(struct pci_dev *pdev, 300 struct intel_vsec_platform_info *info) 301 { 302 bool have_devices = false; 303 int pos = 0; 304 305 do { 306 struct intel_vsec_header header; 307 u32 table, hdr; 308 int ret; 309 310 pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_VNDR); 311 if (!pos) 312 break; 313 314 pci_read_config_dword(pdev, pos + PCI_VNDR_HEADER, &hdr); 315 316 /* Support only revision 1 */ 317 header.rev = PCI_VNDR_HEADER_REV(hdr); 318 if (header.rev != 1) { 319 dev_info(&pdev->dev, "Unsupported VSEC revision %d\n", header.rev); 320 continue; 321 } 322 323 header.id = PCI_VNDR_HEADER_ID(hdr); 324 header.length = PCI_VNDR_HEADER_LEN(hdr); 325 326 /* entry, size, and table offset are the same as DVSEC */ 327 pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES, &header.num_entries); 328 pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE, &header.entry_size); 329 pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE, &table); 330 331 header.tbir = INTEL_DVSEC_TABLE_BAR(table); 332 header.offset = INTEL_DVSEC_TABLE_OFFSET(table); 333 334 ret = intel_vsec_add_dev(pdev, &header, info); 335 if (ret) 336 continue; 337 338 have_devices = true; 339 } while (true); 340 341 return have_devices; 342 } 343 344 void intel_vsec_register(struct pci_dev *pdev, 345 struct intel_vsec_platform_info *info) 346 { 347 if (!pdev || !info) 348 return; 349 350 intel_vsec_walk_header(pdev, info); 351 } 352 EXPORT_SYMBOL_NS_GPL(intel_vsec_register, INTEL_VSEC); 353 354 static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 355 { 356 struct intel_vsec_platform_info *info; 357 bool have_devices = false; 358 int ret; 359 360 ret = pcim_enable_device(pdev); 361 if (ret) 362 return ret; 363 364 pci_save_state(pdev); 365 info = (struct intel_vsec_platform_info *)id->driver_data; 366 if (!info) 367 return -EINVAL; 368 369 if (intel_vsec_walk_dvsec(pdev, info)) 370 have_devices = true; 371 372 if (intel_vsec_walk_vsec(pdev, info)) 373 have_devices = true; 374 375 if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) && 376 intel_vsec_walk_header(pdev, info)) 377 have_devices = true; 378 379 if (!have_devices) 380 return -ENODEV; 381 382 return 0; 383 } 384 385 /* DG1 info */ 386 static struct intel_vsec_header dg1_header = { 387 .length = 0x10, 388 .id = 2, 389 .num_entries = 1, 390 .entry_size = 3, 391 .tbir = 0, 392 .offset = 0x466000, 393 }; 394 395 static struct intel_vsec_header *dg1_headers[] = { 396 &dg1_header, 397 NULL 398 }; 399 400 static const struct intel_vsec_platform_info dg1_info = { 401 .caps = VSEC_CAP_TELEMETRY, 402 .headers = dg1_headers, 403 .quirks = VSEC_QUIRK_NO_DVSEC | VSEC_QUIRK_EARLY_HW, 404 }; 405 406 /* MTL info */ 407 static const struct intel_vsec_platform_info mtl_info = { 408 .caps = VSEC_CAP_TELEMETRY, 409 }; 410 411 /* OOBMSM info */ 412 static const struct intel_vsec_platform_info oobmsm_info = { 413 .caps = VSEC_CAP_TELEMETRY | VSEC_CAP_SDSI | VSEC_CAP_TPMI, 414 }; 415 416 /* TGL info */ 417 static const struct intel_vsec_platform_info tgl_info = { 418 .caps = VSEC_CAP_TELEMETRY, 419 .quirks = VSEC_QUIRK_TABLE_SHIFT | VSEC_QUIRK_EARLY_HW, 420 }; 421 422 /* LNL info */ 423 static const struct intel_vsec_platform_info lnl_info = { 424 .caps = VSEC_CAP_TELEMETRY | VSEC_CAP_WATCHER, 425 }; 426 427 #define PCI_DEVICE_ID_INTEL_VSEC_ADL 0x467d 428 #define PCI_DEVICE_ID_INTEL_VSEC_DG1 0x490e 429 #define PCI_DEVICE_ID_INTEL_VSEC_MTL_M 0x7d0d 430 #define PCI_DEVICE_ID_INTEL_VSEC_MTL_S 0xad0d 431 #define PCI_DEVICE_ID_INTEL_VSEC_OOBMSM 0x09a7 432 #define PCI_DEVICE_ID_INTEL_VSEC_RPL 0xa77d 433 #define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d 434 #define PCI_DEVICE_ID_INTEL_VSEC_LNL_M 0x647d 435 static const struct pci_device_id intel_vsec_pci_ids[] = { 436 { PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) }, 437 { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, 438 { PCI_DEVICE_DATA(INTEL, VSEC_MTL_M, &mtl_info) }, 439 { PCI_DEVICE_DATA(INTEL, VSEC_MTL_S, &mtl_info) }, 440 { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &oobmsm_info) }, 441 { PCI_DEVICE_DATA(INTEL, VSEC_RPL, &tgl_info) }, 442 { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, 443 { PCI_DEVICE_DATA(INTEL, VSEC_LNL_M, &lnl_info) }, 444 { } 445 }; 446 MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids); 447 448 static pci_ers_result_t intel_vsec_pci_error_detected(struct pci_dev *pdev, 449 pci_channel_state_t state) 450 { 451 pci_ers_result_t status = PCI_ERS_RESULT_NEED_RESET; 452 453 dev_info(&pdev->dev, "PCI error detected, state %d", state); 454 455 if (state == pci_channel_io_perm_failure) 456 status = PCI_ERS_RESULT_DISCONNECT; 457 else 458 pci_disable_device(pdev); 459 460 return status; 461 } 462 463 static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev) 464 { 465 struct intel_vsec_device *intel_vsec_dev; 466 pci_ers_result_t status = PCI_ERS_RESULT_DISCONNECT; 467 const struct pci_device_id *pci_dev_id; 468 unsigned long index; 469 470 dev_info(&pdev->dev, "Resetting PCI slot\n"); 471 472 msleep(2000); 473 if (pci_enable_device(pdev)) { 474 dev_info(&pdev->dev, 475 "Failed to re-enable PCI device after reset.\n"); 476 goto out; 477 } 478 479 status = PCI_ERS_RESULT_RECOVERED; 480 481 xa_for_each(&auxdev_array, index, intel_vsec_dev) { 482 /* check if pdev doesn't match */ 483 if (pdev != intel_vsec_dev->pcidev) 484 continue; 485 devm_release_action(&pdev->dev, intel_vsec_remove_aux, 486 &intel_vsec_dev->auxdev); 487 } 488 pci_disable_device(pdev); 489 pci_restore_state(pdev); 490 pci_dev_id = pci_match_id(intel_vsec_pci_ids, pdev); 491 intel_vsec_pci_probe(pdev, pci_dev_id); 492 493 out: 494 return status; 495 } 496 497 static void intel_vsec_pci_resume(struct pci_dev *pdev) 498 { 499 dev_info(&pdev->dev, "Done resuming PCI device\n"); 500 } 501 502 static const struct pci_error_handlers intel_vsec_pci_err_handlers = { 503 .error_detected = intel_vsec_pci_error_detected, 504 .slot_reset = intel_vsec_pci_slot_reset, 505 .resume = intel_vsec_pci_resume, 506 }; 507 508 static struct pci_driver intel_vsec_pci_driver = { 509 .name = "intel_vsec", 510 .id_table = intel_vsec_pci_ids, 511 .probe = intel_vsec_pci_probe, 512 .err_handler = &intel_vsec_pci_err_handlers, 513 }; 514 module_pci_driver(intel_vsec_pci_driver); 515 516 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); 517 MODULE_DESCRIPTION("Intel Extended Capabilities auxiliary bus driver"); 518 MODULE_LICENSE("GPL v2"); 519