mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 18:13:04 +00:00
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);
|
||||
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 */
|
||||
base = cnspci->cfg0_regs;
|
||||
break;
|
||||
default:
|
||||
else
|
||||
return NULL; /* no such device */
|
||||
}
|
||||
} else /* remote PCI bus */
|
||||
base = cnspci->cfg1_regs;
|
||||
|
||||
offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc);
|
||||
return base + offset;
|
||||
} else if (busno == 1) { /* directly connected PCIe device */
|
||||
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,
|
||||
@ -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] */
|
||||
|
Loading…
Reference in New Issue
Block a user