|
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 |
@@ -324,7 +320,7 @@ pci_bridge_emul_read_ssid(struct pci_bridge_emul *bridge, int reg, u32 *value) |
324 | 320 | switch (reg) { |
325 | 321 | case PCI_CAP_LIST_ID: |
326 | 322 | *value = PCI_CAP_ID_SSVID | |
327 | | - (bridge->has_pcie ? (PCI_CAP_PCIE_START << 8) : 0); |
| 323 | + ((bridge->pcie_start > bridge->ssid_start) ? (bridge->pcie_start << 8) : 0); |
328 | 324 | return PCI_BRIDGE_EMUL_HANDLED; |
329 | 325 |
|
330 | 326 | case PCI_SSVID_VENDOR_ID: |
@@ -365,18 +361,33 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge, |
365 | 361 | if (!bridge->pci_regs_behavior) |
366 | 362 | return -ENOMEM; |
367 | 363 |
|
368 | | - if (bridge->subsystem_vendor_id) |
369 | | - bridge->conf.capabilities_pointer = PCI_CAP_SSID_START; |
370 | | - else if (bridge->has_pcie) |
371 | | - bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START; |
372 | | - else |
373 | | - bridge->conf.capabilities_pointer = 0; |
| 364 | + /* If ssid_start and pcie_start were not specified then choose the lowest possible value. */ |
| 365 | + if (!bridge->ssid_start && !bridge->pcie_start) { |
| 366 | + if (bridge->subsystem_vendor_id) |
| 367 | + bridge->ssid_start = PCI_BRIDGE_CONF_END; |
| 368 | + if (bridge->has_pcie) |
| 369 | + bridge->pcie_start = bridge->ssid_start + PCI_CAP_SSID_SIZEOF; |
| 370 | + } else if (!bridge->ssid_start && bridge->subsystem_vendor_id) { |
| 371 | + if (bridge->pcie_start - PCI_BRIDGE_CONF_END >= PCI_CAP_SSID_SIZEOF) |
| 372 | + bridge->ssid_start = PCI_BRIDGE_CONF_END; |
| 373 | + else |
| 374 | + bridge->ssid_start = bridge->pcie_start + PCI_CAP_PCIE_SIZEOF; |
| 375 | + } else if (!bridge->pcie_start && bridge->has_pcie) { |
| 376 | + if (bridge->ssid_start - PCI_BRIDGE_CONF_END >= PCI_CAP_PCIE_SIZEOF) |
| 377 | + bridge->pcie_start = PCI_BRIDGE_CONF_END; |
| 378 | + else |
| 379 | + bridge->pcie_start = bridge->ssid_start + PCI_CAP_SSID_SIZEOF; |
| 380 | + } |
| 381 | + |
| 382 | + bridge->conf.capabilities_pointer = min(bridge->ssid_start, bridge->pcie_start); |
374 | 383 |
|
375 | 384 | if (bridge->conf.capabilities_pointer) |
376 | 385 | bridge->conf.status |= cpu_to_le16(PCI_STATUS_CAP_LIST); |
377 | 386 |
|
378 | 387 | if (bridge->has_pcie) { |
379 | 388 | bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP; |
| 389 | + bridge->pcie_conf.next = (bridge->ssid_start > bridge->pcie_start) ? |
| 390 | + bridge->ssid_start : 0; |
380 | 391 | bridge->pcie_conf.cap |= cpu_to_le16(PCI_EXP_TYPE_ROOT_PORT << 4); |
381 | 392 | bridge->pcie_cap_regs_behavior = |
382 | 393 | kmemdup(pcie_cap_regs_behavior, |
@@ -459,15 +470,17 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where, |
459 | 470 | read_op = bridge->ops->read_base; |
460 | 471 | cfgspace = (__le32 *) &bridge->conf; |
461 | 472 | behavior = bridge->pci_regs_behavior; |
462 | | - } else if (reg >= PCI_CAP_SSID_START && reg < PCI_CAP_SSID_END && bridge->subsystem_vendor_id) { |
| 473 | + } else if (reg >= bridge->ssid_start && reg < bridge->ssid_start + PCI_CAP_SSID_SIZEOF && |
| 474 | + bridge->subsystem_vendor_id) { |
463 | 475 | /* Emulated PCI Bridge Subsystem Vendor ID capability */ |
464 | | - reg -= PCI_CAP_SSID_START; |
| 476 | + reg -= bridge->ssid_start; |
465 | 477 | read_op = pci_bridge_emul_read_ssid; |
466 | 478 | cfgspace = NULL; |
467 | 479 | behavior = NULL; |
468 | | - } else if (reg >= PCI_CAP_PCIE_START && reg < PCI_CAP_PCIE_END && bridge->has_pcie) { |
| 480 | + } else if (reg >= bridge->pcie_start && reg < bridge->pcie_start + PCI_CAP_PCIE_SIZEOF && |
| 481 | + bridge->has_pcie) { |
469 | 482 | /* Our emulated PCIe capability */ |
470 | | - reg -= PCI_CAP_PCIE_START; |
| 483 | + reg -= bridge->pcie_start; |
471 | 484 | read_op = bridge->ops->read_pcie; |
472 | 485 | cfgspace = (__le32 *) &bridge->pcie_conf; |
473 | 486 | behavior = bridge->pcie_cap_regs_behavior; |
@@ -538,9 +551,10 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where, |
538 | 551 | write_op = bridge->ops->write_base; |
539 | 552 | cfgspace = (__le32 *) &bridge->conf; |
540 | 553 | behavior = bridge->pci_regs_behavior; |
541 | | - } else if (reg >= PCI_CAP_PCIE_START && reg < PCI_CAP_PCIE_END && bridge->has_pcie) { |
| 554 | + } else if (reg >= bridge->pcie_start && reg < bridge->pcie_start + PCI_CAP_PCIE_SIZEOF && |
| 555 | + bridge->has_pcie) { |
542 | 556 | /* Our emulated PCIe capability */ |
543 | | - reg -= PCI_CAP_PCIE_START; |
| 557 | + reg -= bridge->pcie_start; |
544 | 558 | write_op = bridge->ops->write_pcie; |
545 | 559 | cfgspace = (__le32 *) &bridge->pcie_conf; |
546 | 560 | behavior = bridge->pcie_cap_regs_behavior; |
|
0 commit comments