@@ -35,52 +35,167 @@
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
-static int fsl_pcie_check_link(struct pci_controller *hose)
+
+int __weak fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn)
+{
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int fsl_pci_read_config(struct fsl_pci *pci, int bus, int devfn,
+ int offset, int len, u32 *val)
+{
+ u32 bus_no, reg, data;
+
+ if (pci->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
+ if (bus != pci->first_busno)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (devfn != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ if (fsl_arch_pci_exclude_device(pci, bus, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ bus_no = (bus == pci->first_busno) ? pci->self_busno : bus;
+
+ if (pci->indirect_type & INDIRECT_TYPE_EXT_REG)
+ reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+ else
+ reg = offset & 0xfc;
+
+ if (pci->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
+ iowrite32be(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
+ &pci->regs->config_addr);
+ else
+ iowrite32(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
+ &pci->regs->config_addr);
+
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ data = ioread32(&pci->regs->config_data);
+ switch (len) {
+ case 1:
+ *val = (data >> (8 * (offset & 3))) & 0xff;
+ break;
+ case 2:
+ *val = (data >> (8 * (offset & 3))) & 0xffff;
+ break;
+ default:
+ *val = data;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int fsl_pci_write_config(struct fsl_pci *pci, int bus, int devfn,
+ int offset, int len, u32 val)
+{
+ void __iomem *cfg_data;
+ u32 bus_no, reg;
+
+ if (pci->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
+ if (bus != pci->first_busno)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (devfn != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ if (fsl_arch_pci_exclude_device(pci, bus, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ bus_no = (bus == pci->first_busno) ?
+ pci->self_busno : bus;
+
+ if (pci->indirect_type & INDIRECT_TYPE_EXT_REG)
+ reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+ else
+ reg = offset & 0xfc;
+
+ if (pci->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
+ iowrite32be(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
+ &pci->regs->config_addr);
+ else
+ iowrite32(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
+ &pci->regs->config_addr);
+
+ /* suppress setting of PCI_PRIMARY_BUS */
+ if (pci->indirect_type & INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
+ if ((offset == PCI_PRIMARY_BUS) &&
+ (bus == pci->first_busno))
+ val &= 0xffffff00;
+
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ cfg_data = ((void *) &(pci->regs->config_data)) + (offset & 3);
+ switch (len) {
+ case 1:
+ iowrite8(val, cfg_data);
+ break;
+ case 2:
+ iowrite16(val, cfg_data);
+ break;
+ default:
+ iowrite32(val, cfg_data);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+bool fsl_pci_check_link(struct fsl_pci *pci)
{
u32 val = 0;
- if (hose->indirect_type & PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK) {
- if (hose->ops->read == fsl_indirect_read_config) {
- struct pci_bus bus;
- bus.number = hose->first_busno;
- bus.sysdata = hose;
- bus.ops = hose->ops;
- indirect_read_config(&bus, 0, PCIE_LTSSM, 4, &val);
- } else
- early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
+ if (pci->indirect_type & INDIRECT_TYPE_FSL_CFG_REG_LINK) {
+ fsl_pci_read_config(pci, 0, 0, PCIE_LTSSM, 4, &val);
if (val < PCIE_LTSSM_L0)
- return 1;
+ return false;
} else {
- struct ccsr_pci __iomem *pci = hose->private_data;
/* for PCIe IP rev 3.0 or greater use CSR0 for link state */
- val = (in_be32(&pci->pex_csr0) & PEX_CSR0_LTSSM_MASK)
+ val = (ioread32be(&pci->regs->pex_csr0) & PEX_CSR0_LTSSM_MASK)
>> PEX_CSR0_LTSSM_SHIFT;
if (val != PEX_CSR0_LTSSM_L0)
- return 1;
+ return false;
}
- return 0;
+ return true;
}
static int fsl_indirect_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
- struct pci_controller *hose = pci_bus_to_host(bus);
+ struct fsl_pci *pci = fsl_arch_sys_to_pci(bus->sysdata);
+
+ if (!pci)
+ return PCIBIOS_DEVICE_NOT_FOUND;
- if (fsl_pcie_check_link(hose))
- hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
+ if (fsl_pci_check_link(pci))
+ pci->indirect_type &= ~INDIRECT_TYPE_NO_PCIE_LINK;
else
- hose->indirect_type &= ~PPC_INDIRECT_TYPE_NO_PCIE_LINK;
+ pci->indirect_type |= INDIRECT_TYPE_NO_PCIE_LINK;
- return indirect_read_config(bus, devfn, offset, len, val);
+ return fsl_pci_read_config(pci, bus->number, devfn, offset, len, val);
}
-#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
-
-static struct pci_ops fsl_indirect_pcie_ops =
+static int fsl_indirect_write_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 val)
{
+ struct fsl_pci *pci = fsl_arch_sys_to_pci(bus->sysdata);
+
+ if (!pci)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return fsl_pci_write_config(pci, bus->number, devfn,
+ offset, len, val);
+}
+
+static struct pci_ops fsl_indirect_pci_ops = {
.read = fsl_indirect_read_config,
- .write = indirect_write_config,
+ .write = fsl_indirect_write_config,
};
static int setup_one_atmu(struct ccsr_pci __iomem *pci,
@@ -150,5 +150,11 @@ struct fsl_pci {
*/
extern struct fsl_pci *fsl_arch_sys_to_pci(void *sys);
+/* Return link status true -> link, false -> no link */
+bool fsl_pci_check_link(struct fsl_pci *pci);
+
+/* To avoid touching specified devices */
+int fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn);
+
#endif /* __PCI_COMMON_H */
#endif /* __KERNEL__ */
The patch adds PCI indirect read/write functions. The main code is ported from arch/powerpc/sysdev/indirect_pci.c. We use general IO API iowrite32be/ioread32be instead of out_be32/in_be32, and use structure fsl_Pci instead of PowerPC's pci_controller. The patch also provides fsl_pcie_check_link() to check PCI link. The weak function fsl_arch_pci_exclude_device() is provided to call ppc_md.pci_exclude_device() for PowerPC architecture. Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com> --- change log: v4: moved indirect type macro to header file v1-v3: Derived from http://patchwork.ozlabs.org/patch/278965/ Based on upstream master. Based on the discussion of RFC version here http://patchwork.ozlabs.org/patch/274487/ drivers/pci/host/pci-fsl-common.c | 163 ++++++++++++++++++++++++++++++++------ include/linux/fsl/pci-common.h | 6 ++ 2 files changed, 145 insertions(+), 24 deletions(-)