[OpenWrt-Devel] [PATCH 6/6] bcm53xx: R8000 handle PEX8603 switch
Ian Kent
raven at themaw.net
Mon Jun 22 19:58:55 EDT 2015
On Mon, 2015-06-22 at 18:42 +0200, Hauke Mehrtens wrote:
>
> On 03/10/2015 04:30 AM, Ian Kent wrote:
> > The Netgear R8000 has a PEX8603 connected to the BCM53012 and if
> > it isn't configured during the bus scan the PCI layer goes crazy
> > trying to configure phantom devices.
>
> Could you provide some diagram how this is connected?
I could try, when I get a chance, ascii art isn't my strong suit.
>
> My current assumption is that on one of the 3 PCIe ports is this switch,
> so the scan will find this switch as a PCIe device, bu how does it go
> from there?
I can only infer from looking at sysfs, which is what I have done.
Perhaps I'm not correct but it looks to me that there are is a BCM53012
connected with two legs, one has one wireless device, and the other has
a PEX8603 bridge which has two legs, each with a wireless device.
> From the vendor driver I would assume that that the two devices behind
> the switch are device function 0x08 and 0x10 on the switch device.
I'll have to reacquaint myself with the code before I respond to the
comments below, its been a while.
>
> Can you also post the output of lspci on your device?
Don't think I have lspci in the build I was using, I'll need to add it
and rebuild. That probably won't be until the weekend.
>
> >
> > Signed-off-by: Ian Kent <raven at themaw.net>
> > ---
> > .../172-bcm5301x-R8000-handle-PEX8603-switch.patch | 225 ++++++++++++++++++++
> > .../172-bcm5301x-R8000-handle-PEX8603-switch.patch | 225 ++++++++++++++++++++
> > 2 files changed, 450 insertions(+)
> > create mode 100644 target/linux/bcm53xx/patches-3.14/172-bcm5301x-R8000-handle-PEX8603-switch.patch
> > create mode 100644 target/linux/bcm53xx/patches-3.18/172-bcm5301x-R8000-handle-PEX8603-switch.patch
> >
>
>
> ......
>
>
> > diff --git a/target/linux/bcm53xx/patches-3.18/172-bcm5301x-R8000-handle-PEX8603-switch.patch b/target/linux/bcm53xx/patches-3.18/172-bcm5301x-R8000-handle-PEX8603-switch.patch
> > new file mode 100644
> > index 0000000..fc606b4
> > --- /dev/null
> > +++ b/target/linux/bcm53xx/patches-3.18/172-bcm5301x-R8000-handle-PEX8603-switch.patch
> > @@ -0,0 +1,225 @@
> > +bcm53xx: R8000 handle PEX8603 switch
> > +
> > +The Netgear R8000 has a PEX8603 which, if not configured at
> > +bus probe results in quite a few phantom devices as it doesn't
> > +respond properly to configuration requests. The device needs
> > +to be configured when seen.
> > +
> > +Signed-off-by: Ian Kent <raven at themaw.net>
> > +
> > +--- a/drivers/pci/host/pci-host-bcm5301x.c
> > ++++ b/drivers/pci/host/pci-host-bcm5301x.c
> > +@@ -29,6 +29,21 @@
> > + #define PCI_TARGET_LINK_SPEED_GEN2 0x2
> > + #define PCI_TARGET_LINK_SPEED_GEN1 0x1
> > +
> > ++#define PCI_MAX_BUS 4
> > ++#define PLX_PRIM_SEC_BUS_NUM (0x00000201 | (PCI_MAX_BUS << 16))
> > ++
> > ++#ifndef SZ_48M
> > ++#define SZ_48M (SZ_32M + SZ_16M)
> > ++#endif
>
> Please remove the ifndef, it should fail if this gets added.
>
>
> > ++
> > ++struct pex86xx_info {
> > ++ u8 busno; /* Upstream bus PEX is on */
> > ++ u8 slot; /* Upstream slot PEX is at */
> > ++ u16 active; /* Active port count */
> > ++ u16 ports; /* Active port bit map */
> > ++};
> > ++struct pex86xx_info pex8603;
> > ++
> > + static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
> > + {
> > + struct pci_sys_data *sys = pdev->sysdata;
> > +@@ -115,6 +130,39 @@ static int bcma_pcie2_read_config_pci(st
> > + struct pci_sys_data *sys = bus->sysdata;
> > + struct bcma_device *bdev = sys->private_data;
> > +
> > ++ /* The PEX8603 won't return sensible values to the PCI layer so
> > ++ * we have to do that ourselves.
> > ++ */
> > ++ if (pex8603.busno) {
> > ++ u16 slot = PCI_SLOT(devfn);
> > ++
> > ++ /* Not the PEX upstream slot */
> > ++ if (pex8603.busno == bus->number && pex8603.slot != slot)
> > ++ goto done;
> > ++
> > ++ /* Not the PEX downstream bus? */
> > ++ if (bus->number < pex8603.busno ||
> > ++ bus->number > pex8603.busno + 1)
> > ++ goto done;
> > ++
> > ++ switch (bus->number - pex8603.busno) {
> > ++ case 0:
> > ++ /* Upstream port */
> > ++ break;
> > ++
> > ++ case 1:
> > ++ /* PEX8603, not present for slots other than 1 or 2 */
> > ++ if (!(slot == 1 || slot == 2)) {
> > ++ *val = 0xffffffff;
> > ++ return PCIBIOS_SUCCESSFUL;
> > ++ }
> > ++ break;
> > ++
> > ++ default:
> > ++ break;
> > ++ }
> > ++ }
> > ++done:
> > + *val = bcma_pcie2_read_config(bdev, bus->number, devfn, where, size);
> > +
> > + return PCIBIOS_SUCCESSFUL;
> > +@@ -126,6 +174,37 @@ static int bcma_pcie2_write_config_pci(s
> > + struct pci_sys_data *sys = bus->sysdata;
> > + struct bcma_device *bdev = sys->private_data;
> > +
> > ++ /* Don't try and set anything on the PEX8603 if it isn't
> > ++ * valid.
> > ++ */
> > ++ if (pex8603.busno) {
> > ++ u16 slot = PCI_SLOT(devfn);
> > ++
> > ++ /* Not the PEX upstream slot */
> > ++ if (pex8603.busno == bus->number && pex8603.slot != slot)
> > ++ goto done;
> > ++
> > ++ /* Not the PEX downstream bus? */
> > ++ if (bus->number < pex8603.busno ||
> > ++ bus->number > pex8603.busno + 1)
> > ++ goto done;
> > ++
> > ++ switch (bus->number - pex8603.busno) {
> > ++ case 0:
> > ++ /* Upstream port */
> > ++ break;
> > ++
> > ++ case 1:
> > ++ /* PEX8603 slots only slots 1 and 2 present */
> > ++ if (!(slot == 1 || slot == 2))
> > ++ return PCIBIOS_SUCCESSFUL;
> > ++ break;
> > ++
> > ++ default:
> > ++ break;
> > ++ }
> > ++ }
> > ++done:
> > + bcma_pcie2_write_config(bdev, bus->number, devfn, where, size, val);
> > +
> > + return PCIBIOS_SUCCESSFUL;
> > +@@ -147,6 +226,113 @@ static void bcma_pcie2_fixup_class(struc
> > + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8011, bcma_pcie2_fixup_class);
> > + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8012, bcma_pcie2_fixup_class);
> > +
> > ++static void bcma_pcie2_pex_switch_setup(struct pci_dev *dev)
> > ++{
> > ++ struct pci_sys_data *sys = dev->sysdata;
> > ++ struct bcma_device *bdev = sys->private_data;
> > ++ unsigned char busno = dev->bus->number;
> > ++ unsigned int devfn = dev->devfn;
> > ++ unsigned int slot = PCI_SLOT(devfn);
> > ++ u32 addr = bdev->addr_s[0];
> > ++ u32 tmp32;
> > ++ u16 tmp16;
> > ++
> > ++ tmp32 = bcma_pcie2_read_config(bdev, busno, devfn, 0x100, 4);
> > ++ if (!tmp32) {
> > ++ dev_info(&bdev->dev, "failed to read PEX switch\n");
> > ++ return;
> > ++ }
> > ++
> > ++ /* Debug control register. */
> > ++ tmp32 = bcma_pcie2_read_config(bdev, busno, devfn, 0x1dc, 4);
> > ++ tmp32 &= ~(1<<22);
> > ++ bcma_pcie2_write_config(bdev, busno, devfn, 0x1dc, 4, tmp32);
> > ++
> > ++ /* Set GPIO enable. */
> > ++ tmp32 = bcma_pcie2_read_config(bdev, busno, devfn, 0x62c, 4);
> > ++ tmp32 &= ~((1 << 0) | (1 << 1) | (1 << 3));
> > ++ tmp32 |= ((1 << 4) | (1 << 5) | (1 << 7));
> > ++ bcma_pcie2_write_config(bdev, busno, devfn, 0x62c, 4, tmp32);
> > ++
> > ++ mdelay(50);
>
> You should use msleep(50) here.
>
> > ++
> > ++ tmp32 |= ((1<<0)|(1<<1));
> > ++ bcma_pcie2_write_config(bdev, busno, devfn, 0x62c, 4, tmp32);
> > ++
> > ++ /* Bus master */
> > ++ tmp16 = bcma_pcie2_read_config(bdev, busno, devfn, 0x4, 2);
> > ++ tmp16 |= 0x06;
> > ++ bcma_pcie2_write_config(bdev, busno, devfn, 0x4, 2, tmp16);
> > ++
> > ++ switch (slot) {
>
> Are you sure this is correct?
>
> Why does the vendor driver use the bus number and afterwards the device
> function for the last two spaces and you are using only the slot number?
>
> > ++ case 0:
> > ++ /* Upstream port busno and slot */
> > ++ pex8603.busno = busno;
> > ++ pex8603.slot = slot;
> > ++
> > ++ bcma_pcie2_write_config(bdev, busno,
> > ++ devfn, 0x18, 4, PLX_PRIM_SEC_BUS_NUM);
> > ++
> > ++ /* TODO: We need to scan all outgoing windows,
> > ++ * to look for a base limit pair for this register.
> > ++ */
> > ++ /* MEM_BASE, MEM_LIM require 1MB alignment */
> > ++ bcma_pcie2_write_config(bdev, busno,
> > ++ devfn, PCI_MEMORY_BASE, 2,
> > ++ addr >> 16);
> > ++ BUG_ON(((addr + SZ_32M) >> 16) & 0xf);
> > ++ bcma_pcie2_write_config(bdev, busno,
> > ++ devfn, PCI_MEMORY_LIMIT, 2,
> > ++ (addr + SZ_32M) >> 16);
> > ++ break;
> > ++
> > ++ case 1:
> > ++ bcma_pcie2_write_config(bdev, busno,
> > ++ devfn, 0x18, 4,
> > ++ (((busno + slot) << 16) |
> > ++ ((busno + slot) << 8) | busno));
> > ++ BUG_ON(((addr + SZ_48M) >> 16) & 0xf);
> > ++ bcma_pcie2_write_config(bdev, busno,
> > ++ devfn, PCI_MEMORY_BASE, 4,
> > ++ (addr + SZ_48M) >> 16);
> > ++ BUG_ON(((addr + SZ_48M + SZ_32M) >> 16) & 0xf);
> > ++ bcma_pcie2_write_config(bdev, busno,
> > ++ devfn, PCI_MEMORY_LIMIT, 4,
> > ++ (addr + SZ_48M + SZ_32M) >> 16);
> > ++
> > ++ /* Mark port bit number as active if successful */
> > ++ tmp16 = bcma_pcie2_read_config(bdev, busno, devfn, 0x7A, 2);
> > ++ if (tmp16 & PCI_EXP_LNKSTA_DLLLA) {
> > ++ pex8603.ports |= ((1 << (slot - 1)) & 0xffff);
> > ++ pex8603.active++;
> > ++ }
> > ++ break;
> > ++
> > ++ case 2:
> > ++ bcma_pcie2_write_config(bdev, busno,
> > ++ devfn, 0x18, 4,
> > ++ (((busno + slot) << 16) |
> > ++ ((busno + slot) << 8) | busno));
> > ++ BUG_ON(((addr + (SZ_48M * 2)) >> 16) & 0xf);
> > ++ bcma_pcie2_write_config(bdev, busno,
> > ++ devfn, PCI_MEMORY_BASE, 4,
> > ++ (addr + (SZ_48M * 2)) >> 16);
> > ++ BUG_ON(((addr + (SZ_48M * 2) + SZ_32M) >> 16) & 0xf);
> > ++ bcma_pcie2_write_config(bdev, busno,
> > ++ devfn, PCI_MEMORY_LIMIT, 4,
> > ++ (addr + (SZ_48M * 2) + SZ_32M) >> 16);
> > ++
> > ++ /* Mark port bit number as active if successful */
> > ++ tmp16 = bcma_pcie2_read_config(bdev, busno, devfn, 0x7A, 2);
> > ++ if (tmp16 & PCI_EXP_LNKSTA_DLLLA) {
> > ++ pex8603.ports |= ((1 << (slot - 1)) & 0xffff);
> > ++ pex8603.active++;
> > ++ }
> > ++ break;
> > ++ }
> > ++}
> > ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8603, bcma_pcie2_pex_switch_setup);
> > ++
> > + /*
> > + * Check link status, return 0 if link is up in RC mode,
> > + * otherwise return non-zero
> > _______________________________________________
> > openwrt-devel mailing list
> > openwrt-devel at lists.openwrt.org
> > https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
> >
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list