[OpenWrt-Devel] [PATCH 6/6] bcm53xx: R8000 handle PEX8603 switch

Ian Kent raven at themaw.net
Sun Aug 16 00:19:09 EDT 2015


On Tue, 2015-06-23 at 07:58 +0800, Ian Kent wrote:
> 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.

OK, I've been able get a build.

My updated patch doesn't yet function so I've used the driver we're
discussing here to get info.

TBH, looking at this, I'm not so sure the patch is wrong now.

lspci gives:
0000:00:00.0 PCI bridge: Broadcom Corporation Device 8012 (rev 01)
0000:01:00.0 Network controller: Broadcom Corporation Device aa52 (rev 01)
0001:00:00.0 PCI bridge: Broadcom Corporation Device 8012 (rev 01)
0001:01:00.0 PCI bridge: PLX Technology, Inc. Device 8603 (rev ab)
0001:02:01.0 PCI bridge: PLX Technology, Inc. Device 8603 (rev ab)
0001:02:02.0 PCI bridge: PLX Technology, Inc. Device 8603 (rev ab)
0001:03:00.0 Network controller: Broadcom Corporation Device aa52 (rev 01)
0001:04:00.0 Network controller: Broadcom Corporation Device aa52 (rev 01)

and a list of /sys/bus/pci/devices on a Vendor firmware install gives:
0000:00:00.0  0000:00:06.0  0000:00:0b.1  0000:00:11.0  0002:01:00.0
0000:00:01.0  0000:00:07.0  0000:00:0c.0  0000:00:12.0  0002:02:01.0
0000:00:02.0  0000:00:08.0  0000:00:0d.0  0000:00:13.0  0002:02:02.0
0000:00:03.0  0000:00:09.0  0000:00:0e.0  0001:00:00.0  0002:03:00.0
0000:00:04.0  0000:00:0a.0  0000:00:0f.0  0001:01:00.0  0002:04:00.0
0000:00:05.0  0000:00:0b.0  0000:00:10.0  0002:00:00.0

which looks like the topology is the same.

So, possibly, my description of how I believe the devices are connected
is accurate.

	    bcm8012
	 ------------
	 |	    |
	aa52	 pex8603
		 -------
		 |     |
		aa52  aa52

> 
> > 
> > > 
> > > 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
_______________________________________________
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