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.
---
 .../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.14/172-bcm5301x-R8000-handle-PEX8603-switch.patch
 
b/target/linux/bcm53xx/patches-3.14/172-bcm5301x-R8000-handle-PEX8603-switch.patch
new file mode 100644
index 0000000..e321845
--- /dev/null
+++ 
b/target/linux/bcm53xx/patches-3.14/172-bcm5301x-R8000-handle-PEX8603-switch.patch
@@ -0,0 +1,225 @@
+bcm5301x - 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 <ra...@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
++
++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);
++
++      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) {
++      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
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..e321845
--- /dev/null
+++ 
b/target/linux/bcm53xx/patches-3.18/172-bcm5301x-R8000-handle-PEX8603-switch.patch
@@ -0,0 +1,225 @@
+bcm5301x - 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 <ra...@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
++
++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);
++
++      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) {
++      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@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to