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