atheros: ar2315-pci: rework the configuration access code
authorJohn Crispin <john@openwrt.org>
Fri, 12 Sep 2014 06:53:09 +0000 (06:53 +0000)
committerJohn Crispin <john@openwrt.org>
Fri, 12 Sep 2014 06:53:09 +0000 (06:53 +0000)
Use __raw_{read,write}l accessors and use Abort interrupt to detect a
configuration space read/write errors. The second change improves errors
detection, what improves the device presence detection and helps us to
avoid following (and similar) errors:

pci 0000:00:00.2: ignoring class 0x7e0200 (doesn't match header type 02)
pci 0000:00:00.2: bridge configuration invalid ([bus 03-90]), reconfiguring
pci 0000:00:00.2: not setting up bridge for bus 0000:01

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
SVN-Revision: 42502

target/linux/atheros/patches-3.14/105-ar2315_pci.patch

index 8009da0..6623dab 100644 (file)
@@ -7,7 +7,7 @@
 +obj-$(CONFIG_ATHEROS_AR2315_PCI) += pci.o
 --- /dev/null
 +++ b/arch/mips/ar231x/pci.c
-@@ -0,0 +1,336 @@
+@@ -0,0 +1,350 @@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 +#define AR2315_MEM_SIZE    0x00ffffffUL
 +#define AR2315_IO_SIZE     0x00007fffUL
 +
++/* Arbitrary size of memory region to access the configuration space */
++#define AR2315_PCI_CFG_SIZE   0x00100000
++
 +#define AR2315_PCI_HOST_SLOT  3
 +#define AR2315_PCI_HOST_DEVID ((0xff18 << 16) | PCI_VENDOR_ID_ATHEROS)
 +
-+static unsigned long configspace;
++static void __iomem *ar2315_pci_cfg_mem;
 +
 +static int ar2315_pci_cfg_access(int devfn, int where, int size, u32 *ptr,
 +                               bool write)
 +{
 +      int func = PCI_FUNC(devfn);
 +      int dev = PCI_SLOT(devfn);
-+      u32 value = 0;
-+      int err = 0;
-+      u32 addr;
++      u32 addr = (1 << (13 + dev)) | (func << 8) | (where & ~3);
++      u32 mask = 0xffffffff >> 8 * (4 - size);
++      u32 sh = (where & 3) * 8;
++      u32 value, isr;
++
++      /* Prevent access past the remapped area */
++      if (addr >= AR2315_PCI_CFG_SIZE || dev > 18)
++              return PCIBIOS_DEVICE_NOT_FOUND;
 +
++      /* Clear pending errors */
++      ar231x_write_reg(AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
 +      /* Select Configuration access */
 +      ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, 0, AR2315_PCIMISC_CFG_SEL);
-+      mb();
 +
-+      addr = (u32)configspace + (1 << (13 + dev)) + (func << 8) + where;
-+      if (size == 1)
-+              addr ^= 0x3;
-+      else if (size == 2)
-+              addr ^= 0x2;
++      mb();   /* PCI must see space change before we begin */
++
++      value = __raw_readl(ar2315_pci_cfg_mem + addr);
++
++      isr = ar231x_read_reg(AR2315_PCI_ISR);
++      if (isr & AR2315_PCI_INT_ABORT)
++              goto exit_err;
 +
 +      if (write) {
-+              value = *ptr;
-+              if (size == 1)
-+                      err = put_dbe(value, (u8 *)addr);
-+              else if (size == 2)
-+                      err = put_dbe(value, (u16 *)addr);
-+              else if (size == 4)
-+                      err = put_dbe(value, (u32 *)addr);
++              value = (value & ~(mask << sh)) | *ptr << sh;
++              __raw_writel(value, ar2315_pci_cfg_mem + addr);
++              isr = ar231x_read_reg(AR2315_PCI_ISR);
++              if (isr & AR2315_PCI_INT_ABORT)
++                      goto exit_err;
 +      } else {
-+              if (size == 1)
-+                      err = get_dbe(value, (u8 *)addr);
-+              else if (size == 2)
-+                      err = get_dbe(value, (u16 *)addr);
-+              else if (size == 4)
-+                      err = get_dbe(value, (u32 *)addr);
-+              if (err)
-+                      *ptr = 0xffffffff;
-+              else
-+                      *ptr = value;
++              *ptr = (value >> sh) & mask;
 +      }
 +
++      goto exit;
++
++exit_err:
++      ar231x_write_reg(AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
++      if (!write)
++              *ptr = 0xffffffff;
++
++exit:
 +      /* Select Memory access */
 +      ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_CFG_SEL, 0);
 +
-+      return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++      return isr & AR2315_PCI_INT_ABORT ? PCIBIOS_DEVICE_NOT_FOUND :
++                                          PCIBIOS_SUCCESSFUL;
 +}
 +
 +static inline int ar2315_pci_local_cfg_rd(unsigned devfn, int where, u32 *val)
 +static int ar2315_pci_cfg_read(struct pci_bus *bus, unsigned int devfn,
 +                             int where, int size, u32 *value)
 +{
-+      if ((PCI_SLOT(devfn) != 0) || (PCI_FUNC(devfn) > 2))
++      if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT)
 +              return PCIBIOS_DEVICE_NOT_FOUND;
 +
 +      return ar2315_pci_cfg_access(devfn, where, size, value, 0);
 +static int ar2315_pci_cfg_write(struct pci_bus *bus, unsigned int devfn,
 +                              int where, int size, u32 value)
 +{
-+      if ((PCI_SLOT(devfn) != 0) || (PCI_FUNC(devfn) > 2))
++      if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT)
 +              return PCIBIOS_DEVICE_NOT_FOUND;
 +
 +      return ar2315_pci_cfg_access(devfn, where, size, &value, 1);
 +              return -ENODEV;
 +
 +      /* Remap PCI config space */
-+      configspace = (unsigned long)ioremap_nocache(AR2315_PCIEXT,
-+                                                   1 * 1024 * 1024);
++      ar2315_pci_cfg_mem = ioremap_nocache(AR2315_PCIEXT,
++                                           AR2315_PCI_CFG_SIZE);
++      if (!ar2315_pci_cfg_mem) {
++              pr_err("ar2315-pci: failed to remap PCI config space\n");
++              return -ENOMEM;
++      }
++
 +      ar2315_pci_controller.io_map_base =
 +                      (unsigned long)ioremap_nocache(AR2315_MEM_BASE +
 +                      AR2315_MEM_SIZE, AR2315_IO_SIZE);
 +      return 0;
 +
 +error:
-+      iounmap((void __iomem *)configspace);
++      iounmap(ar2315_pci_cfg_mem);
 +      return res;
 +}
 +