[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