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