Commit defaa4d1 authored by Krzysztof Hałasa's avatar Krzysztof Hałasa Committed by Arnd Bergmann

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: default avatarKrzysztof Hałasa <khalasa@piap.pl>
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parent b125170a
......@@ -60,11 +60,10 @@ static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus,
struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus);
int busno = bus->number;
int slot = PCI_SLOT(devfn);
int offset;
void __iomem *base;
/* 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;
/*
......@@ -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
* the first device on the same bus as the CNS PCI bridge.
*/
if (busno == 0) { /* directly connected PCIe bus */
switch (slot) {
case 0: /* host bridge device, function 0 only */
if (busno == 0) { /* internal PCIe bus, host bridge device */
if (devfn == 0) /* device# and function# are ignored by hw */
base = cnspci->host_regs;
break;
case 1: /* directly connected device */
else
return NULL; /* no such device */
} else if (busno == 1) { /* directly connected PCIe device */
if (slot == 0) /* device# is ignored by hw */
base = cnspci->cfg0_regs;
break;
default:
else
return NULL; /* no such device */
}
} else /* remote PCI bus */
base = cnspci->cfg1_regs;
base = cnspci->cfg1_regs + ((busno & 0xf) << 20);
offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc);
return base + offset;
return base + (where & 0xffc) + (devfn << 12);
}
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)
{
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",
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;
/* 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);
pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
dc &= ~(0x3 << 12); /* Clear Device Control Register [14:12] */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment