In the absence of the attached patch, my device (Linksys E3000) does not
consistently boot. Roughly 25% of the time following a power cycle (and
occasionally on reboot), it will hang just after completion of pre-init.
There is no stack trace when this occurs. I'm guessing it is occurring
when the brcm-wl module is loaded. At first I thought there may be some
extended config space access of 1 or 2 bytes (instead of always being 4
bytes), but when I added logging to detect them, none were ever encountered.
The existing code (prior to the patch) does an "ioremap_nocache" on a
subset of a memory region that I think has already been mapped, and then
un-maps that smaller region when it is finished. Could the un-mapping of
the smaller region affect adversely the mapping of the larger region?
Any thoughts on how I might go about isolating the problem further if the
un-mapping of the smaller region is not the cause?
Thanks,
Nathan
--- /dev/null 2012-04-07 22:03:23.120698218 -0700
+++ target/linux/brcm47xx/patches-3.2/240-bcma-pcie-config-access.patch
2012-03-29 23:03:47.966705769 -0700
@@ -0,0 +1,104 @@
+--- a/drivers/bcma/driver_pci_host.c
++++ b/drivers/bcma/driver_pci_host.c
+@@ -98,19 +98,19 @@ static int bcma_extpci_read_config(struc
+ if (dev == 0) {
+ /* we support only two functions on device 0 */
+ if (func > 1)
+- return -EINVAL;
++ goto out;
+
+ /* accesses to config registers with offsets >= 256
+ * requires indirect access.
+ */
+ if (off >= PCI_CONFIG_SPACE_SIZE) {
+ addr = (func << 12);
+- addr |= (off & 0x0FFF);
++ addr |= (off & 0x0FFC);
+ val = bcma_pcie_read_config(pc, addr);
+ } else {
+ addr = BCMA_CORE_PCI_PCICFG0;
+ addr |= (func << 8);
+- addr |= (off & 0xfc);
++ addr |= (off & 0xFC);
+ val = pcicore_read32(pc, addr);
+ }
+ } else {
+@@ -126,8 +126,6 @@ static int bcma_extpci_read_config(struc
+ val = 0xffffffff;
+ goto unmap;
+ }
+-
+- val = readl(mmio);
+ }
+ val >>= (8 * (off & 3));
+
+@@ -155,7 +153,7 @@ static int bcma_extpci_write_config(stru
+ const void *buf, int len)
+ {
+ int err = -EINVAL;
+- u32 addr = 0, val = 0;
++ u32 addr, val;
+ void __iomem *mmio = 0;
+ u16 chipid = pc->core->bus->chipinfo.id;
+
+@@ -163,16 +161,22 @@ static int bcma_extpci_write_config(stru
+ if (unlikely(len != 1 && len != 2 && len != 4))
+ goto out;
+ if (dev == 0) {
++ /* we support only two functions on device 0 */
++ if (func > 1)
++ goto out;
++
+ /* accesses to config registers with offsets >= 256
+ * requires indirect access.
+ */
+- if (off < PCI_CONFIG_SPACE_SIZE) {
+- addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
++ if (off >= PCI_CONFIG_SPACE_SIZE) {
++ addr = (func << 12);
++ addr |= (off & 0x0FFC);
++ val = bcma_pcie_read_config(pc, addr);
++ } else {
++ addr = BCMA_CORE_PCI_PCICFG0;
+ addr |= (func << 8);
+- addr |= (off & 0xfc);
+- mmio = ioremap_nocache(addr, sizeof(val));
+- if (!mmio)
+- goto out;
++ addr |= (off & 0xFC);
++ val = pcicore_read32(pc, addr);
+ }
+ } else {
+ addr = bcma_get_cfgspace_addr(pc, dev, func, off);
+@@ -191,12 +195,10 @@ static int bcma_extpci_write_config(stru
+
+ switch (len) {
+ case 1:
+- val = readl(mmio);
+ val &= ~(0xFF << (8 * (off & 3)));
+ val |= *((const u8 *)buf) << (8 * (off & 3));
+ break;
+ case 2:
+- val = readl(mmio);
+ val &= ~(0xFFFF << (8 * (off & 3)));
+ val |= *((const u16 *)buf) << (8 * (off & 3));
+ break;
+@@ -204,13 +206,14 @@ static int bcma_extpci_write_config(stru
+ val = *((const u32 *)buf);
+ break;
+ }
+- if (dev == 0 && !addr) {
++ if (dev == 0) {
+ /* accesses to config registers with offsets >= 256
+ * requires indirect access.
+ */
+- addr = (func << 12);
+- addr |= (off & 0x0FFF);
+- bcma_pcie_write_config(pc, addr, val);
++ if (off >= PCI_CONFIG_SPACE_SIZE)
++ bcma_pcie_write_config(pc, addr, val);
++ else
++ pcicore_write32(pc, addr, val);
+ } else {
+ writel(val, mmio);
+
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel