Skip to content

Commit 3767a90

Browse files
paliLorenzo Pieralisi
authored andcommitted
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>
1 parent c0bd419 commit 3767a90

2 files changed

Lines changed: 51 additions & 20 deletions

File tree

drivers/pci/pci-bridge-emul.c

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@
2121
#include "pci-bridge-emul.h"
2222

2323
#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)
2427
#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
2629
#define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_CAP_PCIE_SIZEOF)
2730

2831
/**
@@ -315,6 +318,25 @@ struct pci_bridge_reg_behavior pcie_cap_regs_behavior[PCI_CAP_PCIE_SIZEOF / 4] =
315318
},
316319
};
317320

321+
static pci_bridge_emul_read_status_t
322+
pci_bridge_emul_read_ssid(struct pci_bridge_emul *bridge, int reg, u32 *value)
323+
{
324+
switch (reg) {
325+
case PCI_CAP_LIST_ID:
326+
*value = PCI_CAP_ID_SSVID |
327+
(bridge->has_pcie ? (PCI_CAP_PCIE_START << 8) : 0);
328+
return PCI_BRIDGE_EMUL_HANDLED;
329+
330+
case PCI_SSVID_VENDOR_ID:
331+
*value = bridge->subsystem_vendor_id |
332+
(bridge->subsystem_id << 16);
333+
return PCI_BRIDGE_EMUL_HANDLED;
334+
335+
default:
336+
return PCI_BRIDGE_EMUL_NOT_HANDLED;
337+
}
338+
}
339+
318340
/*
319341
* Initialize a pci_bridge_emul structure to represent a fake PCI
320342
* bridge configuration space. The caller needs to have initialized
@@ -341,9 +363,17 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
341363
if (!bridge->pci_regs_behavior)
342364
return -ENOMEM;
343365

344-
if (bridge->has_pcie) {
366+
if (bridge->subsystem_vendor_id)
367+
bridge->conf.capabilities_pointer = PCI_CAP_SSID_START;
368+
else if (bridge->has_pcie)
345369
bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START;
370+
else
371+
bridge->conf.capabilities_pointer = 0;
372+
373+
if (bridge->conf.capabilities_pointer)
346374
bridge->conf.status |= cpu_to_le16(PCI_STATUS_CAP_LIST);
375+
376+
if (bridge->has_pcie) {
347377
bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP;
348378
bridge->pcie_conf.cap |= cpu_to_le16(PCI_EXP_TYPE_ROOT_PORT << 4);
349379
bridge->pcie_cap_regs_behavior =
@@ -427,26 +457,28 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
427457
read_op = bridge->ops->read_base;
428458
cfgspace = (__le32 *) &bridge->conf;
429459
behavior = bridge->pci_regs_behavior;
430-
} else if (!bridge->has_pcie) {
431-
/* PCIe space is not implemented, and no PCI capabilities */
432-
*value = 0;
433-
return PCIBIOS_SUCCESSFUL;
434-
} else if (reg < PCI_CAP_PCIE_END) {
460+
} else if (reg >= PCI_CAP_SSID_START && reg < PCI_CAP_SSID_END && bridge->subsystem_vendor_id) {
461+
/* Emulated PCI Bridge Subsystem Vendor ID capability */
462+
reg -= PCI_CAP_SSID_START;
463+
read_op = pci_bridge_emul_read_ssid;
464+
cfgspace = NULL;
465+
behavior = NULL;
466+
} else if (reg >= PCI_CAP_PCIE_START && reg < PCI_CAP_PCIE_END && bridge->has_pcie) {
435467
/* Our emulated PCIe capability */
436468
reg -= PCI_CAP_PCIE_START;
437469
read_op = bridge->ops->read_pcie;
438470
cfgspace = (__le32 *) &bridge->pcie_conf;
439471
behavior = bridge->pcie_cap_regs_behavior;
440-
} else if (reg < PCI_CFG_SPACE_SIZE) {
441-
/* Rest of PCI space not implemented */
442-
*value = 0;
443-
return PCIBIOS_SUCCESSFUL;
444-
} else {
472+
} else if (reg >= PCI_CFG_SPACE_SIZE && bridge->has_pcie) {
445473
/* PCIe extended capability space */
446474
reg -= PCI_CFG_SPACE_SIZE;
447475
read_op = bridge->ops->read_ext;
448476
cfgspace = NULL;
449477
behavior = NULL;
478+
} else {
479+
/* Not implemented */
480+
*value = 0;
481+
return PCIBIOS_SUCCESSFUL;
450482
}
451483

452484
if (read_op)
@@ -504,24 +536,21 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
504536
write_op = bridge->ops->write_base;
505537
cfgspace = (__le32 *) &bridge->conf;
506538
behavior = bridge->pci_regs_behavior;
507-
} else if (!bridge->has_pcie) {
508-
/* PCIe space is not implemented, and no PCI capabilities */
509-
return PCIBIOS_SUCCESSFUL;
510-
} else if (reg < PCI_CAP_PCIE_END) {
539+
} else if (reg >= PCI_CAP_PCIE_START && reg < PCI_CAP_PCIE_END && bridge->has_pcie) {
511540
/* Our emulated PCIe capability */
512541
reg -= PCI_CAP_PCIE_START;
513542
write_op = bridge->ops->write_pcie;
514543
cfgspace = (__le32 *) &bridge->pcie_conf;
515544
behavior = bridge->pcie_cap_regs_behavior;
516-
} else if (reg < PCI_CFG_SPACE_SIZE) {
517-
/* Rest of PCI space not implemented */
518-
return PCIBIOS_SUCCESSFUL;
519-
} else {
545+
} else if (reg >= PCI_CFG_SPACE_SIZE && bridge->has_pcie) {
520546
/* PCIe extended capability space */
521547
reg -= PCI_CFG_SPACE_SIZE;
522548
write_op = bridge->ops->write_ext;
523549
cfgspace = NULL;
524550
behavior = NULL;
551+
} else {
552+
/* Not implemented */
553+
return PCIBIOS_SUCCESSFUL;
525554
}
526555

527556
shift = (where & 0x3) * 8;

drivers/pci/pci-bridge-emul.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ struct pci_bridge_emul {
132132
struct pci_bridge_reg_behavior *pcie_cap_regs_behavior;
133133
void *data;
134134
bool has_pcie;
135+
u16 subsystem_vendor_id;
136+
u16 subsystem_id;
135137
};
136138

137139
enum {

0 commit comments

Comments
 (0)