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

PCI: pci-bridge-emul: Set position of PCI capabilities to real HW value

mvebu and aardvark HW have PCIe capabilities on different offset in PCI
config space. Extend pci-bridge-emul.c code to allow setting custom driver
custom value where PCIe capabilities starts.

With this change PCIe capabilities of both drivers are reported at the same
location as where they are reported by U-Boot - in their real HW offset.

Link: https://lore.kernel.org/r/20220824112124.21675-1-pali@kernel.org
Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>

authored by

Pali Rohár and committed by
Lorenzo Pieralisi
658aea35 568035b0

+35 -17
+1
drivers/pci/controller/pci-aardvark.c
··· 1078 1078 bridge->pcie_conf.rootcap = cpu_to_le16(PCI_EXP_RTCAP_CRSVIS); 1079 1079 1080 1080 bridge->has_pcie = true; 1081 + bridge->pcie_start = PCIE_CORE_PCIEXP_CAP; 1081 1082 bridge->data = pcie; 1082 1083 bridge->ops = &advk_pci_bridge_emul_ops; 1083 1084
+1
drivers/pci/controller/pci-mvebu.c
··· 946 946 bridge->subsystem_vendor_id = ssdev_id & 0xffff; 947 947 bridge->subsystem_id = ssdev_id >> 16; 948 948 bridge->has_pcie = true; 949 + bridge->pcie_start = PCIE_CAP_PCIEXP; 949 950 bridge->data = port; 950 951 bridge->ops = &mvebu_pci_bridge_emul_ops; 951 952
+31 -17
drivers/pci/pci-bridge-emul.c
··· 22 22 23 23 #define PCI_BRIDGE_CONF_END PCI_STD_HEADER_SIZEOF 24 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) 27 25 #define PCI_CAP_PCIE_SIZEOF (PCI_EXP_SLTSTA2 + 2) 28 - #define PCI_CAP_PCIE_START PCI_CAP_SSID_END 29 - #define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_CAP_PCIE_SIZEOF) 30 26 31 27 /** 32 28 * struct pci_bridge_reg_behavior - register bits behaviors ··· 320 324 switch (reg) { 321 325 case PCI_CAP_LIST_ID: 322 326 *value = PCI_CAP_ID_SSVID | 323 - (bridge->has_pcie ? (PCI_CAP_PCIE_START << 8) : 0); 327 + ((bridge->pcie_start > bridge->ssid_start) ? (bridge->pcie_start << 8) : 0); 324 328 return PCI_BRIDGE_EMUL_HANDLED; 325 329 326 330 case PCI_SSVID_VENDOR_ID: ··· 361 365 if (!bridge->pci_regs_behavior) 362 366 return -ENOMEM; 363 367 364 - if (bridge->subsystem_vendor_id) 365 - bridge->conf.capabilities_pointer = PCI_CAP_SSID_START; 366 - else if (bridge->has_pcie) 367 - bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START; 368 - else 369 - bridge->conf.capabilities_pointer = 0; 368 + /* If ssid_start and pcie_start were not specified then choose the lowest possible value. */ 369 + if (!bridge->ssid_start && !bridge->pcie_start) { 370 + if (bridge->subsystem_vendor_id) 371 + bridge->ssid_start = PCI_BRIDGE_CONF_END; 372 + if (bridge->has_pcie) 373 + bridge->pcie_start = bridge->ssid_start + PCI_CAP_SSID_SIZEOF; 374 + } else if (!bridge->ssid_start && bridge->subsystem_vendor_id) { 375 + if (bridge->pcie_start - PCI_BRIDGE_CONF_END >= PCI_CAP_SSID_SIZEOF) 376 + bridge->ssid_start = PCI_BRIDGE_CONF_END; 377 + else 378 + bridge->ssid_start = bridge->pcie_start + PCI_CAP_PCIE_SIZEOF; 379 + } else if (!bridge->pcie_start && bridge->has_pcie) { 380 + if (bridge->ssid_start - PCI_BRIDGE_CONF_END >= PCI_CAP_PCIE_SIZEOF) 381 + bridge->pcie_start = PCI_BRIDGE_CONF_END; 382 + else 383 + bridge->pcie_start = bridge->ssid_start + PCI_CAP_SSID_SIZEOF; 384 + } 385 + 386 + bridge->conf.capabilities_pointer = min(bridge->ssid_start, bridge->pcie_start); 370 387 371 388 if (bridge->conf.capabilities_pointer) 372 389 bridge->conf.status |= cpu_to_le16(PCI_STATUS_CAP_LIST); 373 390 374 391 if (bridge->has_pcie) { 375 392 bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP; 393 + bridge->pcie_conf.next = (bridge->ssid_start > bridge->pcie_start) ? 394 + bridge->ssid_start : 0; 376 395 bridge->pcie_conf.cap |= cpu_to_le16(PCI_EXP_TYPE_ROOT_PORT << 4); 377 396 bridge->pcie_cap_regs_behavior = 378 397 kmemdup(pcie_cap_regs_behavior, ··· 470 459 read_op = bridge->ops->read_base; 471 460 cfgspace = (__le32 *) &bridge->conf; 472 461 behavior = bridge->pci_regs_behavior; 473 - } else if (reg >= PCI_CAP_SSID_START && reg < PCI_CAP_SSID_END && bridge->subsystem_vendor_id) { 462 + } else if (reg >= bridge->ssid_start && reg < bridge->ssid_start + PCI_CAP_SSID_SIZEOF && 463 + bridge->subsystem_vendor_id) { 474 464 /* Emulated PCI Bridge Subsystem Vendor ID capability */ 475 - reg -= PCI_CAP_SSID_START; 465 + reg -= bridge->ssid_start; 476 466 read_op = pci_bridge_emul_read_ssid; 477 467 cfgspace = NULL; 478 468 behavior = NULL; 479 - } else if (reg >= PCI_CAP_PCIE_START && reg < PCI_CAP_PCIE_END && bridge->has_pcie) { 469 + } else if (reg >= bridge->pcie_start && reg < bridge->pcie_start + PCI_CAP_PCIE_SIZEOF && 470 + bridge->has_pcie) { 480 471 /* Our emulated PCIe capability */ 481 - reg -= PCI_CAP_PCIE_START; 472 + reg -= bridge->pcie_start; 482 473 read_op = bridge->ops->read_pcie; 483 474 cfgspace = (__le32 *) &bridge->pcie_conf; 484 475 behavior = bridge->pcie_cap_regs_behavior; ··· 551 538 write_op = bridge->ops->write_base; 552 539 cfgspace = (__le32 *) &bridge->conf; 553 540 behavior = bridge->pci_regs_behavior; 554 - } else if (reg >= PCI_CAP_PCIE_START && reg < PCI_CAP_PCIE_END && bridge->has_pcie) { 541 + } else if (reg >= bridge->pcie_start && reg < bridge->pcie_start + PCI_CAP_PCIE_SIZEOF && 542 + bridge->has_pcie) { 555 543 /* Our emulated PCIe capability */ 556 - reg -= PCI_CAP_PCIE_START; 544 + reg -= bridge->pcie_start; 557 545 write_op = bridge->ops->write_pcie; 558 546 cfgspace = (__le32 *) &bridge->pcie_conf; 559 547 behavior = bridge->pcie_cap_regs_behavior;
+2
drivers/pci/pci-bridge-emul.h
··· 131 131 struct pci_bridge_reg_behavior *pci_regs_behavior; 132 132 struct pci_bridge_reg_behavior *pcie_cap_regs_behavior; 133 133 void *data; 134 + u8 pcie_start; 135 + u8 ssid_start; 134 136 bool has_pcie; 135 137 u16 subsystem_vendor_id; 136 138 u16 subsystem_id;