CNS3xxx: Fix logical PCIe topology.
Without this patch, each root port and the device connected directly to it seem to be located on a shared (virtual) bus #0. It creates problems with enabling devices (the PCI code doesn't know that the root bridge must be enabled in order to access other devices). The PCIe topology shown by lspci doesn't reflect reality, e.g.: 0000:00:00.0 PCI bridge: Cavium Networks Device 3400 0000:00:01.0 PCI bridge: Texas Instruments XIO2001 PCI Express-to-PCI Bridge 0000:02:... 0001:00:00.0 PCI bridge: Cavium Networks Device 3400 (for the second lane/bus) -+-[0001:00]---00.0-[01]-- \-[0000:00]-+-00.0-[01]-- | ^^^^ root bridge \-01.0-[02]----... ^^^^ first external device With this patch, the first external PCIe device is connected to bus #1 (behind the root bridge). -+-[0001:00]---00.0-[01]-- \-[0000:00]---00.0-[01-02]----------00.0-[02]----... ^^^^ root bridge ^^^^ first external device Signed-off-by: Krzysztof Hałasa <khalasa@piap.pl> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
parent
b125170a39
commit
defaa4d1dc
|
@ -60,11 +60,10 @@ static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus,
|
||||||
struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus);
|
struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus);
|
||||||
int busno = bus->number;
|
int busno = bus->number;
|
||||||
int slot = PCI_SLOT(devfn);
|
int slot = PCI_SLOT(devfn);
|
||||||
int offset;
|
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
|
||||||
/* If there is no link, just show the CNS PCI bridge. */
|
/* If there is no link, just show the CNS PCI bridge. */
|
||||||
if (!cnspci->linked && (busno > 0 || slot > 0))
|
if (!cnspci->linked && busno > 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -72,22 +71,21 @@ static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus,
|
||||||
* we still want to access it. For this to work, we must place
|
* we still want to access it. For this to work, we must place
|
||||||
* the first device on the same bus as the CNS PCI bridge.
|
* the first device on the same bus as the CNS PCI bridge.
|
||||||
*/
|
*/
|
||||||
if (busno == 0) { /* directly connected PCIe bus */
|
if (busno == 0) { /* internal PCIe bus, host bridge device */
|
||||||
switch (slot) {
|
if (devfn == 0) /* device# and function# are ignored by hw */
|
||||||
case 0: /* host bridge device, function 0 only */
|
|
||||||
base = cnspci->host_regs;
|
base = cnspci->host_regs;
|
||||||
break;
|
else
|
||||||
case 1: /* directly connected device */
|
|
||||||
base = cnspci->cfg0_regs;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return NULL; /* no such device */
|
return NULL; /* no such device */
|
||||||
}
|
|
||||||
} else /* remote PCI bus */
|
|
||||||
base = cnspci->cfg1_regs;
|
|
||||||
|
|
||||||
offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc);
|
} else if (busno == 1) { /* directly connected PCIe device */
|
||||||
return base + offset;
|
if (slot == 0) /* device# is ignored by hw */
|
||||||
|
base = cnspci->cfg0_regs;
|
||||||
|
else
|
||||||
|
return NULL; /* no such device */
|
||||||
|
} else /* remote PCI bus */
|
||||||
|
base = cnspci->cfg1_regs + ((busno & 0xf) << 20);
|
||||||
|
|
||||||
|
return base + (where & 0xffc) + (devfn << 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
|
static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
|
||||||
|
@ -167,7 +165,7 @@ static struct pci_ops cns3xxx_pcie_ops = {
|
||||||
static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||||
{
|
{
|
||||||
struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev);
|
struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev);
|
||||||
int irq = cnspci->irqs[slot];
|
int irq = cnspci->irqs[!!dev->bus->number];
|
||||||
|
|
||||||
pr_info("PCIe map irq: %04d:%02x:%02x.%02x slot %d, pin %d, irq: %d\n",
|
pr_info("PCIe map irq: %04d:%02x:%02x.%02x slot %d, pin %d, irq: %d\n",
|
||||||
pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn),
|
pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn),
|
||||||
|
@ -297,7 +295,8 @@ static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Set Device Max_Read_Request_Size to 128 byte */
|
/* Set Device Max_Read_Request_Size to 128 byte */
|
||||||
devfn = PCI_DEVFN(1, 0);
|
bus.number = 1; /* directly connected PCIe device */
|
||||||
|
devfn = PCI_DEVFN(0, 0);
|
||||||
pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP);
|
pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP);
|
||||||
pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
|
pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
|
||||||
dc &= ~(0x3 << 12); /* Clear Device Control Register [14:12] */
|
dc &= ~(0x3 << 12); /* Clear Device Control Register [14:12] */
|
||||||
|
|
Loading…
Reference in New Issue