Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: pci-bridge-emul: Add support for PCI Bridge Subsystem Vendor ID capability

This is read-only capability in PCI config space. Put it between base PCI
capability and base PCI Express capability.

Driver just have to specify subsystem_vendor_id and subsystem_id fields in
emulated bridge structure and pci-bridge-emul takes care of correctly
compose PCI Bridge Subsystem Vendor ID capability.

Link: https://lore.kernel.org/r/20220222155030.988-4-pali@kernel.org
Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

authored by

Pali Rohár and committed by
Lorenzo Pieralisi
3767a902 c0bd4197

+51 -20
+49 -20
drivers/pci/pci-bridge-emul.c
··· 21 21 #include "pci-bridge-emul.h" 22 22 23 23 #define PCI_BRIDGE_CONF_END PCI_STD_HEADER_SIZEOF 24 + #define PCI_CAP_SSID_SIZEOF (PCI_SSVID_DEVICE_ID + 2) 25 + #define PCI_CAP_SSID_START PCI_BRIDGE_CONF_END 26 + #define PCI_CAP_SSID_END (PCI_CAP_SSID_START + PCI_CAP_SSID_SIZEOF) 24 27 #define PCI_CAP_PCIE_SIZEOF (PCI_EXP_SLTSTA2 + 2) 25 - #define PCI_CAP_PCIE_START PCI_BRIDGE_CONF_END 28 + #define PCI_CAP_PCIE_START PCI_CAP_SSID_END 26 29 #define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_CAP_PCIE_SIZEOF) 27 30 28 31 /** ··· 318 315 }, 319 316 }; 320 317 318 + static pci_bridge_emul_read_status_t 319 + pci_bridge_emul_read_ssid(struct pci_bridge_emul *bridge, int reg, u32 *value) 320 + { 321 + switch (reg) { 322 + case PCI_CAP_LIST_ID: 323 + *value = PCI_CAP_ID_SSVID | 324 + (bridge->has_pcie ? (PCI_CAP_PCIE_START << 8) : 0); 325 + return PCI_BRIDGE_EMUL_HANDLED; 326 + 327 + case PCI_SSVID_VENDOR_ID: 328 + *value = bridge->subsystem_vendor_id | 329 + (bridge->subsystem_id << 16); 330 + return PCI_BRIDGE_EMUL_HANDLED; 331 + 332 + default: 333 + return PCI_BRIDGE_EMUL_NOT_HANDLED; 334 + } 335 + } 336 + 321 337 /* 322 338 * Initialize a pci_bridge_emul structure to represent a fake PCI 323 339 * bridge configuration space. The caller needs to have initialized ··· 363 341 if (!bridge->pci_regs_behavior) 364 342 return -ENOMEM; 365 343 366 - if (bridge->has_pcie) { 344 + if (bridge->subsystem_vendor_id) 345 + bridge->conf.capabilities_pointer = PCI_CAP_SSID_START; 346 + else if (bridge->has_pcie) 367 347 bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START; 348 + else 349 + bridge->conf.capabilities_pointer = 0; 350 + 351 + if (bridge->conf.capabilities_pointer) 368 352 bridge->conf.status |= cpu_to_le16(PCI_STATUS_CAP_LIST); 353 + 354 + if (bridge->has_pcie) { 369 355 bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP; 370 356 bridge->pcie_conf.cap |= cpu_to_le16(PCI_EXP_TYPE_ROOT_PORT << 4); 371 357 bridge->pcie_cap_regs_behavior = ··· 457 427 read_op = bridge->ops->read_base; 458 428 cfgspace = (__le32 *) &bridge->conf; 459 429 behavior = bridge->pci_regs_behavior; 460 - } else if (!bridge->has_pcie) { 461 - /* PCIe space is not implemented, and no PCI capabilities */ 462 - *value = 0; 463 - return PCIBIOS_SUCCESSFUL; 464 - } else if (reg < PCI_CAP_PCIE_END) { 430 + } else if (reg >= PCI_CAP_SSID_START && reg < PCI_CAP_SSID_END && bridge->subsystem_vendor_id) { 431 + /* Emulated PCI Bridge Subsystem Vendor ID capability */ 432 + reg -= PCI_CAP_SSID_START; 433 + read_op = pci_bridge_emul_read_ssid; 434 + cfgspace = NULL; 435 + behavior = NULL; 436 + } else if (reg >= PCI_CAP_PCIE_START && reg < PCI_CAP_PCIE_END && bridge->has_pcie) { 465 437 /* Our emulated PCIe capability */ 466 438 reg -= PCI_CAP_PCIE_START; 467 439 read_op = bridge->ops->read_pcie; 468 440 cfgspace = (__le32 *) &bridge->pcie_conf; 469 441 behavior = bridge->pcie_cap_regs_behavior; 470 - } else if (reg < PCI_CFG_SPACE_SIZE) { 471 - /* Rest of PCI space not implemented */ 472 - *value = 0; 473 - return PCIBIOS_SUCCESSFUL; 474 - } else { 442 + } else if (reg >= PCI_CFG_SPACE_SIZE && bridge->has_pcie) { 475 443 /* PCIe extended capability space */ 476 444 reg -= PCI_CFG_SPACE_SIZE; 477 445 read_op = bridge->ops->read_ext; 478 446 cfgspace = NULL; 479 447 behavior = NULL; 448 + } else { 449 + /* Not implemented */ 450 + *value = 0; 451 + return PCIBIOS_SUCCESSFUL; 480 452 } 481 453 482 454 if (read_op) ··· 536 504 write_op = bridge->ops->write_base; 537 505 cfgspace = (__le32 *) &bridge->conf; 538 506 behavior = bridge->pci_regs_behavior; 539 - } else if (!bridge->has_pcie) { 540 - /* PCIe space is not implemented, and no PCI capabilities */ 541 - return PCIBIOS_SUCCESSFUL; 542 - } else if (reg < PCI_CAP_PCIE_END) { 507 + } else if (reg >= PCI_CAP_PCIE_START && reg < PCI_CAP_PCIE_END && bridge->has_pcie) { 543 508 /* Our emulated PCIe capability */ 544 509 reg -= PCI_CAP_PCIE_START; 545 510 write_op = bridge->ops->write_pcie; 546 511 cfgspace = (__le32 *) &bridge->pcie_conf; 547 512 behavior = bridge->pcie_cap_regs_behavior; 548 - } else if (reg < PCI_CFG_SPACE_SIZE) { 549 - /* Rest of PCI space not implemented */ 550 - return PCIBIOS_SUCCESSFUL; 551 - } else { 513 + } else if (reg >= PCI_CFG_SPACE_SIZE && bridge->has_pcie) { 552 514 /* PCIe extended capability space */ 553 515 reg -= PCI_CFG_SPACE_SIZE; 554 516 write_op = bridge->ops->write_ext; 555 517 cfgspace = NULL; 556 518 behavior = NULL; 519 + } else { 520 + /* Not implemented */ 521 + return PCIBIOS_SUCCESSFUL; 557 522 } 558 523 559 524 shift = (where & 0x3) * 8;
+2
drivers/pci/pci-bridge-emul.h
··· 132 132 struct pci_bridge_reg_behavior *pcie_cap_regs_behavior; 133 133 void *data; 134 134 bool has_pcie; 135 + u16 subsystem_vendor_id; 136 + u16 subsystem_id; 135 137 }; 136 138 137 139 enum {