* [PATCH 1/2] pci: fsl: derive the common PCI driver to drivers/pci/host
From: Minghuan Lian @ 2013-09-18 11:02 UTC (permalink / raw)
To: linuxppc-dev
Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
Scott Wood
The Freescale's Layerscape series processors will use ARM cores.
The LS1's PCIe controllers is the same as T4240's. So it's better
the PCIe controller driver can support PowerPC and ARM
simultaneously. This patch is for this purpose. It derives
the common functions from arch/powerpc/sysdev/fsl_pci.c to
drivers/pci/host/pci-fsl.c and leaves the architecture-specific
functions which should be implemented in arch related files.
Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/
arch/powerpc/sysdev/fsl_pci.c | 521 +-----------------
arch/powerpc/sysdev/fsl_pci.h | 89 ----
.../sysdev/fsl_pci.c => drivers/pci/host/pci-fsl.c | 591 +--------------------
.../sysdev/fsl_pci.h => include/linux/fsl/pci.h | 45 +-
4 files changed, 7 insertions(+), 1239 deletions(-)
copy arch/powerpc/sysdev/fsl_pci.c => drivers/pci/host/pci-fsl.c (54%)
copy arch/powerpc/sysdev/fsl_pci.h => include/linux/fsl/pci.h (79%)
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index ccfb50d..a189ff0 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -27,6 +27,7 @@
#include <linux/log2.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/fsl/pci.h>
#include <asm/io.h>
#include <asm/prom.h>
@@ -58,57 +59,8 @@ static void quirk_fsl_pcie_header(struct pci_dev *dev)
return;
}
-static int fsl_indirect_read_config(struct pci_bus *, unsigned int,
- int, int, u32 *);
-
-static int fsl_pcie_check_link(struct pci_controller *hose)
-{
- 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 (val < PCIE_LTSSM_L0)
- return 1;
- } 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)
- >> PEX_CSR0_LTSSM_SHIFT;
- if (val != PEX_CSR0_LTSSM_L0)
- return 1;
- }
-
- return 0;
-}
-
-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);
-
- if (fsl_pcie_check_link(hose))
- hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
- else
- hose->indirect_type &= ~PPC_INDIRECT_TYPE_NO_PCIE_LINK;
-
- return indirect_read_config(bus, devfn, offset, len, val);
-}
-
#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
-static struct pci_ops fsl_indirect_pcie_ops =
-{
- .read = fsl_indirect_read_config,
- .write = indirect_write_config,
-};
-
#define MAX_PHYS_ADDR_BITS 40
static u64 pci64_dma_offset = 1ull << MAX_PHYS_ADDR_BITS;
@@ -132,291 +84,6 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
return 0;
}
-static int setup_one_atmu(struct ccsr_pci __iomem *pci,
- unsigned int index, const struct resource *res,
- resource_size_t offset)
-{
- resource_size_t pci_addr = res->start - offset;
- resource_size_t phys_addr = res->start;
- resource_size_t size = resource_size(res);
- u32 flags = 0x80044000; /* enable & mem R/W */
- unsigned int i;
-
- pr_debug("PCI MEM resource start 0x%016llx, size 0x%016llx.\n",
- (u64)res->start, (u64)size);
-
- if (res->flags & IORESOURCE_PREFETCH)
- flags |= 0x10000000; /* enable relaxed ordering */
-
- for (i = 0; size > 0; i++) {
- unsigned int bits = min(ilog2(size),
- __ffs(pci_addr | phys_addr));
-
- if (index + i >= 5)
- return -1;
-
- out_be32(&pci->pow[index + i].potar, pci_addr >> 12);
- out_be32(&pci->pow[index + i].potear, (u64)pci_addr >> 44);
- out_be32(&pci->pow[index + i].powbar, phys_addr >> 12);
- out_be32(&pci->pow[index + i].powar, flags | (bits - 1));
-
- pci_addr += (resource_size_t)1U << bits;
- phys_addr += (resource_size_t)1U << bits;
- size -= (resource_size_t)1U << bits;
- }
-
- return i;
-}
-
-/* atmu setup for fsl pci/pcie controller */
-static void setup_pci_atmu(struct pci_controller *hose)
-{
- struct ccsr_pci __iomem *pci = hose->private_data;
- int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4;
- u64 mem, sz, paddr_hi = 0;
- u64 offset = 0, paddr_lo = ULLONG_MAX;
- u32 pcicsrbar = 0, pcicsrbar_sz;
- u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
- PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
- const char *name = hose->dn->full_name;
- const u64 *reg;
- int len;
-
- if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
- if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) {
- win_idx = 2;
- start_idx = 0;
- end_idx = 3;
- }
- }
-
- /* Disable all windows (except powar0 since it's ignored) */
- for(i = 1; i < 5; i++)
- out_be32(&pci->pow[i].powar, 0);
- for (i = start_idx; i < end_idx; i++)
- out_be32(&pci->piw[i].piwar, 0);
-
- /* Setup outbound MEM window */
- for(i = 0, j = 1; i < 3; i++) {
- if (!(hose->mem_resources[i].flags & IORESOURCE_MEM))
- continue;
-
- paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start);
- paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end);
-
- /* We assume all memory resources have the same offset */
- offset = hose->mem_offset[i];
- n = setup_one_atmu(pci, j, &hose->mem_resources[i], offset);
-
- if (n < 0 || j >= 5) {
- pr_err("Ran out of outbound PCI ATMUs for resource %d!\n", i);
- hose->mem_resources[i].flags |= IORESOURCE_DISABLED;
- } else
- j += n;
- }
-
- /* Setup outbound IO window */
- if (hose->io_resource.flags & IORESOURCE_IO) {
- if (j >= 5) {
- pr_err("Ran out of outbound PCI ATMUs for IO resource\n");
- } else {
- pr_debug("PCI IO resource start 0x%016llx, size 0x%016llx, "
- "phy base 0x%016llx.\n",
- (u64)hose->io_resource.start,
- (u64)resource_size(&hose->io_resource),
- (u64)hose->io_base_phys);
- out_be32(&pci->pow[j].potar, (hose->io_resource.start >> 12));
- out_be32(&pci->pow[j].potear, 0);
- out_be32(&pci->pow[j].powbar, (hose->io_base_phys >> 12));
- /* Enable, IO R/W */
- out_be32(&pci->pow[j].powar, 0x80088000
- | (ilog2(hose->io_resource.end
- - hose->io_resource.start + 1) - 1));
- }
- }
-
- /* convert to pci address space */
- paddr_hi -= offset;
- paddr_lo -= offset;
-
- if (paddr_hi == paddr_lo) {
- pr_err("%s: No outbound window space\n", name);
- return;
- }
-
- if (paddr_lo == 0) {
- pr_err("%s: No space for inbound window\n", name);
- return;
- }
-
- /* setup PCSRBAR/PEXCSRBAR */
- early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff);
- early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
- pcicsrbar_sz = ~pcicsrbar_sz + 1;
-
- if (paddr_hi < (0x100000000ull - pcicsrbar_sz) ||
- (paddr_lo > 0x100000000ull))
- pcicsrbar = 0x100000000ull - pcicsrbar_sz;
- else
- pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz;
- early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar);
-
- paddr_lo = min(paddr_lo, (u64)pcicsrbar);
-
- pr_info("%s: PCICSRBAR @ 0x%x\n", name, pcicsrbar);
-
- /* Setup inbound mem window */
- mem = memblock_end_of_DRAM();
-
- /*
- * The msi-address-64 property, if it exists, indicates the physical
- * address of the MSIIR register. Normally, this register is located
- * inside CCSR, so the ATMU that covers all of CCSR is used. But if
- * this property exists, then we normally need to create a new ATMU
- * for it. For now, however, we cheat. The only entity that creates
- * this property is the Freescale hypervisor, and the address is
- * specified in the partition configuration. Typically, the address
- * is located in the page immediately after the end of DDR. If so, we
- * can avoid allocating a new ATMU by extending the DDR ATMU by one
- * page.
- */
- reg = of_get_property(hose->dn, "msi-address-64", &len);
- if (reg && (len == sizeof(u64))) {
- u64 address = be64_to_cpup(reg);
-
- if ((address >= mem) && (address < (mem + PAGE_SIZE))) {
- pr_info("%s: extending DDR ATMU to cover MSIIR", name);
- mem += PAGE_SIZE;
- } else {
- /* TODO: Create a new ATMU for MSIIR */
- pr_warn("%s: msi-address-64 address of %llx is "
- "unsupported\n", name, address);
- }
- }
-
- sz = min(mem, paddr_lo);
- mem_log = ilog2(sz);
-
- /* PCIe can overmap inbound & outbound since RX & TX are separated */
- if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
- /* Size window to exact size if power-of-two or one size up */
- if ((1ull << mem_log) != mem) {
- mem_log++;
- if ((1ull << mem_log) > mem)
- pr_info("%s: Setting PCI inbound window "
- "greater than memory size\n", name);
- }
-
- piwar |= ((mem_log - 1) & PIWAR_SZ_MASK);
-
- /* Setup inbound memory window */
- out_be32(&pci->piw[win_idx].pitar, 0x00000000);
- out_be32(&pci->piw[win_idx].piwbar, 0x00000000);
- out_be32(&pci->piw[win_idx].piwar, piwar);
- win_idx--;
-
- hose->dma_window_base_cur = 0x00000000;
- hose->dma_window_size = (resource_size_t)sz;
-
- /*
- * if we have >4G of memory setup second PCI inbound window to
- * let devices that are 64-bit address capable to work w/o
- * SWIOTLB and access the full range of memory
- */
- if (sz != mem) {
- mem_log = ilog2(mem);
-
- /* Size window up if we dont fit in exact power-of-2 */
- if ((1ull << mem_log) != mem)
- mem_log++;
-
- piwar = (piwar & ~PIWAR_SZ_MASK) | (mem_log - 1);
-
- /* Setup inbound memory window */
- out_be32(&pci->piw[win_idx].pitar, 0x00000000);
- out_be32(&pci->piw[win_idx].piwbear,
- pci64_dma_offset >> 44);
- out_be32(&pci->piw[win_idx].piwbar,
- pci64_dma_offset >> 12);
- out_be32(&pci->piw[win_idx].piwar, piwar);
-
- /*
- * install our own dma_set_mask handler to fixup dma_ops
- * and dma_offset
- */
- ppc_md.dma_set_mask = fsl_pci_dma_set_mask;
-
- pr_info("%s: Setup 64-bit PCI DMA window\n", name);
- }
- } else {
- u64 paddr = 0;
-
- /* Setup inbound memory window */
- out_be32(&pci->piw[win_idx].pitar, paddr >> 12);
- out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
- out_be32(&pci->piw[win_idx].piwar, (piwar | (mem_log - 1)));
- win_idx--;
-
- paddr += 1ull << mem_log;
- sz -= 1ull << mem_log;
-
- if (sz) {
- mem_log = ilog2(sz);
- piwar |= (mem_log - 1);
-
- out_be32(&pci->piw[win_idx].pitar, paddr >> 12);
- out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
- out_be32(&pci->piw[win_idx].piwar, piwar);
- win_idx--;
-
- paddr += 1ull << mem_log;
- }
-
- hose->dma_window_base_cur = 0x00000000;
- hose->dma_window_size = (resource_size_t)paddr;
- }
-
- if (hose->dma_window_size < mem) {
-#ifdef CONFIG_SWIOTLB
- ppc_swiotlb_enable = 1;
-#else
- pr_err("%s: ERROR: Memory size exceeds PCI ATMU ability to "
- "map - enable CONFIG_SWIOTLB to avoid dma errors.\n",
- name);
-#endif
- /* adjusting outbound windows could reclaim space in mem map */
- if (paddr_hi < 0xffffffffull)
- pr_warning("%s: WARNING: Outbound window cfg leaves "
- "gaps in memory map. Adjusting the memory map "
- "could reduce unnecessary bounce buffering.\n",
- name);
-
- pr_info("%s: DMA window size is 0x%llx\n", name,
- (u64)hose->dma_window_size);
- }
-}
-
-static void __init setup_pci_cmd(struct pci_controller *hose)
-{
- u16 cmd;
- int cap_x;
-
- early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
- | PCI_COMMAND_IO;
- early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd);
-
- cap_x = early_find_capability(hose, 0, 0, PCI_CAP_ID_PCIX);
- if (cap_x) {
- int pci_x_cmd = cap_x + PCI_X_CMD;
- cmd = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
- | PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
- early_write_config_word(hose, 0, 0, pci_x_cmd, cmd);
- } else {
- early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
- }
-}
-
void fsl_pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_controller *hose = pci_bus_to_host(bus);
@@ -454,112 +121,6 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
}
}
-int __init fsl_add_bridge(struct platform_device *pdev, int is_primary)
-{
- int len;
- struct pci_controller *hose;
- struct resource rsrc;
- const int *bus_range;
- u8 hdr_type, progif;
- struct device_node *dev;
- struct ccsr_pci __iomem *pci;
-
- dev = pdev->dev.of_node;
-
- if (!of_device_is_available(dev)) {
- pr_warning("%s: disabled\n", dev->full_name);
- return -ENODEV;
- }
-
- pr_debug("Adding PCI host bridge %s\n", dev->full_name);
-
- /* Fetch host bridge registers address */
- if (of_address_to_resource(dev, 0, &rsrc)) {
- printk(KERN_WARNING "Can't get pci register base!");
- return -ENOMEM;
- }
-
- /* Get bus range if any */
- bus_range = of_get_property(dev, "bus-range", &len);
- if (bus_range == NULL || len < 2 * sizeof(int))
- printk(KERN_WARNING "Can't get bus-range for %s, assume"
- " bus 0\n", dev->full_name);
-
- pci_add_flags(PCI_REASSIGN_ALL_BUS);
- hose = pcibios_alloc_controller(dev);
- if (!hose)
- return -ENOMEM;
-
- /* set platform device as the parent */
- hose->parent = &pdev->dev;
- hose->first_busno = bus_range ? bus_range[0] : 0x0;
- hose->last_busno = bus_range ? bus_range[1] : 0xff;
-
- pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",
- (u64)rsrc.start, (u64)resource_size(&rsrc));
-
- pci = hose->private_data = ioremap(rsrc.start, resource_size(&rsrc));
- if (!hose->private_data)
- goto no_bridge;
-
- setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4,
- PPC_INDIRECT_TYPE_BIG_ENDIAN);
-
- if (in_be32(&pci->block_rev1) < PCIE_IP_REV_3_0)
- hose->indirect_type |= PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK;
-
- if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
- /* use fsl_indirect_read_config for PCIe */
- hose->ops = &fsl_indirect_pcie_ops;
- /* For PCIE read HEADER_TYPE to identify controler mode */
- early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type);
- if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
- goto no_bridge;
-
- } else {
- /* For PCI read PROG to identify controller mode */
- early_read_config_byte(hose, 0, 0, PCI_CLASS_PROG, &progif);
- if ((progif & 1) == 1)
- goto no_bridge;
- }
-
- setup_pci_cmd(hose);
-
- /* check PCI express link status */
- if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
- hose->indirect_type |= PPC_INDIRECT_TYPE_EXT_REG |
- PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
- if (fsl_pcie_check_link(hose))
- hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
- }
-
- printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
- "Firmware bus number: %d->%d\n",
- (unsigned long long)rsrc.start, hose->first_busno,
- hose->last_busno);
-
- pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
- hose, hose->cfg_addr, hose->cfg_data);
-
- /* Interpret the "ranges" property */
- /* This also maps the I/O region and sets isa_io/mem_base */
- pci_process_bridge_OF_ranges(hose, dev, is_primary);
-
- /* Setup PEX window registers */
- setup_pci_atmu(hose);
-
- return 0;
-
-no_bridge:
- iounmap(hose->private_data);
- /* unmap cfg_data & cfg_addr separately if not on same page */
- if (((unsigned long)hose->cfg_data & PAGE_MASK) !=
- ((unsigned long)hose->cfg_addr & PAGE_MASK))
- iounmap(hose->cfg_data);
- iounmap(hose->cfg_addr);
- pcibios_free_controller(hose);
- return -ENODEV;
-}
#endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_pcie_header);
@@ -1029,26 +590,6 @@ int fsl_pci_mcheck_exception(struct pt_regs *regs)
#endif
#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
-static const struct of_device_id pci_ids[] = {
- { .compatible = "fsl,mpc8540-pci", },
- { .compatible = "fsl,mpc8548-pcie", },
- { .compatible = "fsl,mpc8610-pci", },
- { .compatible = "fsl,mpc8641-pcie", },
- { .compatible = "fsl,qoriq-pcie-v2.1", },
- { .compatible = "fsl,qoriq-pcie-v2.2", },
- { .compatible = "fsl,qoriq-pcie-v2.3", },
- { .compatible = "fsl,qoriq-pcie-v2.4", },
- { .compatible = "fsl,qoriq-pcie-v3.0", },
-
- /*
- * The following entries are for compatibility with older device
- * trees.
- */
- { .compatible = "fsl,p1022-pcie", },
- { .compatible = "fsl,p4080-pcie", },
-
- {},
-};
struct device_node *fsl_pci_primary;
@@ -1083,64 +624,4 @@ void fsl_pci_assign_primary(void)
}
}
}
-
-static int fsl_pci_probe(struct platform_device *pdev)
-{
- int ret;
- struct device_node *node;
-
- node = pdev->dev.of_node;
- ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
-
- mpc85xx_pci_err_probe(pdev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int fsl_pci_resume(struct device *dev)
-{
- struct pci_controller *hose;
- struct resource pci_rsrc;
-
- hose = pci_find_hose_for_OF_device(dev->of_node);
- if (!hose)
- return -ENODEV;
-
- if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) {
- dev_err(dev, "Get pci register base failed.");
- return -ENODEV;
- }
-
- setup_pci_atmu(hose);
-
- return 0;
-}
-
-static const struct dev_pm_ops pci_pm_ops = {
- .resume = fsl_pci_resume,
-};
-
-#define PCI_PM_OPS (&pci_pm_ops)
-
-#else
-
-#define PCI_PM_OPS NULL
-
-#endif
-
-static struct platform_driver fsl_pci_driver = {
- .driver = {
- .name = "fsl-pci",
- .pm = PCI_PM_OPS,
- .of_match_table = pci_ids,
- },
- .probe = fsl_pci_probe,
-};
-
-static int __init fsl_pci_init(void)
-{
- return platform_driver_register(&fsl_pci_driver);
-}
-arch_initcall(fsl_pci_init);
#endif
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index 8d455df..ce77aad 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -21,95 +21,6 @@ struct platform_device;
#define PCI_FSL_BRR1 0xbf8
#define PCI_FSL_BRR1_VER 0xffff
-#define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */
-#define PCIE_LTSSM_L0 0x16 /* L0 state */
-#define PCIE_IP_REV_2_2 0x02080202 /* PCIE IP block version Rev2.2 */
-#define PCIE_IP_REV_3_0 0x02080300 /* PCIE IP block version Rev3.0 */
-#define PIWAR_EN 0x80000000 /* Enable */
-#define PIWAR_PF 0x20000000 /* prefetch */
-#define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */
-#define PIWAR_READ_SNOOP 0x00050000
-#define PIWAR_WRITE_SNOOP 0x00005000
-#define PIWAR_SZ_MASK 0x0000003f
-
-/* PCI/PCI Express outbound window reg */
-struct pci_outbound_window_regs {
- __be32 potar; /* 0x.0 - Outbound translation address register */
- __be32 potear; /* 0x.4 - Outbound translation extended address register */
- __be32 powbar; /* 0x.8 - Outbound window base address register */
- u8 res1[4];
- __be32 powar; /* 0x.10 - Outbound window attributes register */
- u8 res2[12];
-};
-
-/* PCI/PCI Express inbound window reg */
-struct pci_inbound_window_regs {
- __be32 pitar; /* 0x.0 - Inbound translation address register */
- u8 res1[4];
- __be32 piwbar; /* 0x.8 - Inbound window base address register */
- __be32 piwbear; /* 0x.c - Inbound window base extended address register */
- __be32 piwar; /* 0x.10 - Inbound window attributes register */
- u8 res2[12];
-};
-
-/* PCI/PCI Express IO block registers for 85xx/86xx */
-struct ccsr_pci {
- __be32 config_addr; /* 0x.000 - PCI/PCIE Configuration Address Register */
- __be32 config_data; /* 0x.004 - PCI/PCIE Configuration Data Register */
- __be32 int_ack; /* 0x.008 - PCI Interrupt Acknowledge Register */
- __be32 pex_otb_cpl_tor; /* 0x.00c - PCIE Outbound completion timeout register */
- __be32 pex_conf_tor; /* 0x.010 - PCIE configuration timeout register */
- __be32 pex_config; /* 0x.014 - PCIE CONFIG Register */
- __be32 pex_int_status; /* 0x.018 - PCIE interrupt status */
- u8 res2[4];
- __be32 pex_pme_mes_dr; /* 0x.020 - PCIE PME and message detect register */
- __be32 pex_pme_mes_disr; /* 0x.024 - PCIE PME and message disable register */
- __be32 pex_pme_mes_ier; /* 0x.028 - PCIE PME and message interrupt enable register */
- __be32 pex_pmcr; /* 0x.02c - PCIE power management command register */
- u8 res3[3016];
- __be32 block_rev1; /* 0x.bf8 - PCIE Block Revision register 1 */
- __be32 block_rev2; /* 0x.bfc - PCIE Block Revision register 2 */
-
-/* PCI/PCI Express outbound window 0-4
- * Window 0 is the default window and is the only window enabled upon reset.
- * The default outbound register set is used when a transaction misses
- * in all of the other outbound windows.
- */
- struct pci_outbound_window_regs pow[5];
- u8 res14[96];
- struct pci_inbound_window_regs pmit; /* 0xd00 - 0xd9c Inbound MSI */
- u8 res6[96];
-/* PCI/PCI Express inbound window 3-0
- * inbound window 1 supports only a 32-bit base address and does not
- * define an inbound window base extended address register.
- */
- struct pci_inbound_window_regs piw[4];
-
- __be32 pex_err_dr; /* 0x.e00 - PCI/PCIE error detect register */
- u8 res21[4];
- __be32 pex_err_en; /* 0x.e08 - PCI/PCIE error interrupt enable register */
- u8 res22[4];
- __be32 pex_err_disr; /* 0x.e10 - PCI/PCIE error disable register */
- u8 res23[12];
- __be32 pex_err_cap_stat; /* 0x.e20 - PCI/PCIE error capture status register */
- u8 res24[4];
- __be32 pex_err_cap_r0; /* 0x.e28 - PCIE error capture register 0 */
- __be32 pex_err_cap_r1; /* 0x.e2c - PCIE error capture register 0 */
- __be32 pex_err_cap_r2; /* 0x.e30 - PCIE error capture register 0 */
- __be32 pex_err_cap_r3; /* 0x.e34 - PCIE error capture register 0 */
- u8 res_e38[200];
- __be32 pdb_stat; /* 0x.f00 - PCIE Debug Status */
- u8 res_f04[16];
- __be32 pex_csr0; /* 0x.f14 - PEX Control/Status register 0*/
-#define PEX_CSR0_LTSSM_MASK 0xFC
-#define PEX_CSR0_LTSSM_SHIFT 2
-#define PEX_CSR0_LTSSM_L0 0x11
- __be32 pex_csr1; /* 0x.f18 - PEX Control/Status register 1*/
- u8 res_f1c[228];
-
-};
-
-extern int fsl_add_bridge(struct platform_device *pdev, int is_primary);
extern void fsl_pcibios_fixup_bus(struct pci_bus *bus);
extern int mpc83xx_add_bridge(struct device_node *dev);
u64 fsl_pci_immrbar_base(struct pci_controller *hose);
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/drivers/pci/host/pci-fsl.c
similarity index 54%
copy from arch/powerpc/sysdev/fsl_pci.c
copy to drivers/pci/host/pci-fsl.c
index ccfb50d..69d338b 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/drivers/pci/host/pci-fsl.c
@@ -1,5 +1,5 @@
/*
- * MPC83xx/85xx/86xx PCI/PCIE support routing.
+ * 85xx/86xx/LS PCI/PCIE support routing.
*
* Copyright 2007-2012 Freescale Semiconductor, Inc.
* Copyright 2008-2009 MontaVista Software, Inc.
@@ -8,9 +8,6 @@
* Recode: ZHANG WEI <wei.zhang@freescale.com>
* Rewrite the routing for Frescale PCI and PCI Express
* Roy Zang <tie-fei.zang@freescale.com>
- * MPC83xx PCI-Express support:
- * Tony Li <tony.li@freescale.com>
- * Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -38,29 +35,6 @@
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
-static int fsl_pcie_bus_fixup, is_mpc83xx_pci;
-
-static void quirk_fsl_pcie_header(struct pci_dev *dev)
-{
- u8 hdr_type;
-
- /* if we aren't a PCIe don't bother */
- if (!pci_find_capability(dev, PCI_CAP_ID_EXP))
- return;
-
- /* if we aren't in host mode don't bother */
- pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);
- if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
- return;
-
- dev->class = PCI_CLASS_BRIDGE_PCI << 8;
- fsl_pcie_bus_fixup = 1;
- return;
-}
-
-static int fsl_indirect_read_config(struct pci_bus *, unsigned int,
- int, int, u32 *);
-
static int fsl_pcie_check_link(struct pci_controller *hose)
{
u32 val = 0;
@@ -109,29 +83,6 @@ static struct pci_ops fsl_indirect_pcie_ops =
.write = indirect_write_config,
};
-#define MAX_PHYS_ADDR_BITS 40
-static u64 pci64_dma_offset = 1ull << MAX_PHYS_ADDR_BITS;
-
-static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
-{
- if (!dev->dma_mask || !dma_supported(dev, dma_mask))
- return -EIO;
-
- /*
- * Fixup PCI devices that are able to DMA to above the physical
- * address width of the SoC such that we can address any internal
- * SoC address from across PCI if needed
- */
- if ((dev->bus == &pci_bus_type) &&
- dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) {
- set_dma_ops(dev, &dma_direct_ops);
- set_dma_offset(dev, pci64_dma_offset);
- }
-
- *dev->dma_mask = dma_mask;
- return 0;
-}
-
static int setup_one_atmu(struct ccsr_pci __iomem *pci,
unsigned int index, const struct resource *res,
resource_size_t offset)
@@ -417,43 +368,6 @@ static void __init setup_pci_cmd(struct pci_controller *hose)
}
}
-void fsl_pcibios_fixup_bus(struct pci_bus *bus)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
- int i, is_pcie = 0, no_link;
-
- /* The root complex bridge comes up with bogus resources,
- * we copy the PHB ones in.
- *
- * With the current generic PCI code, the PHB bus no longer
- * has bus->resource[0..4] set, so things are a bit more
- * tricky.
- */
-
- if (fsl_pcie_bus_fixup)
- is_pcie = early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);
- no_link = !!(hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK);
-
- if (bus->parent == hose->bus && (is_pcie || no_link)) {
- for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; ++i) {
- struct resource *res = bus->resource[i];
- struct resource *par;
-
- if (!res)
- continue;
- if (i == 0)
- par = &hose->io_resource;
- else if (i < 4)
- par = &hose->mem_resources[i-1];
- else par = NULL;
-
- res->start = par ? par->start : 0;
- res->end = par ? par->end : 0;
- res->flags = par ? par->flags : 0;
- }
- }
-}
-
int __init fsl_add_bridge(struct platform_device *pdev, int is_primary)
{
int len;
@@ -560,475 +474,7 @@ no_bridge:
pcibios_free_controller(hose);
return -ENODEV;
}
-#endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_pcie_header);
-
-#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x)
-struct mpc83xx_pcie_priv {
- void __iomem *cfg_type0;
- void __iomem *cfg_type1;
- u32 dev_base;
-};
-
-struct pex_inbound_window {
- u32 ar;
- u32 tar;
- u32 barl;
- u32 barh;
-};
-
-/*
- * With the convention of u-boot, the PCIE outbound window 0 serves
- * as configuration transactions outbound.
- */
-#define PEX_OUTWIN0_BAR 0xCA4
-#define PEX_OUTWIN0_TAL 0xCA8
-#define PEX_OUTWIN0_TAH 0xCAC
-#define PEX_RC_INWIN_BASE 0xE60
-#define PEX_RCIWARn_EN 0x1
-
-static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
-
- if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK)
- return PCIBIOS_DEVICE_NOT_FOUND;
- /*
- * Workaround for the HW bug: for Type 0 configure transactions the
- * PCI-E controller does not check the device number bits and just
- * assumes that the device number bits are 0.
- */
- if (bus->number == hose->first_busno ||
- bus->primary == hose->first_busno) {
- if (devfn & 0xf8)
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- if (ppc_md.pci_exclude_device) {
- if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static void __iomem *mpc83xx_pcie_remap_cfg(struct pci_bus *bus,
- unsigned int devfn, int offset)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
- struct mpc83xx_pcie_priv *pcie = hose->dn->data;
- u32 dev_base = bus->number << 24 | devfn << 16;
- int ret;
-
- ret = mpc83xx_pcie_exclude_device(bus, devfn);
- if (ret)
- return NULL;
-
- offset &= 0xfff;
-
- /* Type 0 */
- if (bus->number == hose->first_busno)
- return pcie->cfg_type0 + offset;
-
- if (pcie->dev_base == dev_base)
- goto mapped;
-
- out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, dev_base);
-
- pcie->dev_base = dev_base;
-mapped:
- return pcie->cfg_type1 + offset;
-}
-
-static int mpc83xx_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
- int offset, int len, u32 *val)
-{
- void __iomem *cfg_addr;
-
- cfg_addr = mpc83xx_pcie_remap_cfg(bus, devfn, offset);
- if (!cfg_addr)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- switch (len) {
- case 1:
- *val = in_8(cfg_addr);
- break;
- case 2:
- *val = in_le16(cfg_addr);
- break;
- default:
- *val = in_le32(cfg_addr);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int mpc83xx_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
- int offset, int len, u32 val)
-{
- struct pci_controller *hose = pci_bus_to_host(bus);
- void __iomem *cfg_addr;
-
- cfg_addr = mpc83xx_pcie_remap_cfg(bus, devfn, offset);
- if (!cfg_addr)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- /* PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS */
- if (offset == PCI_PRIMARY_BUS && bus->number == hose->first_busno)
- val &= 0xffffff00;
-
- switch (len) {
- case 1:
- out_8(cfg_addr, val);
- break;
- case 2:
- out_le16(cfg_addr, val);
- break;
- default:
- out_le32(cfg_addr, val);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops mpc83xx_pcie_ops = {
- .read = mpc83xx_pcie_read_config,
- .write = mpc83xx_pcie_write_config,
-};
-
-static int __init mpc83xx_pcie_setup(struct pci_controller *hose,
- struct resource *reg)
-{
- struct mpc83xx_pcie_priv *pcie;
- u32 cfg_bar;
- int ret = -ENOMEM;
-
- pcie = zalloc_maybe_bootmem(sizeof(*pcie), GFP_KERNEL);
- if (!pcie)
- return ret;
-
- pcie->cfg_type0 = ioremap(reg->start, resource_size(reg));
- if (!pcie->cfg_type0)
- goto err0;
-
- cfg_bar = in_le32(pcie->cfg_type0 + PEX_OUTWIN0_BAR);
- if (!cfg_bar) {
- /* PCI-E isn't configured. */
- ret = -ENODEV;
- goto err1;
- }
-
- pcie->cfg_type1 = ioremap(cfg_bar, 0x1000);
- if (!pcie->cfg_type1)
- goto err1;
-
- WARN_ON(hose->dn->data);
- hose->dn->data = pcie;
- hose->ops = &mpc83xx_pcie_ops;
- hose->indirect_type |= PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK;
-
- out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAH, 0);
- out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, 0);
-
- if (fsl_pcie_check_link(hose))
- hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
-
- return 0;
-err1:
- iounmap(pcie->cfg_type0);
-err0:
- kfree(pcie);
- return ret;
-
-}
-
-int __init mpc83xx_add_bridge(struct device_node *dev)
-{
- int ret;
- int len;
- struct pci_controller *hose;
- struct resource rsrc_reg;
- struct resource rsrc_cfg;
- const int *bus_range;
- int primary;
-
- is_mpc83xx_pci = 1;
-
- if (!of_device_is_available(dev)) {
- pr_warning("%s: disabled by the firmware.\n",
- dev->full_name);
- return -ENODEV;
- }
- pr_debug("Adding PCI host bridge %s\n", dev->full_name);
-
- /* Fetch host bridge registers address */
- if (of_address_to_resource(dev, 0, &rsrc_reg)) {
- printk(KERN_WARNING "Can't get pci register base!\n");
- return -ENOMEM;
- }
-
- memset(&rsrc_cfg, 0, sizeof(rsrc_cfg));
-
- if (of_address_to_resource(dev, 1, &rsrc_cfg)) {
- printk(KERN_WARNING
- "No pci config register base in dev tree, "
- "using default\n");
- /*
- * MPC83xx supports up to two host controllers
- * one at 0x8500 has config space registers at 0x8300
- * one at 0x8600 has config space registers at 0x8380
- */
- if ((rsrc_reg.start & 0xfffff) == 0x8500)
- rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8300;
- else if ((rsrc_reg.start & 0xfffff) == 0x8600)
- rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8380;
- }
- /*
- * Controller at offset 0x8500 is primary
- */
- if ((rsrc_reg.start & 0xfffff) == 0x8500)
- primary = 1;
- else
- primary = 0;
-
- /* Get bus range if any */
- bus_range = of_get_property(dev, "bus-range", &len);
- if (bus_range == NULL || len < 2 * sizeof(int)) {
- printk(KERN_WARNING "Can't get bus-range for %s, assume"
- " bus 0\n", dev->full_name);
- }
-
- pci_add_flags(PCI_REASSIGN_ALL_BUS);
- hose = pcibios_alloc_controller(dev);
- if (!hose)
- return -ENOMEM;
-
- hose->first_busno = bus_range ? bus_range[0] : 0;
- hose->last_busno = bus_range ? bus_range[1] : 0xff;
-
- if (of_device_is_compatible(dev, "fsl,mpc8314-pcie")) {
- ret = mpc83xx_pcie_setup(hose, &rsrc_reg);
- if (ret)
- goto err0;
- } else {
- setup_indirect_pci(hose, rsrc_cfg.start,
- rsrc_cfg.start + 4, 0);
- }
-
- printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
- "Firmware bus number: %d->%d\n",
- (unsigned long long)rsrc_reg.start, hose->first_busno,
- hose->last_busno);
-
- pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
- hose, hose->cfg_addr, hose->cfg_data);
-
- /* Interpret the "ranges" property */
- /* This also maps the I/O region and sets isa_io/mem_base */
- pci_process_bridge_OF_ranges(hose, dev, primary);
-
- return 0;
-err0:
- pcibios_free_controller(hose);
- return ret;
-}
-#endif /* CONFIG_PPC_83xx */
-
-u64 fsl_pci_immrbar_base(struct pci_controller *hose)
-{
-#ifdef CONFIG_PPC_83xx
- if (is_mpc83xx_pci) {
- struct mpc83xx_pcie_priv *pcie = hose->dn->data;
- struct pex_inbound_window *in;
- int i;
-
- /* Walk the Root Complex Inbound windows to match IMMR base */
- in = pcie->cfg_type0 + PEX_RC_INWIN_BASE;
- for (i = 0; i < 4; i++) {
- /* not enabled, skip */
- if (!in_le32(&in[i].ar) & PEX_RCIWARn_EN)
- continue;
-
- if (get_immrbase() == in_le32(&in[i].tar))
- return (u64)in_le32(&in[i].barh) << 32 |
- in_le32(&in[i].barl);
- }
-
- printk(KERN_WARNING "could not find PCI BAR matching IMMR\n");
- }
-#endif
-
-#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
- if (!is_mpc83xx_pci) {
- u32 base;
-
- pci_bus_read_config_dword(hose->bus,
- PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base);
- return base;
- }
-#endif
-
- return 0;
-}
-#ifdef CONFIG_E500
-static int mcheck_handle_load(struct pt_regs *regs, u32 inst)
-{
- unsigned int rd, ra, rb, d;
-
- rd = get_rt(inst);
- ra = get_ra(inst);
- rb = get_rb(inst);
- d = get_d(inst);
-
- switch (get_op(inst)) {
- case 31:
- switch (get_xop(inst)) {
- case OP_31_XOP_LWZX:
- case OP_31_XOP_LWBRX:
- regs->gpr[rd] = 0xffffffff;
- break;
-
- case OP_31_XOP_LWZUX:
- regs->gpr[rd] = 0xffffffff;
- regs->gpr[ra] += regs->gpr[rb];
- break;
-
- case OP_31_XOP_LBZX:
- regs->gpr[rd] = 0xff;
- break;
-
- case OP_31_XOP_LBZUX:
- regs->gpr[rd] = 0xff;
- regs->gpr[ra] += regs->gpr[rb];
- break;
-
- case OP_31_XOP_LHZX:
- case OP_31_XOP_LHBRX:
- regs->gpr[rd] = 0xffff;
- break;
-
- case OP_31_XOP_LHZUX:
- regs->gpr[rd] = 0xffff;
- regs->gpr[ra] += regs->gpr[rb];
- break;
-
- case OP_31_XOP_LHAX:
- regs->gpr[rd] = ~0UL;
- break;
-
- case OP_31_XOP_LHAUX:
- regs->gpr[rd] = ~0UL;
- regs->gpr[ra] += regs->gpr[rb];
- break;
-
- default:
- return 0;
- }
- break;
-
- case OP_LWZ:
- regs->gpr[rd] = 0xffffffff;
- break;
-
- case OP_LWZU:
- regs->gpr[rd] = 0xffffffff;
- regs->gpr[ra] += (s16)d;
- break;
-
- case OP_LBZ:
- regs->gpr[rd] = 0xff;
- break;
-
- case OP_LBZU:
- regs->gpr[rd] = 0xff;
- regs->gpr[ra] += (s16)d;
- break;
-
- case OP_LHZ:
- regs->gpr[rd] = 0xffff;
- break;
-
- case OP_LHZU:
- regs->gpr[rd] = 0xffff;
- regs->gpr[ra] += (s16)d;
- break;
-
- case OP_LHA:
- regs->gpr[rd] = ~0UL;
- break;
-
- case OP_LHAU:
- regs->gpr[rd] = ~0UL;
- regs->gpr[ra] += (s16)d;
- break;
-
- default:
- return 0;
- }
-
- return 1;
-}
-
-static int is_in_pci_mem_space(phys_addr_t addr)
-{
- struct pci_controller *hose;
- struct resource *res;
- int i;
-
- list_for_each_entry(hose, &hose_list, list_node) {
- if (!(hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG))
- continue;
-
- for (i = 0; i < 3; i++) {
- res = &hose->mem_resources[i];
- if ((res->flags & IORESOURCE_MEM) &&
- addr >= res->start && addr <= res->end)
- return 1;
- }
- }
- return 0;
-}
-
-int fsl_pci_mcheck_exception(struct pt_regs *regs)
-{
- u32 inst;
- int ret;
- phys_addr_t addr = 0;
-
- /* Let KVM/QEMU deal with the exception */
- if (regs->msr & MSR_GS)
- return 0;
-
-#ifdef CONFIG_PHYS_64BIT
- addr = mfspr(SPRN_MCARU);
- addr <<= 32;
-#endif
- addr += mfspr(SPRN_MCAR);
-
- if (is_in_pci_mem_space(addr)) {
- if (user_mode(regs)) {
- pagefault_disable();
- ret = get_user(regs->nip, &inst);
- pagefault_enable();
- } else {
- ret = probe_kernel_address(regs->nip, inst);
- }
-
- if (mcheck_handle_load(regs, inst)) {
- regs->nip += 4;
- return 1;
- }
- }
-
- return 0;
-}
-#endif
-
-#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
static const struct of_device_id pci_ids[] = {
{ .compatible = "fsl,mpc8540-pci", },
{ .compatible = "fsl,mpc8548-pcie", },
@@ -1050,40 +496,6 @@ static const struct of_device_id pci_ids[] = {
{},
};
-struct device_node *fsl_pci_primary;
-
-void fsl_pci_assign_primary(void)
-{
- struct device_node *np;
-
- /* Callers can specify the primary bus using other means. */
- if (fsl_pci_primary)
- return;
-
- /* If a PCI host bridge contains an ISA node, it's primary. */
- np = of_find_node_by_type(NULL, "isa");
- while ((fsl_pci_primary = of_get_parent(np))) {
- of_node_put(np);
- np = fsl_pci_primary;
-
- if (of_match_node(pci_ids, np) && of_device_is_available(np))
- return;
- }
-
- /*
- * If there's no PCI host bridge with ISA, arbitrarily
- * designate one as primary. This can go away once
- * various bugs with primary-less systems are fixed.
- */
- for_each_matching_node(np, pci_ids) {
- if (of_device_is_available(np)) {
- fsl_pci_primary = np;
- of_node_put(np);
- return;
- }
- }
-}
-
static int fsl_pci_probe(struct platform_device *pdev)
{
int ret;
@@ -1143,4 +555,3 @@ static int __init fsl_pci_init(void)
return platform_driver_register(&fsl_pci_driver);
}
arch_initcall(fsl_pci_init);
-#endif
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/include/linux/fsl/pci.h
similarity index 79%
copy from arch/powerpc/sysdev/fsl_pci.h
copy to include/linux/fsl/pci.h
index 8d455df..bfc241d 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/include/linux/fsl/pci.h
@@ -1,5 +1,5 @@
/*
- * MPC85xx/86xx PCI Express structure define
+ * MPC85xx/86xx/LS PCI Express structure define
*
* Copyright 2007,2011 Freescale Semiconductor, Inc
*
@@ -11,15 +11,8 @@
*/
#ifdef __KERNEL__
-#ifndef __POWERPC_FSL_PCI_H
-#define __POWERPC_FSL_PCI_H
-
-struct platform_device;
-
-
-/* FSL PCI controller BRR1 register */
-#define PCI_FSL_BRR1 0xbf8
-#define PCI_FSL_BRR1_VER 0xffff
+#ifndef __PCI_H
+#define __PCI_H
#define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */
#define PCIE_LTSSM_L0 0x16 /* L0 state */
@@ -52,7 +45,7 @@ struct pci_inbound_window_regs {
u8 res2[12];
};
-/* PCI/PCI Express IO block registers for 85xx/86xx */
+/* PCI/PCI Express IO block registers for 85xx/86xx/LS */
struct ccsr_pci {
__be32 config_addr; /* 0x.000 - PCI/PCIE Configuration Address Register */
__be32 config_data; /* 0x.004 - PCI/PCIE Configuration Data Register */
@@ -109,33 +102,5 @@ struct ccsr_pci {
};
-extern int fsl_add_bridge(struct platform_device *pdev, int is_primary);
-extern void fsl_pcibios_fixup_bus(struct pci_bus *bus);
-extern int mpc83xx_add_bridge(struct device_node *dev);
-u64 fsl_pci_immrbar_base(struct pci_controller *hose);
-
-extern struct device_node *fsl_pci_primary;
-
-#ifdef CONFIG_PCI
-void fsl_pci_assign_primary(void);
-#else
-static inline void fsl_pci_assign_primary(void) {}
-#endif
-
-#ifdef CONFIG_EDAC_MPC85XX
-int mpc85xx_pci_err_probe(struct platform_device *op);
-#else
-static inline int mpc85xx_pci_err_probe(struct platform_device *op)
-{
- return -ENOTSUPP;
-}
-#endif
-
-#ifdef CONFIG_FSL_PCI
-extern int fsl_pci_mcheck_exception(struct pt_regs *);
-#else
-static inline int fsl_pci_mcheck_exception(struct pt_regs *regs) {return 0; }
-#endif
-
-#endif /* __POWERPC_FSL_PCI_H */
+#endif /* __PCI_H */
#endif /* __KERNEL__ */
--
1.8.1.2
^ permalink raw reply related
* [PATCH 2/2] pci: fsl: rework PCI driver compatible with Layerscape
From: Minghuan Lian @ 2013-09-18 11:02 UTC (permalink / raw)
To: linuxppc-dev
Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
Scott Wood
In-Reply-To: <1379502122-20792-1-git-send-email-Minghuan.Lian@freescale.com>
The Freescale's Layerscape series processors will use the same PCI
controller but change cores from PowerPC to ARM. This patch is to
rework FSL PCI driver to support PowerPC and ARM simultaneously.
PowerPC uses structure pci_controller to describe PCI controller,
but arm uses structure hw_pci and pci_sys_data. They also have
different architecture implementation and initialization flow.
The architecture-dependent driver will bridge the gap, get the
settings from the common driver and initialize the corresponding
structure and call the related interface to register PCI controller.
The common driver pci-fsl.c removes all the architecture-specific
code and provides structure fsl_pci to store all the controller
settings and the common functionalities that include reading/writing
PCI configuration space, parsing dts node and getting the MEM/IO and
bus number ranges, setting ATMU and check link status.
Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
Based on upstream master
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274488/
The function has been tested on MPC8315ERDB MPC8572DS P5020DS P3041DS
and T4240QDS boards
arch/powerpc/Kconfig | 1 +
arch/powerpc/sysdev/fsl_pci.c | 147 +++++++++-
drivers/edac/mpc85xx_edac.c | 16 +-
drivers/pci/host/Kconfig | 7 +
drivers/pci/host/Makefile | 1 +
drivers/pci/host/pci-fsl.c | 653 +++++++++++++++++++++++++++---------------
include/linux/fsl/pci.h | 69 +++++
7 files changed, 653 insertions(+), 241 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 38f3b7e..6fd6348 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -690,6 +690,7 @@ config FSL_SOC
config FSL_PCI
bool
+ select PCI_FSL if FSL_SOC_BOOKE || PPC_86xx
select PPC_INDIRECT_PCI
select PCI_QUIRKS
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index a189ff0..1413257 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -62,7 +62,11 @@ static void quirk_fsl_pcie_header(struct pci_dev *dev)
#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
#define MAX_PHYS_ADDR_BITS 40
-static u64 pci64_dma_offset = 1ull << MAX_PHYS_ADDR_BITS;
+
+u64 fsl_arch_pci64_dma_offset(void)
+{
+ return 1ull << MAX_PHYS_ADDR_BITS;
+}
static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
{
@@ -77,17 +81,43 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
if ((dev->bus == &pci_bus_type) &&
dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) {
set_dma_ops(dev, &dma_direct_ops);
- set_dma_offset(dev, pci64_dma_offset);
+ set_dma_offset(dev, fsl_arch_pci64_dma_offset());
}
*dev->dma_mask = dma_mask;
return 0;
}
+struct fsl_pci *fsl_arch_sys_to_pci(void *sys)
+{
+ struct pci_controller *hose = sys;
+ struct fsl_pci *pci = hose->private_data;
+
+ /* Update the first bus number */
+ if (pci->first_busno != hose->first_busno)
+ pci->first_busno = hose->first_busno;
+
+ return pci;
+}
+
+struct pci_bus *fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr)
+{
+ static struct pci_bus bus;
+ static struct pci_controller hose;
+
+ bus.number = busnr;
+ bus.sysdata = &hose;
+ hose.private_data = pci;
+ bus.ops = pci->ops;
+
+ return &bus;
+}
+
void fsl_pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_controller *hose = pci_bus_to_host(bus);
- int i, is_pcie = 0, no_link;
+ int i, is_pcie, no_link;
+ struct fsl_pci *pci = fsl_arch_sys_to_pci(hose);
/* The root complex bridge comes up with bogus resources,
* we copy the PHB ones in.
@@ -97,9 +127,8 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
* tricky.
*/
- if (fsl_pcie_bus_fixup)
- is_pcie = early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);
- no_link = !!(hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK);
+ is_pcie = pci->is_pcie;
+ no_link = fsl_pci_check_link(pci);
if (bus->parent == hose->bus && (is_pcie || no_link)) {
for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; ++i) {
@@ -121,6 +150,94 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
}
}
+int fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn)
+{
+ struct pci_controller *hose = pci->sys;
+
+ if (!hose)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (ppc_md.pci_exclude_device)
+ if (ppc_md.pci_exclude_device(hose, bus, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int fsl_arch_pci_sys_register(struct fsl_pci *pci)
+{
+ struct pci_controller *hose;
+
+ pci_add_flags(PCI_REASSIGN_ALL_BUS);
+ hose = pcibios_alloc_controller(pci->dn);
+ if (!hose)
+ return -ENOMEM;
+
+ /* set platform device as the parent */
+ hose->private_data = pci;
+ hose->parent = pci->dev;
+ hose->first_busno = pci->first_busno;
+ hose->last_busno = pci->last_busno;
+ hose->ops = pci->ops;
+
+#ifdef CONFIG_PPC32
+ /* On 32 bits, limit I/O space to 16MB */
+ if (pci->pci_io_size > 0x01000000)
+ pci->pci_io_size = 0x01000000;
+
+ /* 32 bits needs to map IOs here */
+ hose->io_base_virt = ioremap(pci->io_base_phys + pci->io_resource.start,
+ pci->pci_io_size);
+
+ /* Expect trouble if pci_addr is not 0 */
+ if (fsl_pci_primary == pci->dn)
+ isa_io_base = (unsigned long)hose->io_base_virt;
+#endif /* CONFIG_PPC32 */
+
+ hose->pci_io_size = pci->io_resource.start + pci->pci_io_size;
+ hose->io_base_phys = pci->io_base_phys;
+ hose->io_resource = pci->io_resource;
+
+ memcpy(hose->mem_offset, pci->mem_offset, sizeof(hose->mem_offset));
+ memcpy(hose->mem_resources, pci->mem_resources,
+ sizeof(hose->mem_resources));
+ hose->dma_window_base_cur = pci->dma_window_base_cur;
+ hose->dma_window_size = pci->dma_window_size;
+
+ pci->sys = hose;
+
+ /*
+ * Install our own dma_set_mask handler to fixup dma_ops
+ * and dma_offset when memory is more than dma window size
+ */
+ if (pci->is_pcie && memblock_end_of_DRAM() > hose->dma_window_size)
+ ppc_md.dma_set_mask = fsl_pci_dma_set_mask;
+
+#ifdef CONFIG_SWIOTLB
+ /*
+ * if we couldn't map all of DRAM via the dma windows
+ * we need SWIOTLB to handle buffers located outside of
+ * dma capable memory region
+ */
+ if (memblock_end_of_DRAM() - 1 > hose->dma_window_base_cur +
+ hose->dma_window_size)
+ ppc_swiotlb_enable = 1;
+#endif
+
+ mpc85xx_pci_err_probe(to_platform_device(pci->dev));
+ return 0;
+}
+
+void fsl_arch_pci_sys_remove(struct fsl_pci *pci)
+{
+ struct pci_controller *hose = pci->sys;
+
+ if (!hose)
+ return;
+
+ pcibios_free_controller(hose);
+}
+
#endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_pcie_header);
@@ -260,6 +377,16 @@ static struct pci_ops mpc83xx_pcie_ops = {
.write = mpc83xx_pcie_write_config,
};
+static int mpc83xx_pcie_check_link(struct pci_controller *hose)
+{
+ u32 val = 0;
+
+ early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
+ if (val < PCIE_LTSSM_L0)
+ return 1;
+ return 0;
+}
+
static int __init mpc83xx_pcie_setup(struct pci_controller *hose,
struct resource *reg)
{
@@ -294,7 +421,7 @@ static int __init mpc83xx_pcie_setup(struct pci_controller *hose,
out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAH, 0);
out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, 0);
- if (fsl_pcie_check_link(hose))
+ if (mpc83xx_pcie_check_link(hose))
hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
return 0;
@@ -592,6 +719,7 @@ int fsl_pci_mcheck_exception(struct pt_regs *regs)
#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
struct device_node *fsl_pci_primary;
+extern const struct of_device_id fsl_pci_ids[];
void fsl_pci_assign_primary(void)
{
@@ -607,7 +735,8 @@ void fsl_pci_assign_primary(void)
of_node_put(np);
np = fsl_pci_primary;
- if (of_match_node(pci_ids, np) && of_device_is_available(np))
+ if (of_match_node(fsl_pci_ids, np) &&
+ of_device_is_available(np))
return;
}
@@ -616,7 +745,7 @@ void fsl_pci_assign_primary(void)
* designate one as primary. This can go away once
* various bugs with primary-less systems are fixed.
*/
- for_each_matching_node(np, pci_ids) {
+ for_each_matching_node(np, fsl_pci_ids) {
if (of_device_is_available(np)) {
fsl_pci_primary = np;
of_node_put(np);
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 3eb32f6..2e51575 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -239,7 +239,6 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata = pci->pvt_info;
pdata->name = "mpc85xx_pci_err";
pdata->irq = NO_IRQ;
- dev_set_drvdata(&op->dev, pci);
pci->dev = &op->dev;
pci->mod_name = EDAC_MOD_STR;
pci->ctl_name = pdata->name;
@@ -260,14 +259,13 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
/* we only need the error registers */
r.start += 0xe00;
- if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
- pdata->name)) {
- printk(KERN_ERR "%s: Error while requesting mem region\n",
- __func__);
- res = -EBUSY;
- goto err;
- }
-
+ /*
+ * The main pci driver has been changed to call
+ * devm_request_mem_region() to request all PCI controller register
+ * region. PCI EDAC driver can not request error register region
+ * again. so it just only need to call devm_ioremap() to map the error
+ * register region.
+ */
pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
if (!pdata->pci_vbase) {
printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 3d95048..e829b18 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -19,4 +19,11 @@ config PCI_TEGRA
bool "NVIDIA Tegra PCIe controller"
depends on ARCH_TEGRA
+config PCI_FSL
+ bool "Freescale PCI/PCIe controller"
+ depends on FSL_SOC_BOOKE || PPC_86xx
+ help
+ Include support for PCI/PCIE controller on Freescale embedded
+ processors 85xx/86xx/QorIQ/Layerscape.
+
endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index c9a997b..3447a27 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_PCIE_DW) += pcie-designware.o
obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
+obj-$(CONFIG_PCI_FSL) += pci-fsl.o
diff --git a/drivers/pci/host/pci-fsl.c b/drivers/pci/host/pci-fsl.c
index 69d338b..0423e72 100644
--- a/drivers/pci/host/pci-fsl.c
+++ b/drivers/pci/host/pci-fsl.c
@@ -22,38 +22,159 @@
#include <linux/bootmem.h>
#include <linux/memblock.h>
#include <linux/log2.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc-pci.h>
-#include <asm/machdep.h>
-#include <asm/disassemble.h>
-#include <asm/ppc-opcode.h>
-#include <sysdev/fsl_soc.h>
-#include <sysdev/fsl_pci.h>
-
-static int fsl_pcie_check_link(struct pci_controller *hose)
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/pci_regs.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/types.h>
+#include <linux/memblock.h>
+#include <linux/fsl/pci.h>
+
+/* Indirect type */
+#define INDIRECT_TYPE_EXT_REG 0x00000002
+#define INDIRECT_TYPE_SURPRESS_PRIMARY_BUS 0x00000004
+#define INDIRECT_TYPE_NO_PCIE_LINK 0x00000008
+#define INDIRECT_TYPE_BIG_ENDIAN 0x00000010
+#define INDIRECT_TYPE_FSL_CFG_REG_LINK 0x00000040
+
+u64 __weak fsl_arch_pci64_dma_offset(void)
+{
+ return 0;
+}
+
+struct fsl_pci * __weak fsl_arch_sys_to_pci(void *sys)
+{
+ return NULL;
+}
+
+struct pci_bus * __weak fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr)
+{
+ return NULL;
+}
+
+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;
+}
+
+int 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;
} 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 = (in_be32(&pci->regs->pex_csr0) & PEX_CSR0_LTSSM_MASK)
>> PEX_CSR0_LTSSM_SHIFT;
if (val != PEX_CSR0_LTSSM_L0)
return 1;
@@ -65,27 +186,65 @@ static int fsl_pcie_check_link(struct pci_controller *hose)
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,
};
+#define EARLY_FSL_PCI_OP(rw, size, type) \
+int early_fsl_##rw##_config_##size(struct fsl_pci *pci, int bus, \
+ int devfn, int offset, type value) \
+{ \
+ return pci_bus_##rw##_config_##size(fsl_arch_fake_pci_bus(pci, bus),\
+ devfn, offset, value); \
+}
+
+EARLY_FSL_PCI_OP(read, byte, u8 *)
+EARLY_FSL_PCI_OP(read, word, u16 *)
+EARLY_FSL_PCI_OP(read, dword, u32 *)
+EARLY_FSL_PCI_OP(write, byte, u8)
+EARLY_FSL_PCI_OP(write, word, u16)
+EARLY_FSL_PCI_OP(write, dword, u32)
+
+static int early_fsl_find_capability(struct fsl_pci *pci,
+ int busnr, int devfn, int cap)
+{
+ struct pci_bus *bus = fsl_arch_fake_pci_bus(pci, busnr);
+
+ if (!bus)
+ return 0;
+
+ return pci_bus_find_capability(bus, devfn, cap);
+}
+
static int setup_one_atmu(struct ccsr_pci __iomem *pci,
- unsigned int index, const struct resource *res,
- resource_size_t offset)
+ unsigned int index, const struct resource *res,
+ resource_size_t offset)
{
resource_size_t pci_addr = res->start - offset;
resource_size_t phys_addr = res->start;
@@ -106,10 +265,10 @@ static int setup_one_atmu(struct ccsr_pci __iomem *pci,
if (index + i >= 5)
return -1;
- out_be32(&pci->pow[index + i].potar, pci_addr >> 12);
- out_be32(&pci->pow[index + i].potear, (u64)pci_addr >> 44);
- out_be32(&pci->pow[index + i].powbar, phys_addr >> 12);
- out_be32(&pci->pow[index + i].powar, flags | (bits - 1));
+ iowrite32be(pci_addr >> 12, &pci->pow[index + i].potar);
+ iowrite32be((u64)pci_addr >> 44, &pci->pow[index + i].potear);
+ iowrite32be(phys_addr >> 12, &pci->pow[index + i].powbar);
+ iowrite32be(flags | (bits - 1), &pci->pow[index + i].powar);
pci_addr += (resource_size_t)1U << bits;
phys_addr += (resource_size_t)1U << bits;
@@ -120,21 +279,19 @@ static int setup_one_atmu(struct ccsr_pci __iomem *pci,
}
/* atmu setup for fsl pci/pcie controller */
-static void setup_pci_atmu(struct pci_controller *hose)
+static void setup_pci_atmu(struct fsl_pci *pci)
{
- struct ccsr_pci __iomem *pci = hose->private_data;
int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4;
u64 mem, sz, paddr_hi = 0;
u64 offset = 0, paddr_lo = ULLONG_MAX;
u32 pcicsrbar = 0, pcicsrbar_sz;
u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
- const char *name = hose->dn->full_name;
const u64 *reg;
int len;
- if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
- if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) {
+ if (pci->is_pcie) {
+ if (in_be32(&pci->regs->block_rev1) >= PCIE_IP_REV_2_2) {
win_idx = 2;
start_idx = 0;
end_idx = 3;
@@ -142,47 +299,54 @@ static void setup_pci_atmu(struct pci_controller *hose)
}
/* Disable all windows (except powar0 since it's ignored) */
- for(i = 1; i < 5; i++)
- out_be32(&pci->pow[i].powar, 0);
+ for (i = 1; i < 5; i++)
+ iowrite32be(0, &pci->regs->pow[i].powar);
for (i = start_idx; i < end_idx; i++)
- out_be32(&pci->piw[i].piwar, 0);
+ iowrite32be(0, &pci->regs->piw[i].piwar);
/* Setup outbound MEM window */
- for(i = 0, j = 1; i < 3; i++) {
- if (!(hose->mem_resources[i].flags & IORESOURCE_MEM))
+ for (i = 0, j = 1; i < 3; i++) {
+ if (!(pci->mem_resources[i].flags & IORESOURCE_MEM))
continue;
- paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start);
- paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end);
+ paddr_lo = min_t(u64, paddr_lo, pci->mem_resources[i].start);
+ paddr_hi = max_t(u64, paddr_hi, pci->mem_resources[i].end);
/* We assume all memory resources have the same offset */
- offset = hose->mem_offset[i];
- n = setup_one_atmu(pci, j, &hose->mem_resources[i], offset);
+ offset = pci->mem_offset[i];
+ n = setup_one_atmu(pci->regs, j, &pci->mem_resources[i],
+ offset);
if (n < 0 || j >= 5) {
- pr_err("Ran out of outbound PCI ATMUs for resource %d!\n", i);
- hose->mem_resources[i].flags |= IORESOURCE_DISABLED;
+ dev_err(pci->dev,
+ "Ran out of outbound PCI ATMUs for resource %d!\n",
+ i);
+ pci->mem_resources[i].flags |= IORESOURCE_DISABLED;
} else
j += n;
}
/* Setup outbound IO window */
- if (hose->io_resource.flags & IORESOURCE_IO) {
- if (j >= 5) {
- pr_err("Ran out of outbound PCI ATMUs for IO resource\n");
- } else {
- pr_debug("PCI IO resource start 0x%016llx, size 0x%016llx, "
- "phy base 0x%016llx.\n",
- (u64)hose->io_resource.start,
- (u64)resource_size(&hose->io_resource),
- (u64)hose->io_base_phys);
- out_be32(&pci->pow[j].potar, (hose->io_resource.start >> 12));
- out_be32(&pci->pow[j].potear, 0);
- out_be32(&pci->pow[j].powbar, (hose->io_base_phys >> 12));
+ if (pci->io_resource.flags & IORESOURCE_IO) {
+ if (j >= 5)
+ dev_err(pci->dev,
+ "Ran out of outbound PCI ATMUs for IO resource\n");
+ else {
+ dev_dbg(pci->dev,
+ "PCI IO resource start 0x%016llx,"
+ "size 0x%016llx, phy base 0x%016llx.\n",
+ (u64)pci->io_resource.start,
+ (u64)resource_size(&pci->io_resource),
+ (u64)pci->io_base_phys);
+ iowrite32be(pci->io_resource.start >> 12,
+ &pci->regs->pow[j].potar);
+ iowrite32be(0, &pci->regs->pow[j].potear);
+ iowrite32be(pci->io_base_phys >> 12,
+ &pci->regs->pow[j].powbar);
/* Enable, IO R/W */
- out_be32(&pci->pow[j].powar, 0x80088000
- | (ilog2(hose->io_resource.end
- - hose->io_resource.start + 1) - 1));
+ iowrite32be(0x80088000 |
+ (ilog2(resource_size(&pci->io_resource)) - 1),
+ &pci->regs->pow[j].powar);
}
}
@@ -191,18 +355,20 @@ static void setup_pci_atmu(struct pci_controller *hose)
paddr_lo -= offset;
if (paddr_hi == paddr_lo) {
- pr_err("%s: No outbound window space\n", name);
+ dev_err(pci->dev, "No outbound window space\n");
return;
}
if (paddr_lo == 0) {
- pr_err("%s: No space for inbound window\n", name);
+ dev_err(pci->dev, "No space for inbound window\n");
return;
}
/* setup PCSRBAR/PEXCSRBAR */
- early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff);
- early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
+ early_fsl_write_config_dword(pci, 0, 0, PCI_BASE_ADDRESS_0,
+ 0xffffffff);
+ early_fsl_read_config_dword(pci, 0, 0, PCI_BASE_ADDRESS_0,
+ &pcicsrbar_sz);
pcicsrbar_sz = ~pcicsrbar_sz + 1;
if (paddr_hi < (0x100000000ull - pcicsrbar_sz) ||
@@ -210,11 +376,12 @@ static void setup_pci_atmu(struct pci_controller *hose)
pcicsrbar = 0x100000000ull - pcicsrbar_sz;
else
pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz;
- early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar);
+ early_fsl_write_config_dword(pci, 0, 0, PCI_BASE_ADDRESS_0,
+ pcicsrbar);
- paddr_lo = min(paddr_lo, (u64)pcicsrbar);
+ paddr_lo = min_t(u64, paddr_lo, pcicsrbar);
- pr_info("%s: PCICSRBAR @ 0x%x\n", name, pcicsrbar);
+ dev_info(pci->dev, "PCICSRBAR @ 0x%x\n", pcicsrbar);
/* Setup inbound mem window */
mem = memblock_end_of_DRAM();
@@ -231,17 +398,19 @@ static void setup_pci_atmu(struct pci_controller *hose)
* can avoid allocating a new ATMU by extending the DDR ATMU by one
* page.
*/
- reg = of_get_property(hose->dn, "msi-address-64", &len);
+ reg = of_get_property(pci->dn, "msi-address-64", &len);
if (reg && (len == sizeof(u64))) {
u64 address = be64_to_cpup(reg);
if ((address >= mem) && (address < (mem + PAGE_SIZE))) {
- pr_info("%s: extending DDR ATMU to cover MSIIR", name);
+ dev_info(pci->dev,
+ "extending DDR ATMU to cover MSIIR\n");
mem += PAGE_SIZE;
} else {
/* TODO: Create a new ATMU for MSIIR */
- pr_warn("%s: msi-address-64 address of %llx is "
- "unsupported\n", name, address);
+ dev_warn(pci->dev,
+ "msi-address-64 address of %llx is "
+ "unsupported\n", address);
}
}
@@ -249,25 +418,26 @@ static void setup_pci_atmu(struct pci_controller *hose)
mem_log = ilog2(sz);
/* PCIe can overmap inbound & outbound since RX & TX are separated */
- if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
+ if (pci->is_pcie) {
/* Size window to exact size if power-of-two or one size up */
if ((1ull << mem_log) != mem) {
mem_log++;
if ((1ull << mem_log) > mem)
- pr_info("%s: Setting PCI inbound window "
- "greater than memory size\n", name);
+ dev_info(pci->dev,
+ "Setting PCI inbound window "
+ "greater than memory size\n");
}
piwar |= ((mem_log - 1) & PIWAR_SZ_MASK);
/* Setup inbound memory window */
- out_be32(&pci->piw[win_idx].pitar, 0x00000000);
- out_be32(&pci->piw[win_idx].piwbar, 0x00000000);
- out_be32(&pci->piw[win_idx].piwar, piwar);
+ iowrite32be(0, &pci->regs->piw[win_idx].pitar);
+ iowrite32be(0, &pci->regs->piw[win_idx].piwbar);
+ iowrite32be(piwar, &pci->regs->piw[win_idx].piwar);
win_idx--;
- hose->dma_window_base_cur = 0x00000000;
- hose->dma_window_size = (resource_size_t)sz;
+ pci->dma_window_base_cur = 0x00000000;
+ pci->dma_window_size = (resource_size_t)sz;
/*
* if we have >4G of memory setup second PCI inbound window to
@@ -284,28 +454,22 @@ static void setup_pci_atmu(struct pci_controller *hose)
piwar = (piwar & ~PIWAR_SZ_MASK) | (mem_log - 1);
/* Setup inbound memory window */
- out_be32(&pci->piw[win_idx].pitar, 0x00000000);
- out_be32(&pci->piw[win_idx].piwbear,
- pci64_dma_offset >> 44);
- out_be32(&pci->piw[win_idx].piwbar,
- pci64_dma_offset >> 12);
- out_be32(&pci->piw[win_idx].piwar, piwar);
-
- /*
- * install our own dma_set_mask handler to fixup dma_ops
- * and dma_offset
- */
- ppc_md.dma_set_mask = fsl_pci_dma_set_mask;
-
- pr_info("%s: Setup 64-bit PCI DMA window\n", name);
+ iowrite32be(0, &pci->regs->piw[win_idx].pitar);
+ iowrite32be(fsl_arch_pci64_dma_offset() >> 44,
+ &pci->regs->piw[win_idx].piwbear);
+ iowrite32be(fsl_arch_pci64_dma_offset() >> 12,
+ &pci->regs->piw[win_idx].piwbar);
+ iowrite32be(piwar,
+ &pci->regs->piw[win_idx].piwar);
}
} else {
u64 paddr = 0;
/* Setup inbound memory window */
- out_be32(&pci->piw[win_idx].pitar, paddr >> 12);
- out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
- out_be32(&pci->piw[win_idx].piwar, (piwar | (mem_log - 1)));
+ iowrite32be(paddr >> 12, &pci->regs->piw[win_idx].pitar);
+ iowrite32be(paddr >> 12, &pci->regs->piw[win_idx].piwbar);
+ iowrite32be((piwar | (mem_log - 1)),
+ &pci->regs->piw[win_idx].piwar);
win_idx--;
paddr += 1ull << mem_log;
@@ -315,167 +479,181 @@ static void setup_pci_atmu(struct pci_controller *hose)
mem_log = ilog2(sz);
piwar |= (mem_log - 1);
- out_be32(&pci->piw[win_idx].pitar, paddr >> 12);
- out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
- out_be32(&pci->piw[win_idx].piwar, piwar);
+ iowrite32be(paddr >> 12,
+ &pci->regs->piw[win_idx].pitar);
+ iowrite32be(paddr >> 12,
+ &pci->regs->piw[win_idx].piwbar);
+ iowrite32be(piwar,
+ &pci->regs->piw[win_idx].piwar);
win_idx--;
paddr += 1ull << mem_log;
}
- hose->dma_window_base_cur = 0x00000000;
- hose->dma_window_size = (resource_size_t)paddr;
+ pci->dma_window_base_cur = 0x00000000;
+ pci->dma_window_size = (resource_size_t)paddr;
}
- if (hose->dma_window_size < mem) {
-#ifdef CONFIG_SWIOTLB
- ppc_swiotlb_enable = 1;
-#else
- pr_err("%s: ERROR: Memory size exceeds PCI ATMU ability to "
- "map - enable CONFIG_SWIOTLB to avoid dma errors.\n",
- name);
+ if (pci->dma_window_size < mem) {
+#ifndef CONFIG_SWIOTLB
+ dev_err(pci->dev,
+ "Memory size exceeds PCI ATMU ability to "
+ "map - enable CONFIG_SWIOTLB to avoid dma errors.\n");
#endif
/* adjusting outbound windows could reclaim space in mem map */
if (paddr_hi < 0xffffffffull)
- pr_warning("%s: WARNING: Outbound window cfg leaves "
+ dev_warn(pci->dev,
+ "Outbound window cfg leaves "
"gaps in memory map. Adjusting the memory map "
- "could reduce unnecessary bounce buffering.\n",
- name);
+ "could reduce unnecessary bounce buffering.\n");
- pr_info("%s: DMA window size is 0x%llx\n", name,
- (u64)hose->dma_window_size);
+ dev_info(pci->dev, "DMA window size is 0x%llx\n",
+ (u64)pci->dma_window_size);
}
}
-static void __init setup_pci_cmd(struct pci_controller *hose)
+static void __init setup_pci_cmd(struct fsl_pci *pci)
{
u16 cmd;
int cap_x;
- early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd);
+ early_fsl_read_config_word(pci, 0, 0, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
| PCI_COMMAND_IO;
- early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd);
+ early_fsl_write_config_word(pci, 0, 0, PCI_COMMAND, cmd);
- cap_x = early_find_capability(hose, 0, 0, PCI_CAP_ID_PCIX);
+ cap_x = early_fsl_find_capability(pci, 0, 0, PCI_CAP_ID_PCIX);
if (cap_x) {
int pci_x_cmd = cap_x + PCI_X_CMD;
cmd = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
| PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
- early_write_config_word(hose, 0, 0, pci_x_cmd, cmd);
- } else {
- early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
- }
+ early_fsl_write_config_word(pci, 0, 0, pci_x_cmd, cmd);
+ } else
+ early_fsl_write_config_byte(pci, 0, 0, PCI_LATENCY_TIMER,
+ 0x80);
}
-int __init fsl_add_bridge(struct platform_device *pdev, int is_primary)
+static int __init
+fsl_pci_setup(struct platform_device *pdev, struct fsl_pci *pci)
{
- int len;
- struct pci_controller *hose;
- struct resource rsrc;
- const int *bus_range;
+ struct resource *rsrc;
u8 hdr_type, progif;
- struct device_node *dev;
- struct ccsr_pci __iomem *pci;
+ struct device_node *dn;
+ struct of_pci_range range;
+ struct of_pci_range_parser parser;
+ int mem = 0;
- dev = pdev->dev.of_node;
+ dn = pdev->dev.of_node;
+ pci->dn = dn;
+ pci->dev = &pdev->dev;
- if (!of_device_is_available(dev)) {
- pr_warning("%s: disabled\n", dev->full_name);
- return -ENODEV;
- }
-
- pr_debug("Adding PCI host bridge %s\n", dev->full_name);
+ dev_info(&pdev->dev, "Find controller %s\n", dn->full_name);
/* Fetch host bridge registers address */
- if (of_address_to_resource(dev, 0, &rsrc)) {
- printk(KERN_WARNING "Can't get pci register base!");
- return -ENOMEM;
+ rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!rsrc) {
+ dev_err(&pdev->dev, "Can't get pci register base!");
+ return -EINVAL;
}
+ dev_info(&pdev->dev, "REG 0x%016llx..0x%016llx\n",
+ (u64)rsrc->start, (u64)rsrc->end);
- /* Get bus range if any */
- bus_range = of_get_property(dev, "bus-range", &len);
- if (bus_range == NULL || len < 2 * sizeof(int))
- printk(KERN_WARNING "Can't get bus-range for %s, assume"
- " bus 0\n", dev->full_name);
-
- pci_add_flags(PCI_REASSIGN_ALL_BUS);
- hose = pcibios_alloc_controller(dev);
- if (!hose)
- return -ENOMEM;
+ /* Parse pci range resources from device tree */
+ if (of_pci_range_parser_init(&parser, dn)) {
+ dev_err(&pdev->dev, "missing ranges property\n");
+ return -EINVAL;
+ }
- /* set platform device as the parent */
- hose->parent = &pdev->dev;
- hose->first_busno = bus_range ? bus_range[0] : 0x0;
- hose->last_busno = bus_range ? bus_range[1] : 0xff;
+ /* Get the I/O and memory ranges from device tree */
+ for_each_of_pci_range(&parser, &range) {
+ unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
+ if (restype == IORESOURCE_IO) {
+ of_pci_range_to_resource(&range, dn,
+ &pci->io_resource);
+ pci->io_resource.name = "I/O";
+ pci->io_resource.start = range.pci_addr;
+ pci->io_resource.end = range.pci_addr + range.size - 1;
+ pci->pci_io_size = range.size;
+ pci->io_base_phys = range.cpu_addr - range.pci_addr;
+ dev_info(&pdev->dev,
+ " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
+ range.cpu_addr,
+ range.cpu_addr + range.size - 1,
+ range.pci_addr);
+ }
+ if (restype == IORESOURCE_MEM) {
+ if (mem >= 3)
+ continue;
+ of_pci_range_to_resource(&range, dn,
+ &pci->mem_resources[mem]);
+ pci->mem_resources[mem].name = "MEM";
+ pci->mem_offset[mem] = range.cpu_addr - range.pci_addr;
+ dev_info(&pdev->dev,
+ "MEM 0x%016llx..0x%016llx -> 0x%016llx\n",
+ (u64)pci->mem_resources[mem].start,
+ (u64)pci->mem_resources[mem].end,
+ range.pci_addr);
+ }
+ }
- pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",
- (u64)rsrc.start, (u64)resource_size(&rsrc));
+ /* Get bus range */
+ if (of_pci_parse_bus_range(dn, &pci->busn)) {
+ dev_err(&pdev->dev, "failed to parse bus-range property\n");
+ pci->first_busno = 0x0;
+ pci->last_busno = 0xff;
+ } else {
+ pci->first_busno = pci->busn.start;
+ pci->last_busno = pci->busn.end;
+ }
+ dev_info(&pdev->dev, "Firmware bus number %d->%d\n",
+ pci->first_busno, pci->last_busno);
- pci = hose->private_data = ioremap(rsrc.start, resource_size(&rsrc));
- if (!hose->private_data)
- goto no_bridge;
+ pci->regs = devm_ioremap_resource(&pdev->dev, rsrc);
+ if (IS_ERR(pci->regs))
+ return PTR_ERR(pci->regs);
- setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4,
- PPC_INDIRECT_TYPE_BIG_ENDIAN);
+ pci->ops = &fsl_indirect_pci_ops;
+ pci->indirect_type = INDIRECT_TYPE_BIG_ENDIAN;
- if (in_be32(&pci->block_rev1) < PCIE_IP_REV_3_0)
- hose->indirect_type |= PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK;
+ if (in_be32(&pci->regs->block_rev1) < PCIE_IP_REV_3_0)
+ pci->indirect_type |= INDIRECT_TYPE_FSL_CFG_REG_LINK;
- if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
- /* use fsl_indirect_read_config for PCIe */
- hose->ops = &fsl_indirect_pcie_ops;
- /* For PCIE read HEADER_TYPE to identify controler mode */
- early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type);
- if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ pci->is_pcie = early_fsl_find_capability(pci, 0, 0, PCI_CAP_ID_EXP);
+ if (pci->is_pcie) {
+ /* For PCIE read HEADER_TYPE to identify controller mode */
+ early_fsl_read_config_byte(pci, 0, 0, PCI_HEADER_TYPE,
+ &hdr_type);
+ if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL)
goto no_bridge;
-
} else {
/* For PCI read PROG to identify controller mode */
- early_read_config_byte(hose, 0, 0, PCI_CLASS_PROG, &progif);
+ early_fsl_read_config_byte(pci, 0, 0, PCI_CLASS_PROG, &progif);
if ((progif & 1) == 1)
goto no_bridge;
}
- setup_pci_cmd(hose);
+ setup_pci_cmd(pci);
/* check PCI express link status */
- if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
- hose->indirect_type |= PPC_INDIRECT_TYPE_EXT_REG |
- PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
- if (fsl_pcie_check_link(hose))
- hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
+ if (pci->is_pcie) {
+ pci->indirect_type |= INDIRECT_TYPE_EXT_REG |
+ INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
+ if (fsl_pci_check_link(pci))
+ pci->indirect_type |= INDIRECT_TYPE_NO_PCIE_LINK;
}
- printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
- "Firmware bus number: %d->%d\n",
- (unsigned long long)rsrc.start, hose->first_busno,
- hose->last_busno);
-
- pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
- hose, hose->cfg_addr, hose->cfg_data);
-
- /* Interpret the "ranges" property */
- /* This also maps the I/O region and sets isa_io/mem_base */
- pci_process_bridge_OF_ranges(hose, dev, is_primary);
-
/* Setup PEX window registers */
- setup_pci_atmu(hose);
+ setup_pci_atmu(pci);
+
+ platform_set_drvdata(pdev, pci);
return 0;
no_bridge:
- iounmap(hose->private_data);
- /* unmap cfg_data & cfg_addr separately if not on same page */
- if (((unsigned long)hose->cfg_data & PAGE_MASK) !=
- ((unsigned long)hose->cfg_addr & PAGE_MASK))
- iounmap(hose->cfg_data);
- iounmap(hose->cfg_addr);
- pcibios_free_controller(hose);
return -ENODEV;
}
-static const struct of_device_id pci_ids[] = {
+const struct of_device_id fsl_pci_ids[] = {
{ .compatible = "fsl,mpc8540-pci", },
{ .compatible = "fsl,mpc8548-pcie", },
{ .compatible = "fsl,mpc8610-pci", },
@@ -496,35 +674,63 @@ static const struct of_device_id pci_ids[] = {
{},
};
-static int fsl_pci_probe(struct platform_device *pdev)
+static int __init fsl_pci_probe(struct platform_device *pdev)
{
int ret;
- struct device_node *node;
+ struct fsl_pci *pci;
+
+ if (!of_device_is_available(pdev->dev.of_node)) {
+ dev_warn(&pdev->dev, "disabled\n");
+ return -ENODEV;
+ }
+
+ if (!fsl_arch_pci_sys_register) {
+ dev_err(&pdev->dev,
+ "no fsl_arch_pci_sys_register implementation\n");
+ return -EPERM;
+ }
+
+ pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL);
+ if (!pci) {
+ dev_err(&pdev->dev, "no memory for fsl_pci\n");
+ return -ENOMEM;
+ }
- node = pdev->dev.of_node;
- ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
+ ret = fsl_pci_setup(pdev, pci);
+ if (ret)
+ return ret;
- mpc85xx_pci_err_probe(pdev);
+ ret = fsl_arch_pci_sys_register(pci);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register pcie to Arch\n");
+ return ret;
+ }
return 0;
}
-#ifdef CONFIG_PM
-static int fsl_pci_resume(struct device *dev)
+static int __exit fsl_pci_remove(struct platform_device *pdev)
{
- struct pci_controller *hose;
- struct resource pci_rsrc;
+ struct fsl_pci *pci = platform_get_drvdata(pdev);
- hose = pci_find_hose_for_OF_device(dev->of_node);
- if (!hose)
+ if (!pci)
return -ENODEV;
- if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) {
- dev_err(dev, "Get pci register base failed.");
+ if (fsl_arch_pci_sys_remove)
+ fsl_arch_pci_sys_remove(pci);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int fsl_pci_resume(struct device *dev)
+{
+ struct fsl_pci *pci = dev_get_drvdata(dev);
+
+ if (!pci)
return -ENODEV;
- }
- setup_pci_atmu(hose);
+ setup_pci_atmu(pci);
return 0;
}
@@ -545,9 +751,10 @@ static struct platform_driver fsl_pci_driver = {
.driver = {
.name = "fsl-pci",
.pm = PCI_PM_OPS,
- .of_match_table = pci_ids,
+ .of_match_table = fsl_pci_ids,
},
.probe = fsl_pci_probe,
+ .remove = fsl_pci_remove,
};
static int __init fsl_pci_init(void)
diff --git a/include/linux/fsl/pci.h b/include/linux/fsl/pci.h
index bfc241d..500bdbb 100644
--- a/include/linux/fsl/pci.h
+++ b/include/linux/fsl/pci.h
@@ -102,5 +102,74 @@ struct ccsr_pci {
};
+/*
+ * Structure of a PCI controller (host bridge)
+ */
+struct fsl_pci {
+ struct list_head node;
+ int is_pcie;
+ struct device_node *dn;
+ struct device *dev;
+
+ int first_busno;
+ int last_busno;
+ int self_busno;
+ struct resource busn;
+
+ struct pci_ops *ops;
+ struct ccsr_pci __iomem *regs;
+
+ u32 indirect_type;
+
+ struct resource io_resource;
+ resource_size_t io_base_phys;
+ resource_size_t pci_io_size;
+
+ struct resource mem_resources[3];
+ resource_size_t mem_offset[3];
+
+ int global_number; /* PCI domain number */
+
+ resource_size_t dma_window_base_cur;
+ resource_size_t dma_window_size;
+
+ void *sys;
+};
+
+/* Return link status 0-> link, 1-> no link */
+int fsl_pci_check_link(struct fsl_pci *pci);
+
+/*
+ * The fsl_arch_* functions are arch hooks. Those functions are
+ * implemented as weak symbols so that they can be overridden by
+ * architecture specific code if needed.
+ */
+
+/* Return PCI64 DMA offset */
+u64 fsl_arch_pci64_dma_offset(void);
+
+/*
+ * Convert architecture specific pci controller structure to fsl_pci
+ * PowerPC uses structure pci_controller and ARM uses structure pci_sys_data
+ * to describe pci controller.
+ */
+struct fsl_pci *fsl_arch_sys_to_pci(void *sys);
+
+/*
+ * To fake a PCI bus
+ * it is called by early_fsl_*(), at that time the architecture-dependent
+ * pci controller and pci bus have not been created.
+ */
+struct pci_bus *fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr);
+
+/* To avoid touching specified devices */
+int fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn);
+
+/* Register PCI/PCIe controller to architecture system */
+int __weak fsl_arch_pci_sys_register(struct fsl_pci *pci);
+
+/* Remove PCI/PCIe controller from architecture system */
+void __weak fsl_arch_pci_sys_remove(struct fsl_pci *pci);
+
#endif /* __PCI_H */
#endif /* __KERNEL__ */
--
1.8.1.2
^ permalink raw reply related
* [PATCH v2 01/10] of/irq: Rework of_irq_count()
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
The of_irq_to_resource() helper that is used to implement of_irq_count()
tries to resolve interrupts and in fact creates a mapping for resolved
interrupts. That's pretty heavy lifting for something that claims to
just return the number of interrupts requested by a given device node.
Instead, use the more lightweight of_irq_map_one(), which, despite the
name, doesn't create an actual mapping. Perhaps a better name would be
of_irq_translate_one().
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
drivers/of/irq.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 1752988..5f44388 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -368,9 +368,10 @@ EXPORT_SYMBOL_GPL(of_irq_to_resource);
*/
int of_irq_count(struct device_node *dev)
{
+ struct of_irq irq;
int nr = 0;
- while (of_irq_to_resource(dev, nr, NULL))
+ while (of_irq_map_one(dev, nr, &irq) == 0)
nr++;
return nr;
--
1.8.4
^ permalink raw reply related
* [PATCH v2 00/10] of/irq: Defer interrupt reference resolution
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
Hi,
This small series allows interrupt references from the device tree to be
resolved at driver probe time, rather than at device creation time. The
current implementation resolves such references while devices are added
during the call to of_platform_populate(), which happens very early in
the boot process. This causes probe ordering issues, because all devices
that are an interrupt parent for other devices need to have been probed
by that time. This is worked around for primary interrupt controllers by
initializing them using a device tree specific way (of_irq_init()), but
it doesn't work for something like a GPIO controller that is itself a
platform device and an interrupt parent for other devices at the same
time.
Currently such drivers use explicit initcall ordering to force these
chips to be probed earlier than other devices, but that only fixes a
subset of the problematic cases. It doesn't work if the interrupt user
is itself a platform device on the same bus. There are possibly other
cases where it doesn't work either.
This patch series attempts to fix this by not resolving the interrupt
references at device creation time. Instead, some functionality is added
to the driver core to resolve them for each device immediately before it
is probed. Often this is a lot later than the point at which the device
was created, which gives interrupt parents more time and therefore a
better chance of being probed. More importantly, however, it allows the
driver core to detect when an interrupt parent isn't there yet and cause
the device to be queued for deferred probing. After all, resolving probe
ordering issues is one of the primary reason for the introduction of
deferred probing.
Unfortunately the interrupt core code isn't prepared to handle this very
well, so some preparatory work is required.
Patches 1 and 2 are cleanup. Patch 1 modifies of_irq_count() to not use
the heavyweight of_irq_to_resource(), which will actually try to create
a mapping. While not usually harmful, it causes a warning during boot if
the interrupt parent hasn't registered an IRQ domain yet. Furthermore it
is much more than the stated intention of the function, which is to
return the number of interrupts that a device node uses. Various uses of
the of_irq_to_resource() function are replaced by more simpler versions
using irq_of_parse_and_map() in patch 2.
Patches 3 introduces the __irq_create_mapping() function, equivalent to
its non-__ counterpart except that it returns a negative error code on
failure and therefore allows propagation of a precise error code instead
of 0 for all errors. This is an important prerequisite for subsequent
patches. I would've preferred not to introduce an underscore-prefixed
variant but there are about 114 callers and updating them all would've
been rather messy.
Patch 4 updates irq_create_of_mapping() to return a negative error code
on failure instead of 0. The number of the mapped interrupt is returned
in an output parameter. All callers of this function are updated.
Patch 5 adds an __-prefixed variant of irq_of_parse_and_map() which
returns a negative error code on failure instead of 0. The number of
the mapped interrupt is returned in an output parameter.
Patch 6 modifies of_irq_to_resource() to return a negative error code on
failure (so that error can be propagated) and updates all callers.
Patch 7 propagates errors from of_irq_to_resource() to users of the
of_irq_to_resource_table() function.
Patch 8 adds functionality to the platform driver code to resolve
interrupt references at probe time. It uses the negative error code of
the of_irq_to_resource_table() function to trigger deferred probing.
Patch 9 implements similar functionality for I2C devices.
Patch 10 serves as an example of the kind of cleanup that can be done
after this series. Obviously this will require quite a bit of retesting
of working setups, but I think that in the long run we're better off
without the kind of explicit probe ordering employed by the gpio-tegra
driver and many others.
Note that I've only implemented this for platform and I2C devices, but
the same can be done for SPI and possibly other subsystems as well.
There is another use-case that I'm aware of for which a similar solution
could be implemented. IOMMUs on SoCs generally need to hook themselves
up to new platform devices. This causes a similar issues as interrupt
resolution and should be fixable by extending the of_platform_probe()
function introduced in patch 7 of this series.
Changes in v2:
- use more consistent naming and calling conventions
- use less wrappers, update more callers
- make of_platform_probe() idempotent
The initial version of this patch series can be found here:
https://lkml.org/lkml/2013/9/16/111
Thierry
Thierry Reding (10):
of/irq: Rework of_irq_count()
of/irq: Use irq_of_parse_and_map()
irqdomain: Introduce __irq_create_mapping()
irqdomain: Return errors from irq_create_of_mapping()
of/irq: Introduce __irq_of_parse_and_map()
of/irq: Return errors from of_irq_to_resource()
of/irq: Propagate errors in of_irq_to_resource_table()
of/platform: Resolve interrupt references at probe time
of/i2c: Resolve interrupt references at probe time
gpio: tegra: Use module_platform_driver()
arch/arm/mach-integrator/pci_v3.c | 8 +-
arch/arm/mach-u300/timer.c | 9 +-
arch/microblaze/pci/pci-common.c | 6 +-
arch/mips/lantiq/irq.c | 2 +-
arch/mips/lantiq/xway/gptu.c | 6 +-
arch/mips/pci/fixup-lantiq.c | 12 ++-
arch/mips/pci/pci-rt3883.c | 9 +-
arch/powerpc/kernel/pci-common.c | 7 +-
arch/powerpc/platforms/83xx/mpc832x_rdb.c | 2 +-
arch/powerpc/platforms/cell/celleb_scc_pciex.c | 8 +-
arch/powerpc/platforms/cell/celleb_scc_sio.c | 8 +-
arch/powerpc/platforms/cell/spider-pic.c | 7 +-
arch/powerpc/platforms/cell/spu_manage.c | 6 +-
arch/powerpc/platforms/fsl_uli1575.c | 7 +-
arch/powerpc/platforms/pseries/event_sources.c | 12 +--
arch/powerpc/sysdev/fsl_gtm.c | 9 +-
arch/powerpc/sysdev/mpic_msgr.c | 6 +-
arch/sparc/kernel/of_device_common.c | 12 ++-
arch/x86/kernel/devicetree.c | 11 ++-
drivers/base/platform.c | 4 +
drivers/crypto/caam/ctrl.c | 2 +-
drivers/crypto/caam/jr.c | 2 +-
drivers/crypto/omap-sham.c | 2 +-
drivers/gpio/gpio-tegra.c | 7 +-
drivers/i2c/busses/i2c-cpm.c | 2 +-
drivers/i2c/i2c-core.c | 24 ++++-
drivers/input/serio/xilinx_ps2.c | 7 +-
drivers/net/ethernet/arc/emac_main.c | 10 +--
drivers/net/ethernet/freescale/fs_enet/mac-fcc.c | 2 +-
drivers/net/ethernet/freescale/fs_enet/mac-fec.c | 2 +-
drivers/net/ethernet/freescale/fs_enet/mac-scc.c | 2 +-
drivers/net/ethernet/marvell/mv643xx_eth.c | 5 +-
drivers/of/irq.c | 49 +++++++----
drivers/of/platform.c | 107 +++++++++++++++++++++--
drivers/pci/host/pci-mvebu.c | 9 +-
drivers/spi/spi-fsl-espi.c | 6 +-
drivers/tty/serial/cpm_uart/cpm_uart_core.c | 2 +-
drivers/tty/serial/lantiq.c | 2 +-
include/linux/of_irq.h | 27 ++++--
include/linux/of_platform.h | 7 ++
kernel/irq/irqdomain.c | 87 +++++++++++-------
41 files changed, 353 insertions(+), 161 deletions(-)
--
1.8.4
^ permalink raw reply
* [PATCH v2 02/10] of/irq: Use irq_of_parse_and_map()
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
Replace some instances of of_irq_map_one()/irq_create_of_mapping() and
of_irq_to_resource() by the simpler equivalent irq_of_parse_and_map().
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
arch/arm/mach-u300/timer.c | 9 ++++-----
arch/powerpc/platforms/cell/celleb_scc_pciex.c | 8 +++-----
arch/powerpc/platforms/cell/spider-pic.c | 7 ++-----
arch/powerpc/sysdev/fsl_gtm.c | 9 ++++-----
arch/powerpc/sysdev/mpic_msgr.c | 6 ++----
drivers/crypto/caam/ctrl.c | 2 +-
drivers/crypto/caam/jr.c | 2 +-
drivers/crypto/omap-sham.c | 2 +-
drivers/i2c/busses/i2c-cpm.c | 2 +-
drivers/input/serio/xilinx_ps2.c | 7 ++++---
drivers/net/ethernet/arc/emac_main.c | 10 +++++-----
drivers/net/ethernet/freescale/fs_enet/mac-fcc.c | 2 +-
drivers/net/ethernet/freescale/fs_enet/mac-fec.c | 2 +-
drivers/net/ethernet/freescale/fs_enet/mac-scc.c | 2 +-
drivers/spi/spi-fsl-espi.c | 6 +++---
drivers/tty/serial/cpm_uart/cpm_uart_core.c | 2 +-
16 files changed, 35 insertions(+), 43 deletions(-)
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
index b5db207..9a5f9fb 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/arch/arm/mach-u300/timer.c
@@ -358,8 +358,7 @@ static struct delay_timer u300_delay_timer;
*/
static void __init u300_timer_init_of(struct device_node *np)
{
- struct resource irq_res;
- int irq;
+ unsigned int irq;
struct clk *clk;
unsigned long rate;
@@ -368,11 +367,11 @@ static void __init u300_timer_init_of(struct device_node *np)
panic("could not ioremap system timer\n");
/* Get the IRQ for the GP1 timer */
- irq = of_irq_to_resource(np, 2, &irq_res);
- if (irq <= 0)
+ irq = irq_of_parse_and_map(np, 2);
+ if (!irq)
panic("no IRQ for system timer\n");
- pr_info("U300 GP1 timer @ base: %p, IRQ: %d\n", u300_timer_base, irq);
+ pr_info("U300 GP1 timer @ base: %p, IRQ: %u\n", u300_timer_base, irq);
/* Clock the interrupt controller */
clk = of_clk_get(np, 0);
diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c
index 14be2bd..856ad64 100644
--- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c
+++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c
@@ -486,8 +486,7 @@ static __init int celleb_setup_pciex(struct device_node *node,
struct pci_controller *phb)
{
struct resource r;
- struct of_irq oirq;
- int virq;
+ unsigned int virq;
/* SMMIO registers; used inside this file */
if (of_address_to_resource(node, 0, &r)) {
@@ -507,12 +506,11 @@ static __init int celleb_setup_pciex(struct device_node *node,
phb->ops = &scc_pciex_pci_ops;
/* internal interrupt handler */
- if (of_irq_map_one(node, 1, &oirq)) {
+ virq = irq_of_parse_and_map(node, 1);
+ if (!virq) {
pr_err("PCIEXC:Failed to map irq\n");
goto error;
}
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
if (request_irq(virq, pciex_handle_internal_irq,
0, "pciex", (void *)phb)) {
pr_err("PCIEXC:Failed to request irq\n");
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 8e29944..1f72f4a 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -235,12 +235,9 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
/* First, we check whether we have a real "interrupts" in the device
* tree in case the device-tree is ever fixed
*/
- struct of_irq oirq;
- if (of_irq_map_one(pic->host->of_node, 0, &oirq) == 0) {
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
+ virq = irq_of_parse_and_map(pic->host->of_node, 0);
+ if (virq)
return virq;
- }
/* Now do the horrible hacks */
tmp = of_get_property(pic->host->of_node, "#interrupt-cells", NULL);
diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c
index 0eb871c..dd0d5be 100644
--- a/arch/powerpc/sysdev/fsl_gtm.c
+++ b/arch/powerpc/sysdev/fsl_gtm.c
@@ -401,16 +401,15 @@ static int __init fsl_gtm_init(void)
gtm->clock = *clock;
for (i = 0; i < ARRAY_SIZE(gtm->timers); i++) {
- int ret;
- struct resource irq;
+ unsigned int irq;
- ret = of_irq_to_resource(np, i, &irq);
- if (ret == NO_IRQ) {
+ irq = irq_of_parse_and_map(np, i);
+ if (irq == NO_IRQ) {
pr_err("%s: not enough interrupts specified\n",
np->full_name);
goto err;
}
- gtm->timers[i].irq = irq.start;
+ gtm->timers[i].irq = irq;
gtm->timers[i].gtm = gtm;
}
diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c
index c753258..2c9b52a 100644
--- a/arch/powerpc/sysdev/mpic_msgr.c
+++ b/arch/powerpc/sysdev/mpic_msgr.c
@@ -237,15 +237,13 @@ static int mpic_msgr_probe(struct platform_device *dev)
raw_spin_lock_init(&msgr->lock);
if (receive_mask & (1 << i)) {
- struct resource irq;
-
- if (of_irq_to_resource(np, irq_index, &irq) == NO_IRQ) {
+ msgr->irq = irq_of_parse_and_map(np, irq_index);
+ if (msgr->irq == NO_IRQ) {
dev_err(&dev->dev,
"Missing interrupt specifier");
kfree(msgr);
return -EFAULT;
}
- msgr->irq = irq.start;
irq_index += 1;
} else {
msgr->irq = NO_IRQ;
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 26438cd..c8224da 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -419,7 +419,7 @@ static int caam_probe(struct platform_device *pdev)
topregs = (struct caam_full __iomem *)ctrl;
/* Get the IRQ of the controller (for security violations only) */
- ctrlpriv->secvio_irq = of_irq_to_resource(nprop, 0, NULL);
+ ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0);
/*
* Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 105ba4d..517a16d 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -403,7 +403,7 @@ int caam_jr_probe(struct platform_device *pdev, struct device_node *np,
dma_set_mask(jrdev, DMA_BIT_MASK(32));
/* Identify the interrupt */
- jrpriv->irq = of_irq_to_resource(np, 0, NULL);
+ jrpriv->irq = irq_of_parse_and_map(np, 0);
/* Now do the platform independent part */
error = caam_jr_init(jrdev); /* now turn on hardware */
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 8bdde57..e28104b 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -1818,7 +1818,7 @@ static int omap_sham_get_res_of(struct omap_sham_dev *dd,
goto err;
}
- dd->irq = of_irq_to_resource(node, 0, NULL);
+ dd->irq = irq_of_parse_and_map(node, 0);
if (!dd->irq) {
dev_err(dev, "can't translate OF irq value\n");
err = -EINVAL;
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index b2b8aa9..3e5ea2c 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -447,7 +447,7 @@ static int cpm_i2c_setup(struct cpm_i2c *cpm)
init_waitqueue_head(&cpm->i2c_wait);
- cpm->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
+ cpm->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
if (!cpm->irq)
return -EINVAL;
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index 4b7662a..36f7b95 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -235,12 +235,12 @@ static void sxps2_close(struct serio *pserio)
*/
static int xps2_of_probe(struct platform_device *ofdev)
{
- struct resource r_irq; /* Interrupt resources */
struct resource r_mem; /* IO mem resources */
struct xps2data *drvdata;
struct serio *serio;
struct device *dev = &ofdev->dev;
resource_size_t remap_size, phys_addr;
+ unsigned int irq;
int error;
dev_info(dev, "Device Tree Probing \'%s\'\n",
@@ -254,7 +254,8 @@ static int xps2_of_probe(struct platform_device *ofdev)
}
/* Get IRQ for the device */
- if (!of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq)) {
+ irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
+ if (!irq) {
dev_err(dev, "no IRQ found\n");
return -ENODEV;
}
@@ -267,7 +268,7 @@ static int xps2_of_probe(struct platform_device *ofdev)
}
spin_lock_init(&drvdata->lock);
- drvdata->irq = r_irq.start;
+ drvdata->irq = irq;
drvdata->serio = serio;
drvdata->dev = dev;
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index 9e16014..d087852 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -628,12 +628,12 @@ static const struct net_device_ops arc_emac_netdev_ops = {
static int arc_emac_probe(struct platform_device *pdev)
{
- struct resource res_regs, res_irq;
+ struct resource res_regs;
struct device_node *phy_node;
struct arc_emac_priv *priv;
struct net_device *ndev;
const char *mac_addr;
- unsigned int id, clock_frequency;
+ unsigned int id, clock_frequency, irq;
int err;
if (!pdev->dev.of_node)
@@ -661,8 +661,8 @@ static int arc_emac_probe(struct platform_device *pdev)
}
/* Get IRQ from device tree */
- err = of_irq_to_resource(pdev->dev.of_node, 0, &res_irq);
- if (!err) {
+ irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ if (!irq) {
dev_err(&pdev->dev, "failed to retrieve <irq> value from device tree\n");
return -ENODEV;
}
@@ -711,7 +711,7 @@ static int arc_emac_probe(struct platform_device *pdev)
goto out;
}
- ndev->irq = res_irq.start;
+ ndev->irq = irq;
dev_info(&pdev->dev, "IRQ is %d\n", ndev->irq);
/* Register interrupt handler for device */
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
index 7583a95..10f781d 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
@@ -88,7 +88,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
struct fs_platform_info *fpi = fep->fpi;
int ret = -EINVAL;
- fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
+ fep->interrupt = irq_of_parse_and_map(ofdev->dev.of_node, 0);
if (fep->interrupt == NO_IRQ)
goto out;
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
index 9ae6cdb..53a0c23 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
@@ -98,7 +98,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
{
struct platform_device *ofdev = to_platform_device(fep->dev);
- fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
+ fep->interrupt = irq_of_parse_and_map(ofdev->dev.of_node, 0);
if (fep->interrupt == NO_IRQ)
return -EINVAL;
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
index 22a02a7..631f098 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
@@ -98,7 +98,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
{
struct platform_device *ofdev = to_platform_device(fep->dev);
- fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
+ fep->interrupt = irq_of_parse_and_map(ofdev->dev.of_node, 0);
if (fep->interrupt == NO_IRQ)
return -EINVAL;
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index b8f1103..3197d55 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -687,7 +687,7 @@ static int of_fsl_espi_probe(struct platform_device *ofdev)
struct device_node *np = ofdev->dev.of_node;
struct spi_master *master;
struct resource mem;
- struct resource irq;
+ unsigned int irq;
int ret = -ENOMEM;
ret = of_mpc8xxx_spi_probe(ofdev);
@@ -702,13 +702,13 @@ static int of_fsl_espi_probe(struct platform_device *ofdev)
if (ret)
goto err;
- ret = of_irq_to_resource(np, 0, &irq);
+ irq = irq_of_parse_and_map(np, 0);
if (!ret) {
ret = -EINVAL;
goto err;
}
- master = fsl_espi_probe(dev, &mem, irq.start);
+ master = fsl_espi_probe(dev, &mem, irq);
if (IS_ERR(master)) {
ret = PTR_ERR(master);
goto err;
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index 1a535f7..6957f445 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -1207,7 +1207,7 @@ static int cpm_uart_init_port(struct device_node *np,
pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize;
spin_lock_init(&pinfo->port.lock);
- pinfo->port.irq = of_irq_to_resource(np, 0, NULL);
+ pinfo->port.irq = irq_of_parse_and_map(np, 0);
if (pinfo->port.irq == NO_IRQ) {
ret = -EINVAL;
goto out_pram;
--
1.8.4
^ permalink raw reply related
* [PATCH v2 03/10] irqdomain: Introduce __irq_create_mapping()
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
This is a version of irq_create_mapping() that propagates the precise
error code instead of returning 0 for all errors. It will be used in
subsequent patches to allow further propagation of error codes.
To avoid code duplication, implement irq_create_mapping() as a wrapper
around the new __irq_create_mapping().
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
kernel/irq/irqdomain.c | 59 +++++++++++++++++++++++++++++++++-----------------
1 file changed, 39 insertions(+), 20 deletions(-)
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 706724e..d2a3b01 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -374,30 +374,21 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
}
EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
-/**
- * irq_create_mapping() - Map a hardware interrupt into linux irq space
- * @domain: domain owning this hardware interrupt or NULL for default domain
- * @hwirq: hardware irq number in that domain space
- *
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * irq number.
- * If the sense/trigger is to be specified, set_irq_type() should be called
- * on the number returned from that call.
- */
-unsigned int irq_create_mapping(struct irq_domain *domain,
- irq_hw_number_t hwirq)
+static int __irq_create_mapping(struct irq_domain *domain,
+ irq_hw_number_t hwirq, unsigned int *virqp)
{
- unsigned int hint;
- int virq;
+ unsigned int hint, virq;
+ int ret;
- pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
+ pr_debug("__irq_create_mapping(0x%p, 0x%lx, %p)\n", domain, hwirq,
+ virqp);
/* Look for default domain if nececssary */
if (domain == NULL)
domain = irq_default_domain;
if (domain == NULL) {
WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
- return 0;
+ return -ENODEV;
}
pr_debug("-> using domain @%p\n", domain);
@@ -405,7 +396,11 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
virq = irq_find_mapping(domain, hwirq);
if (virq) {
pr_debug("-> existing mapping on virq %d\n", virq);
- return virq;
+
+ if (virqp)
+ *virqp = virq;
+
+ return 0;
}
/* Allocate a virtual interrupt number */
@@ -417,17 +412,41 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
if (virq <= 0) {
pr_debug("-> virq allocation failed\n");
- return 0;
+ return virq ? : -ENOSPC;
}
- if (irq_domain_associate(domain, virq, hwirq)) {
+ ret = irq_domain_associate(domain, virq, hwirq);
+ if (ret) {
irq_free_desc(virq);
- return 0;
+ return ret;
}
pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
hwirq, of_node_full_name(domain->of_node), virq);
+ if (virqp)
+ *virqp = virq;
+
+ return 0;
+}
+/**
+ * irq_create_mapping() - Map a hardware interrupt into linux irq space
+ * @domain: domain owning this hardware interrupt or NULL for default domain
+ * @hwirq: hardware irq number in that domain space
+ *
+ * Only one mapping per hardware interrupt is permitted. Returns a linux
+ * irq number.
+ * If the sense/trigger is to be specified, set_irq_type() should be called
+ * on the number returned from that call.
+ */
+unsigned int irq_create_mapping(struct irq_domain *domain,
+ irq_hw_number_t hwirq)
+{
+ unsigned int virq;
+
+ if (__irq_create_mapping(domain, hwirq, &virq))
+ return 0;
+
return virq;
}
EXPORT_SYMBOL_GPL(irq_create_mapping);
--
1.8.4
^ permalink raw reply related
* [PATCH v2 04/10] irqdomain: Return errors from irq_create_of_mapping()
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
Instead of returning 0 for all errors, allow the precise error code to
be propagated. This will be used in subsequent patches to allow further
propagation of error codes.
The interrupt number corresponding to the new mapping is returned in an
output parameter so that the return value is reserved to signal success
(== 0) or failure (< 0).
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- convert existing callers instead of using compatible wrapper
arch/arm/mach-integrator/pci_v3.c | 8 ++++++--
arch/microblaze/pci/pci-common.c | 6 ++++--
arch/mips/pci/fixup-lantiq.c | 12 +++++++----
arch/mips/pci/pci-rt3883.c | 9 +++++----
arch/powerpc/kernel/pci-common.c | 7 +++++--
arch/powerpc/platforms/cell/celleb_scc_sio.c | 8 +++++---
arch/powerpc/platforms/cell/spu_manage.c | 6 +++---
arch/powerpc/platforms/fsl_uli1575.c | 7 +++----
arch/powerpc/platforms/pseries/event_sources.c | 12 ++++++-----
arch/x86/kernel/devicetree.c | 11 +++++-----
drivers/pci/host/pci-mvebu.c | 9 +++++++--
include/linux/of_irq.h | 6 +++---
kernel/irq/irqdomain.c | 28 ++++++++++++++++----------
13 files changed, 78 insertions(+), 51 deletions(-)
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index bef1005..aa0f867 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -847,8 +847,12 @@ static int __init pci_v3_map_irq_dt(const struct pci_dev *dev, u8 slot, u8 pin)
return 0;
}
- return irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
+ ret = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size, &virq);
+ if (ret)
+ return 0;
+
+ return virq;
}
static int __init pci_v3_dtprobe(struct platform_device *pdev,
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 1b93bf0..80b6e0f 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -246,8 +246,10 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
oirq.size, oirq.specifier[0], oirq.specifier[1],
of_node_full_name(oirq.controller));
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
+ ret = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size, &virq);
+ if (ret)
+ virq = 0;
}
if (!virq) {
pr_debug(" Failed to map !\n");
diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c
index 6c829df..dfe7bf1 100644
--- a/arch/mips/pci/fixup-lantiq.c
+++ b/arch/mips/pci/fixup-lantiq.c
@@ -26,15 +26,19 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct of_irq dev_irq;
- int irq;
+ unsigned int irq;
+ int err;
if (of_irq_map_pci(dev, &dev_irq)) {
dev_err(&dev->dev, "trying to map irq for unknown slot:%d pin:%d\n",
slot, pin);
return 0;
}
- irq = irq_create_of_mapping(dev_irq.controller, dev_irq.specifier,
- dev_irq.size);
- dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, irq);
+ err = irq_create_of_mapping(dev_irq.controller, dev_irq.specifier,
+ dev_irq.size, &irq);
+ if (err)
+ return 0;
+
+ dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%u\n", slot, pin, irq);
return irq;
}
diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c
index 95c9d41..79b49b5 100644
--- a/arch/mips/pci/pci-rt3883.c
+++ b/arch/mips/pci/pci-rt3883.c
@@ -584,8 +584,8 @@ err_put_intc_node:
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct of_irq dev_irq;
+ unsigned int irq = 0;
int err;
- int irq;
err = of_irq_map_pci(dev, &dev_irq);
if (err) {
@@ -594,11 +594,12 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return 0;
}
- irq = irq_create_of_mapping(dev_irq.controller,
+ err = irq_create_of_mapping(dev_irq.controller,
dev_irq.specifier,
- dev_irq.size);
+ dev_irq.size,
+ &irq);
- if (irq == 0)
+ if (err)
pr_crit("pci %s: no irq found for pin %u\n",
pci_name((struct pci_dev *) dev), pin);
else
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 905a24b..ae71b14 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -230,6 +230,7 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
{
struct of_irq oirq;
unsigned int virq;
+ int ret;
pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev));
@@ -266,8 +267,10 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
oirq.size, oirq.specifier[0], oirq.specifier[1],
of_node_full_name(oirq.controller));
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
+ ret = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size, &virq);
+ if (ret)
+ virq = NO_IRQ;
}
if(virq == NO_IRQ) {
pr_debug(" Failed to map !\n");
diff --git a/arch/powerpc/platforms/cell/celleb_scc_sio.c b/arch/powerpc/platforms/cell/celleb_scc_sio.c
index 9c339ec..94b771e 100644
--- a/arch/powerpc/platforms/cell/celleb_scc_sio.c
+++ b/arch/powerpc/platforms/cell/celleb_scc_sio.c
@@ -43,7 +43,7 @@ static int __init txx9_serial_init(void)
{
extern int early_serial_txx9_setup(struct uart_port *port);
struct device_node *node;
- int i;
+ int i, err;
struct uart_port req;
struct of_irq irq;
struct resource res;
@@ -66,8 +66,10 @@ static int __init txx9_serial_init(void)
#ifdef CONFIG_SERIAL_TXX9_CONSOLE
req.membase = ioremap(req.mapbase, 0x24);
#endif
- req.irq = irq_create_of_mapping(irq.controller,
- irq.specifier, irq.size);
+ err = irq_create_of_mapping(irq.controller,
+ irq.specifier, irq.size, &req.irq);
+ if (err)
+ req.irq = 0;
req.flags |= UPF_IOREMAP | UPF_BUGGY_UART
/*HAVE_CTS_LINE*/;
req.uartclk = 83300000;
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c
index 2bb6977..b78c7a4 100644
--- a/arch/powerpc/platforms/cell/spu_manage.c
+++ b/arch/powerpc/platforms/cell/spu_manage.c
@@ -190,9 +190,9 @@ static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
ret = -EINVAL;
pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0],
oirq.controller->full_name);
- spu->irqs[i] = irq_create_of_mapping(oirq.controller,
- oirq.specifier, oirq.size);
- if (spu->irqs[i] == NO_IRQ) {
+ ret = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size, &spu->irqs[i]);
+ if (ret) {
pr_debug("spu_new: failed to map it !\n");
goto err;
}
diff --git a/arch/powerpc/platforms/fsl_uli1575.c b/arch/powerpc/platforms/fsl_uli1575.c
index 92ac9b5..575b215 100644
--- a/arch/powerpc/platforms/fsl_uli1575.c
+++ b/arch/powerpc/platforms/fsl_uli1575.c
@@ -322,7 +322,7 @@ static void hpcd_final_uli5288(struct pci_dev *dev)
struct pci_controller *hose = pci_bus_to_host(dev->bus);
struct device_node *hosenode = hose ? hose->dn : NULL;
struct of_irq oirq;
- int virq, pin = 2;
+ int pin = 2;
u32 laddr[3];
if (!machine_is(mpc86xx_hpcd))
@@ -334,9 +334,8 @@ static void hpcd_final_uli5288(struct pci_dev *dev)
laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8);
laddr[1] = laddr[2] = 0;
of_irq_map_raw(hosenode, &pin, 1, laddr, &oirq);
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
- dev->irq = virq;
+ irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size,
+ &dev->irq);
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, hpcd_quirk_uli1575);
diff --git a/arch/powerpc/platforms/pseries/event_sources.c b/arch/powerpc/platforms/pseries/event_sources.c
index 2605c31..4367fdd 100644
--- a/arch/powerpc/platforms/pseries/event_sources.c
+++ b/arch/powerpc/platforms/pseries/event_sources.c
@@ -24,7 +24,7 @@ void request_event_sources_irqs(struct device_node *np,
irq_handler_t handler,
const char *name)
{
- int i, index, count = 0;
+ int i, index, err, count = 0;
struct of_irq oirq;
const u32 *opicprop;
unsigned int opicplen;
@@ -59,10 +59,12 @@ void request_event_sources_irqs(struct device_node *np,
index++) {
if (count > 15)
break;
- virqs[count] = irq_create_of_mapping(oirq.controller,
- oirq.specifier,
- oirq.size);
- if (virqs[count] == NO_IRQ) {
+
+ err = irq_create_of_mapping(oirq.controller,
+ oirq.specifier,
+ oirq.size,
+ &virqs[count]);
+ if (err) {
pr_err("event-sources: Unable to allocate "
"interrupt number for %s\n",
np->full_name);
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index 376dc78..7adede6 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -106,7 +106,6 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
static int x86_of_pci_irq_enable(struct pci_dev *dev)
{
struct of_irq oirq;
- u32 virq;
int ret;
u8 pin;
@@ -120,11 +119,11 @@ static int x86_of_pci_irq_enable(struct pci_dev *dev)
if (ret)
return ret;
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
- if (virq == 0)
- return -EINVAL;
- dev->irq = virq;
+ ret = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size,
+ &dev->irq);
+ if (ret)
+ return ret;
+
return 0;
}
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index 77f8a7c..7773a17 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -656,14 +656,19 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
static int mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct of_irq oirq;
+ unsigned int virq;
int ret;
ret = of_irq_map_pci(dev, &oirq);
if (ret)
return ret;
- return irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
+ ret = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size,
+ &virq);
+ if (ret)
+ return 0;
+
+ return virq;
}
static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index 535cecf..138266d 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -63,9 +63,9 @@ extern int of_irq_map_raw(struct device_node *parent, const __be32 *intspec,
struct of_irq *out_irq);
extern int of_irq_map_one(struct device_node *device, int index,
struct of_irq *out_irq);
-extern unsigned int irq_create_of_mapping(struct device_node *controller,
- const u32 *intspec,
- unsigned int intsize);
+extern int irq_create_of_mapping(struct device_node *controller,
+ const u32 *intspec, unsigned int intsize,
+ unsigned int *virqp);
extern int of_irq_to_resource(struct device_node *dev, int index,
struct resource *r);
extern int of_irq_count(struct device_node *dev);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index d2a3b01..5f8401c 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -484,40 +484,46 @@ int irq_create_strict_mappings(struct irq_domain *domain, unsigned int irq_base,
}
EXPORT_SYMBOL_GPL(irq_create_strict_mappings);
-unsigned int irq_create_of_mapping(struct device_node *controller,
- const u32 *intspec, unsigned int intsize)
+int irq_create_of_mapping(struct device_node *controller, const u32 *intspec,
+ unsigned int intsize, unsigned int *virqp)
{
+ unsigned int type = IRQ_TYPE_NONE;
struct irq_domain *domain;
irq_hw_number_t hwirq;
- unsigned int type = IRQ_TYPE_NONE;
unsigned int virq;
+ int ret;
domain = controller ? irq_find_host(controller) : irq_default_domain;
if (!domain) {
pr_warn("no irq domain found for %s !\n",
of_node_full_name(controller));
- return 0;
+ return -EPROBE_DEFER;
}
/* If domain has no translation, then we assume interrupt line */
if (domain->ops->xlate == NULL)
hwirq = intspec[0];
else {
- if (domain->ops->xlate(domain, controller, intspec, intsize,
- &hwirq, &type))
- return 0;
+ ret = domain->ops->xlate(domain, controller, intspec, intsize,
+ &hwirq, &type);
+ if (ret)
+ return ret;
}
/* Create mapping */
- virq = irq_create_mapping(domain, hwirq);
- if (!virq)
- return virq;
+ ret = __irq_create_mapping(domain, hwirq, &virq);
+ if (ret)
+ return ret;
/* Set type if specified and different than the current one */
if (type != IRQ_TYPE_NONE &&
type != irq_get_trigger_type(virq))
irq_set_irq_type(virq, type);
- return virq;
+
+ if (virqp)
+ *virqp = virq;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(irq_create_of_mapping);
--
1.8.4
^ permalink raw reply related
* [PATCH v2 05/10] of/irq: Introduce __irq_of_parse_and_map()
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
This is a version of irq_of_parse_and_map() that propagates the precise
error code instead of returning 0 for all errors. It will be used in
subsequent patches to allow further propagation of error codes.
To avoid code duplication, implement irq_of_parse_and_map() as a static
inline wrapper around the new __irq_of_parse_and_map(). Note that this
is somewhat complicated by the fact that SPARC implement its own version
of irq_of_parse_and_map(). Make SPARC implement __irq_of_parse_and_map()
so that the static inline wrapper can be used on all platforms.
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- rename of_irq_get() to __irq_of_parse_and_map()
arch/sparc/kernel/of_device_common.c | 12 ++++++++----
drivers/of/irq.c | 18 ++++++++++++------
include/linux/of_irq.h | 19 ++++++++++++++-----
3 files changed, 34 insertions(+), 15 deletions(-)
diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c
index de199bf..a69559f 100644
--- a/arch/sparc/kernel/of_device_common.c
+++ b/arch/sparc/kernel/of_device_common.c
@@ -11,16 +11,20 @@
#include "of_device_common.h"
-unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+int __irq_of_parse_and_map(struct device_node *node, unsigned int index,
+ unsigned int *virqp)
{
struct platform_device *op = of_find_device_by_node(node);
if (!op || index >= op->archdata.num_irqs)
- return 0;
+ return !op ? -ENODEV : -EINVAL;
- return op->archdata.irqs[index];
+ if (virqp)
+ *virqp = op->archdata.irqs[index];
+
+ return 0;
}
-EXPORT_SYMBOL(irq_of_parse_and_map);
+EXPORT_SYMBOL(__irq_of_parse_and_map);
int of_address_to_resource(struct device_node *node, int index,
struct resource *r)
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 5f44388..6ad46fd 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -27,24 +27,30 @@
#include <linux/slab.h>
/**
- * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
+ * __irq_of_parse_and_map - Parse and map an interrupt into linux virq space
* @dev: Device node of the device whose interrupt is to be mapped
* @index: Index of the interrupt to map
+ * @virqp: Linux interrupt number filled by this function
*
* This function is a wrapper that chains of_irq_map_one() and
* irq_create_of_mapping() to make things easier to callers
+ *
+ * Returns 0 on success or a negative error code on failure.
*/
-unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
+int __irq_of_parse_and_map(struct device_node *dev, unsigned int index,
+ unsigned int *virqp)
{
struct of_irq oirq;
+ int ret;
- if (of_irq_map_one(dev, index, &oirq))
- return 0;
+ ret = of_irq_map_one(dev, index, &oirq);
+ if (ret)
+ return ret;
return irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
+ oirq.size, virqp);
}
-EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
+EXPORT_SYMBOL_GPL(__irq_of_parse_and_map);
/**
* of_irq_find_parent - Given a device node, find its interrupt parent node
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index 138266d..11da949 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -11,11 +11,12 @@ struct of_irq;
#include <linux/of.h>
/*
- * irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC
+ * __irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC
* implements it differently. However, the prototype is the same for all,
* so declare it here regardless of the CONFIG_OF_IRQ setting.
*/
-extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
+extern int __irq_of_parse_and_map(struct device_node *node, unsigned int index,
+ unsigned int *virqp);
#if defined(CONFIG_OF_IRQ)
/**
@@ -78,10 +79,11 @@ extern void of_irq_init(const struct of_device_id *matches);
#endif /* CONFIG_OF_IRQ */
#else /* !CONFIG_OF */
-static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
- int index)
+static inline int __irq_of_parse_and_map(struct device_node *dev,
+ unsigned int index,
+ unsigned int *virqp)
{
- return 0;
+ return -ENOSYS;
}
static inline void *of_irq_find_parent(struct device_node *child)
@@ -90,4 +92,11 @@ static inline void *of_irq_find_parent(struct device_node *child)
}
#endif /* !CONFIG_OF */
+static inline unsigned int irq_of_parse_and_map(struct device_node *node,
+ unsigned int index)
+{
+ unsigned int irq;
+ return (__irq_of_parse_and_map(node, index, &irq) < 0) ? 0 : irq;
+}
+
#endif /* __OF_IRQ_H */
--
1.8.4
^ permalink raw reply related
* [PATCH v2 06/10] of/irq: Return errors from of_irq_to_resource()
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
Update of_irq_to_resource() to return 0 on success and a negative error
code on failure. This allows the precise nature of the failure to be
determined in the caller and errors to be propagated appropriately.
While at it, make the index parameter unsigned. Accessing negative
indices is invalid, so we might as well enforce that by using the right
data type.
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- convert existing callers instead of using compatible wrapper
arch/powerpc/platforms/83xx/mpc832x_rdb.c | 2 +-
drivers/net/ethernet/marvell/mv643xx_eth.c | 5 +++--
drivers/of/irq.c | 14 +++++++++++---
include/linux/of_irq.h | 2 +-
4 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
index eff5baa..b198e73 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -89,7 +89,7 @@ static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
goto err;
ret = of_irq_to_resource(np, 0, &res[1]);
- if (ret == NO_IRQ)
+ if (ret)
goto err;
pdev = platform_device_alloc("mpc83xx_spi", i);
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 7fb5677..bd713bd 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -2489,9 +2489,10 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
ppd.shared = pdev;
memset(&res, 0, sizeof(res));
- if (!of_irq_to_resource(pnp, 0, &res)) {
+ ret = of_irq_to_resource(pnp, 0, &res);
+ if (ret) {
dev_err(&pdev->dev, "missing interrupt on %s\n", pnp->name);
- return -EINVAL;
+ return ret;
}
if (of_property_read_u32(pnp, "reg", &ppd.port_number)) {
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 6ad46fd..e4f38c0 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -341,10 +341,18 @@ EXPORT_SYMBOL_GPL(of_irq_map_one);
* @dev: pointer to device tree node
* @index: zero-based index of the irq
* @r: pointer to resource structure to return result into.
+ *
+ * Returns zero on success or a negative error code on failure.
*/
-int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
+int of_irq_to_resource(struct device_node *dev, unsigned int index,
+ struct resource *r)
{
- int irq = irq_of_parse_and_map(dev, index);
+ unsigned int irq;
+ int ret;
+
+ ret = __irq_of_parse_and_map(dev, index, &irq);
+ if (ret)
+ return ret;
/* Only dereference the resource if both the
* resource and the irq are valid. */
@@ -364,7 +372,7 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
r->name = name ? name : dev->full_name;
}
- return irq;
+ return 0;
}
EXPORT_SYMBOL_GPL(of_irq_to_resource);
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index 11da949..6d62b73 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -67,7 +67,7 @@ extern int of_irq_map_one(struct device_node *device, int index,
extern int irq_create_of_mapping(struct device_node *controller,
const u32 *intspec, unsigned int intsize,
unsigned int *virqp);
-extern int of_irq_to_resource(struct device_node *dev, int index,
+extern int of_irq_to_resource(struct device_node *dev, unsigned int index,
struct resource *r);
extern int of_irq_count(struct device_node *dev);
extern int of_irq_to_resource_table(struct device_node *dev,
--
1.8.4
^ permalink raw reply related
* [PATCH v2 07/10] of/irq: Propagate errors in of_irq_to_resource_table()
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
Now that all helpers return precise error codes, this function can
propagate these errors to the caller properly.
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- return 0 on success or a negative error code on failure
- convert callers to new calling convention
arch/mips/lantiq/irq.c | 2 +-
arch/mips/lantiq/xway/gptu.c | 6 ++++--
drivers/of/irq.c | 14 ++++++++------
drivers/tty/serial/lantiq.c | 2 +-
4 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index eb3e186..5bb7ee6 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -389,7 +389,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
ret = of_irq_to_resource_table(eiu_node,
ltq_eiu_irq, exin_avail);
- if (ret != exin_avail)
+ if (ret < 0)
panic("failed to load external irq resources\n");
if (request_mem_region(res.start, resource_size(&res),
diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c
index 850821d..0c4b134 100644
--- a/arch/mips/lantiq/xway/gptu.c
+++ b/arch/mips/lantiq/xway/gptu.c
@@ -137,10 +137,12 @@ static int gptu_probe(struct platform_device *pdev)
{
struct clk *clk;
struct resource *res;
+ int ret;
- if (of_irq_to_resource_table(pdev->dev.of_node, irqres, 6) != 6) {
+ ret = of_irq_to_resource_table(pdev->dev.of_node, irqres, 6);
+ if (ret < 0) {
dev_err(&pdev->dev, "Failed to get IRQ list\n");
- return -EINVAL;
+ return ret;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index e4f38c0..6d7f824 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -397,18 +397,20 @@ int of_irq_count(struct device_node *dev)
* @res: array of resources to fill in
* @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
*
- * Returns the size of the filled in table (up to @nr_irqs).
+ * Returns 0 on success or a negative error code on failure.
*/
int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
int nr_irqs)
{
- int i;
+ int i, ret;
- for (i = 0; i < nr_irqs; i++, res++)
- if (!of_irq_to_resource(dev, i, res))
- break;
+ for (i = 0; i < nr_irqs; i++, res++) {
+ ret = of_irq_to_resource(dev, i, res);
+ if (ret < 0)
+ return ret;
+ }
- return i;
+ return 0;
}
EXPORT_SYMBOL_GPL(of_irq_to_resource_table);
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 88d01e0..e59efdc 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -686,7 +686,7 @@ lqasc_probe(struct platform_device *pdev)
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ret = of_irq_to_resource_table(node, irqres, 3);
- if (!mmres || (ret != 3)) {
+ if (!mmres || (ret < 0)) {
dev_err(&pdev->dev,
"failed to get memory/irq for serial port\n");
return -ENODEV;
--
1.8.4
^ permalink raw reply related
* [PATCH v2 08/10] of/platform: Resolve interrupt references at probe time
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
Interrupt references are currently resolved very early (when a device is
created). This has the disadvantage that it will fail in cases where the
interrupt parent hasn't been probed and no IRQ domain for it has been
registered yet. To work around that various drivers use explicit
initcall ordering to force interrupt parents to be probed before devices
that need them are created. That's error prone and doesn't always work.
If a platform device uses an interrupt line connected to a different
platform device (such as a GPIO controller), both will be created in the
same batch, and the GPIO controller won't have been probed by its driver
when the depending platform device is created. Interrupt resolution will
fail in that case.
Another common workaround is for drivers to explicitly resolve interrupt
references at probe time. This is suboptimal, however, because it will
require every driver to duplicate the code.
This patch adds support for late interrupt resolution to the platform
driver core, by resolving the references right before a device driver's
.probe() function will be called. This not only delays the resolution
until a much later time (giving interrupt parents a better chance of
being probed in the meantime), but it also allows the platform driver
core to queue the device for deferred probing if the interrupt parent
hasn't registered its IRQ domain yet.
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- split off IRQ parsing into separate function to make code flow simpler
- add comments to point out some aspects of the implementation
- make code idempotent (as pointed out by Grygorii Strashko
drivers/base/platform.c | 4 ++
drivers/of/platform.c | 107 +++++++++++++++++++++++++++++++++++++++++---
include/linux/of_platform.h | 7 +++
3 files changed, 112 insertions(+), 6 deletions(-)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 4f8bef3..8dcf835 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -481,6 +481,10 @@ static int platform_drv_probe(struct device *_dev)
struct platform_device *dev = to_platform_device(_dev);
int ret;
+ ret = of_platform_probe(dev);
+ if (ret)
+ return ret;
+
if (ACPI_HANDLE(_dev))
acpi_dev_pm_attach(_dev, true);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 9b439ac..df6d56e 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -142,7 +142,7 @@ struct platform_device *of_device_alloc(struct device_node *np,
struct device *parent)
{
struct platform_device *dev;
- int rc, i, num_reg = 0, num_irq;
+ int rc, i, num_reg = 0;
struct resource *res, temp_res;
dev = platform_device_alloc("", -1);
@@ -153,23 +153,21 @@ struct platform_device *of_device_alloc(struct device_node *np,
if (of_can_translate_address(np))
while (of_address_to_resource(np, num_reg, &temp_res) == 0)
num_reg++;
- num_irq = of_irq_count(np);
/* Populate the resource table */
- if (num_irq || num_reg) {
- res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
+ if (num_reg) {
+ res = kzalloc(sizeof(*res) * num_reg, GFP_KERNEL);
if (!res) {
platform_device_put(dev);
return NULL;
}
- dev->num_resources = num_reg + num_irq;
+ dev->num_resources = num_reg;
dev->resource = res;
for (i = 0; i < num_reg; i++, res++) {
rc = of_address_to_resource(np, i, res);
WARN_ON(rc);
}
- WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
}
dev->dev.of_node = of_node_get(np);
@@ -490,4 +488,101 @@ int of_platform_populate(struct device_node *root,
return rc;
}
EXPORT_SYMBOL_GPL(of_platform_populate);
+
+/**
+ * of_platform_parse_irq() - parse interrupt resource from device node
+ * @pdev: pointer to platform device
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int of_platform_parse_irq(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ unsigned int num_res = pdev->num_resources;
+ struct resource *res = pdev->resource;
+ unsigned int num_irq, num, c;
+ int ret = 0;
+
+ num_irq = of_irq_count(pdev->dev.of_node);
+ if (!num_irq)
+ return 0;
+
+ /*
+ * Deferred probing may cause this function to be called multiple
+ * times, so check if all interrupts have been parsed already and
+ * return early.
+ */
+ for (c = 0; c < num_irq; c++)
+ if (platform_get_irq(pdev, c) < 0)
+ break;
+
+ if (c == num_irq)
+ return 0;
+
+ num = num_res + num_irq;
+
+ /*
+ * Note that in case we're called twice on the same device (due to
+ * deferred probing for example) this will simply be a nop because
+ * krealloc() returns the input pointer if the size of the memory
+ * block that it points to is larger than or equal to the new size
+ * being requested.
+ */
+ res = krealloc(res, num * sizeof(*res), GFP_KERNEL);
+ if (!res)
+ return -ENOMEM;
+
+ pdev->resource = res;
+ res += num_res;
+
+ /*
+ * It is possible for this to fail. If so, not that the number of
+ * resources is not updated, so that the next call to this function
+ * will parse all interrupts again. Otherwise we can't keep track of
+ * how many we've parsed so far.
+ */
+ ret = of_irq_to_resource_table(np, res, num_irq);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * All interrupts are guaranteed to have been parsed and stored in
+ * the resource table, so the number of resources can now safely be
+ * updated.
+ */
+ pdev->num_resources += num_irq;
+
+ return 0;
+}
+
+/**
+ * of_platform_probe() - OF specific initialization at probe time
+ * @pdev: pointer to a platform device
+ *
+ * This function is called by the driver core to perform devicetree-specific
+ * setup for a given platform device at probe time. If a device's resources
+ * as specified in the device tree are not available yet, this function can
+ * return -EPROBE_DEFER and cause the device to be probed again later, when
+ * other drivers that potentially provide the missing resources have been
+ * probed in turn.
+ *
+ * Note that because of the above, all code executed by this function must
+ * be prepared to be run multiple times on the same device (i.e. it must be
+ * idempotent).
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int of_platform_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ if (!pdev->dev.of_node)
+ return 0;
+
+ ret = of_platform_parse_irq(pdev);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
#endif /* CONFIG_OF_ADDRESS */
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 05cb4a9..92fc4f6 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -72,6 +72,8 @@ extern int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent);
+
+extern int of_platform_probe(struct platform_device *pdev);
#else
static inline int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
@@ -80,6 +82,11 @@ static inline int of_platform_populate(struct device_node *root,
{
return -ENODEV;
}
+
+static inline int of_platform_probe(struct platform_device *pdev)
+{
+ return 0;
+}
#endif
#endif /* _LINUX_OF_PLATFORM_H */
--
1.8.4
^ permalink raw reply related
* [PATCH v2 09/10] of/i2c: Resolve interrupt references at probe time
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
Instead of resolving interrupt references at device creation time, delay
resolution until probe time. At device creation time, there is nothing
that can be done if an interrupt parent isn't ready yet, and the device
will end up with an invalid interrupt number (0).
If the interrupt reference is resolved at probe time, the device's probe
can be deferred, so that it's interrupt resolution can be retried after
more devices (possibly including its interrupt parent) have been probed.
However, individual drivers shouldn't be required to do that themselves,
over and over again, so this commit implements this functionality within
the I2C core.
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- use __irq_of_parse_and_map() instead of of_irq_get()
drivers/i2c/i2c-core.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 29d3f04..5b4f289 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -236,6 +236,22 @@ int i2c_recover_bus(struct i2c_adapter *adap)
return adap->bus_recovery_info->recover_bus(adap);
}
+static int of_i2c_probe(struct i2c_client *client)
+{
+ struct device_node *np = client->dev.of_node;
+ int ret;
+
+ /* skip if the device node specifies no interrupts */
+ if (of_get_property(np, "interrupts", NULL)) {
+ ret = __irq_of_parse_and_map(client->dev.of_node, 0,
+ &client->irq);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
@@ -254,6 +270,12 @@ static int i2c_device_probe(struct device *dev)
client->flags & I2C_CLIENT_WAKE);
dev_dbg(dev, "probe\n");
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ status = of_i2c_probe(client);
+ if (status)
+ return status;
+ }
+
status = driver->probe(client, i2c_match_id(driver->id_table, client));
if (status) {
client->driver = NULL;
@@ -1002,7 +1024,6 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
continue;
}
- info.irq = irq_of_parse_and_map(node, 0);
info.of_node = of_node_get(node);
info.archdata = &dev_ad;
@@ -1016,7 +1037,6 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
node->full_name);
of_node_put(node);
- irq_dispose_mapping(info.irq);
continue;
}
}
--
1.8.4
^ permalink raw reply related
* [PATCH v2 10/10] gpio: tegra: Use module_platform_driver()
From: Thierry Reding @ 2013-09-18 13:24 UTC (permalink / raw)
To: Rob Herring, Grant Likely, Greg Kroah-Hartman, Thomas Gleixner
Cc: linux-mips, Russell King, devicetree, linux-kernel, Ralf Baechle,
sparclinux, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-1-git-send-email-treding@nvidia.com>
With the driver core now resolving interrupt references at probe time,
it is no longer necessary to force explicit probe ordering using
initcalls.
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Note that there are potentially many more drivers that can be switched
to the generic module_*_driver() interfaces now that interrupts can be
resolved later and deferred probe should be able to handle all the
ordering issues.
drivers/gpio/gpio-tegra.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 9a62672..766e6ef 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -513,12 +513,7 @@ static struct platform_driver tegra_gpio_driver = {
},
.probe = tegra_gpio_probe,
};
-
-static int __init tegra_gpio_init(void)
-{
- return platform_driver_register(&tegra_gpio_driver);
-}
-postcore_initcall(tegra_gpio_init);
+module_platform_driver(tegra_gpio_driver);
#ifdef CONFIG_DEBUG_FS
--
1.8.4
^ permalink raw reply related
* mpc52xx_uart.c : Possible bug with TTY_OVERRUN and clear error condition?
From: Carlos Crisóstomo @ 2013-09-18 13:08 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 1691 bytes --]
First of all, sorry for my english (I'm spanish).
At our company, we work in various projects in control systems and
automation in industrial environment, mostly with embedded custom linux
distributions with Freescale PowerPC processors (MPC5200b, MPC5125,
P1022, MPC8536E...).
In one of our systems, we have a MPC5125 connected with an ARM Cortex
processor by serial port (ttyPSCX) using the standard mpc52xx_uart.c
driver. Suddently we have encountered a situation in serial
communicationes where
all the incoming serial traffic has a '\0' in the end of each serial
transmission.
Looking at the driver in our custom 2.6.33.7 kernel, the insertion of
the '\0' is in line 1308, on the Overrun condition(TTY_OVERRUN), but
looking at the code, this flag is never cleared (as they arein the line
1297 in "clear error condition")until there is some
other error condition like TTY_BREAK, TTY_PARITY, TTY_FRAME.
We have resolved thisissue adding a clear error condition after the
overrun increment in port->icount.overrun++; but perhaps this is not the
best solution(dirty hack).
It has been discuted in
http://linuxppc.10917.n7.nabble.com/mpc52xx-uart-c-Port-Overruns-td53175.html
for kernel 2.6.24too.
Maybe we can send you a patch for the next commit, or can anyone
evaluate it for the next release? As we can see, this is happening in
the latest release of the Linus kernel treetoo (3.11).
Thank you.
Regards,
--
Carlos Crisóstomo Vals
Operating System Design Director
Product Development
Arteche Smart-Grid
Sistemas Avanzados de Control S.A.
Colquide 6, Portal 2,
28230 Las Rozas - Madrid - Spain
carlos_DOT_crisostomo_AT_sacnet_DOT_es
www.sacnet.es
www.arteche.com
[-- Attachment #2: Type: text/html, Size: 10503 bytes --]
^ permalink raw reply
* Re: [PATCH v2 2/6] PCI/MSI: Factor out pci_get_msi_cap() interface
From: Tejun Heo @ 2013-09-18 14:22 UTC (permalink / raw)
To: Alexander Gordeev
Cc: Joerg Roedel, x86@kernel.org, linux-kernel@vger.kernel.org,
linux-ide@vger.kernel.org, Jan Beulich, linux-pci@vger.kernel.org,
Bjorn Helgaas, linuxppc-dev, Ingo Molnar
In-Reply-To: <20130918094759.GA2353@dhcp-26-207.brq.redhat.com>
Hello,
On Wed, Sep 18, 2013 at 11:48:00AM +0200, Alexander Gordeev wrote:
> On Wed, Sep 18, 2013 at 12:30:23AM +1000, Michael Ellerman wrote:
> > How about no?
> >
> > We have a small number of MSIs available, limited by hardware &
> > firmware, if we don't impose a quota then the first device that probes
> > will get most/all of the MSIs and other devices miss out.
>
> Out of curiosity - how pSeries has had done it without quotas before
> 448e2ca ("powerpc/pseries: Implement a quota system for MSIs")?
Hmmm... do we need to treat this any differently? If the platform
can't allocate full range of requested MSIs, just failing should be
enough regardless of why such allocation can't be met, no?
> > Anyway I don't see what problem you're trying to solve? I agree the
> > -ve/0/+ve return value pattern is ugly, but it's hardly the end of the
> > world.
>
> Well, the interface recently has been re-classified from "ugly" to
> "unnecessarily complex and actively harmful" in Tejun's words ;)
LOL. :)
> Indeed, I checked most of the drivers and it is incredible how people
> are creative in misusing the interface: from innocent pci_disable_msix()
> calls when if pci_enable_msix() failed to assuming MSI-Xs were enabled
> if pci_enable_msix() returned a positive value (apparently untested).
>
> Roughly third of the drivers just do not care and bail out once
> pci_enable_msix() has not succeeded. Not sure how many of these are
> mandated by the hardware.
Yeah, I mean, this type of interface is a trap. People have to
actively resist to avoid doing silly stuff which is a lot to ask.
> /*
> * Retrieving 'nvec' by means other than pci_msix_table_size()
> */
>
> rc = pci_get_msix_limit(pdev);
> if (rc < 0)
> return rc;
>
> /*
> * nvec = min(rc, nvec);
> */
>
> for (i = 0; i < nvec; i++)
> msix_entry[i].entry = i;
>
> rc = pci_enable_msix(pdev, msix_entry, nvec);
> if (rc)
> return rc;
I really think what we should do is
* Determine the number of MSIs the controller wants. Don't worry
about quotas or limits or anything. Just determine the number
necessary to enable enhanced interrupt handling.
* Try allocating that number of MSIs. If it fails, then just revert
to single interrupt mode. It's not the end of the world and mostly
guaranteed to work. Let's please not even try to do partial
multiple interrupts. I really don't think it's worth the risk or
complexity.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH v2 07/10] of/irq: Propagate errors in of_irq_to_resource_table()
From: Ralf Baechle @ 2013-09-18 14:23 UTC (permalink / raw)
To: Thierry Reding
Cc: devicetree, Russell King, linux-mips, Greg Kroah-Hartman,
linux-kernel, Rob Herring, sparclinux, Grant Likely,
Thomas Gleixner, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-8-git-send-email-treding@nvidia.com>
On Wed, Sep 18, 2013 at 03:24:49PM +0200, Thierry Reding wrote:
For the MIPS bits:
Acked-by: Ralf Baechle <ralf@linux-mips.org>
Ralf
^ permalink raw reply
* Re: [PATCH v2 04/10] irqdomain: Return errors from irq_create_of_mapping()
From: Ralf Baechle @ 2013-09-18 14:23 UTC (permalink / raw)
To: Thierry Reding
Cc: devicetree, Russell King, linux-mips, Greg Kroah-Hartman,
linux-kernel, Rob Herring, sparclinux, Grant Likely,
Thomas Gleixner, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1379510692-32435-5-git-send-email-treding@nvidia.com>
On Wed, Sep 18, 2013 at 03:24:46PM +0200, Thierry Reding wrote:
For the MIPS bits:
Acked-by: Ralf Baechle <ralf@linux-mips.org>
Ralf
^ permalink raw reply
* Re: [PATCH 0/2] move of_find_next_cache_node to DT core
From: Grant Likely @ 2013-09-18 14:51 UTC (permalink / raw)
To: Sudeep KarkadaNagesha, devicetree, linuxppc-dev; +Cc: Sudeep KarkadaNagesha
In-Reply-To: <1379501585-12532-1-git-send-email-Sudeep.KarkadaNagesha@arm.com>
On Wed, 18 Sep 2013 11:53:03 +0100, Sudeep KarkadaNagesha <Sudeep.KarkadaNagesha@arm.com> wrote:
> From: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
>
> Hi,
>
> The cache bindings are generic and used by many other architectures
> apart from PPC. These patches fixes and move the existing definition
> of of_find_next_cache_node to DT common code.
>
> Regards,
> Sudeep
Acked-by: Grant Likely <grant.likely@secretlab.ca>
However, do you have a user for this function on other architectures
yet? I'd like to see a user for the function in the same patch series..
g.
>
> Sudeep KarkadaNagesha (2):
> powerpc: remove big endianness assumption in of_find_next_cache_node
> of: move definition of of_find_next_cache_node into common code.
>
> arch/powerpc/include/asm/prom.h | 3 ---
> arch/powerpc/kernel/prom.c | 31 -------------------------------
> drivers/of/base.c | 31 +++++++++++++++++++++++++++++++
> include/linux/of.h | 2 ++
> 4 files changed, 33 insertions(+), 34 deletions(-)
>
> --
> 1.8.1.2
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH 0/2] move of_find_next_cache_node to DT core
From: Sudeep KarkadaNagesha @ 2013-09-18 16:18 UTC (permalink / raw)
To: Grant Likely
Cc: Sudeep KarkadaNagesha, devicetree@vger.kernel.org,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20130918145116.D53A5C42CDF@trevor.secretlab.ca>
On 18/09/13 15:51, Grant Likely wrote:
> On Wed, 18 Sep 2013 11:53:03 +0100, Sudeep KarkadaNagesha <Sudeep.Karkada=
Nagesha@arm.com> wrote:
>> From: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
>>
>> Hi,
>>
>> The cache bindings are generic and used by many other architectures
>> apart from PPC. These patches fixes and move the existing definition
>> of of_find_next_cache_node to DT common code.
>>
>> Regards,
>> Sudeep
>=20
> Acked-by: Grant Likely <grant.likely@secretlab.ca>
>=20
> However, do you have a user for this function on other architectures
> yet? I'd like to see a user for the function in the same patch series..
>=20
Yes I have posted an RFC[1] following this series implementing cacheinfo
for ARM similar to x86 implementation. I was not sure if it's good idea
to combine it as its still initial RFC version.
Regards,
Sudeep
[1] https://lkml.org/lkml/2013/9/18/340
^ permalink raw reply
* Re: [PATCH v2 2/6] PCI/MSI: Factor out pci_get_msi_cap() interface
From: Alexander Gordeev @ 2013-09-18 16:50 UTC (permalink / raw)
To: Tejun Heo
Cc: Joerg Roedel, x86@kernel.org, linux-kernel@vger.kernel.org,
linux-ide@vger.kernel.org, Jan Beulich, linux-pci@vger.kernel.org,
Bjorn Helgaas, linuxppc-dev, Ingo Molnar
In-Reply-To: <20130918142231.GA21650@mtj.dyndns.org>
On Wed, Sep 18, 2013 at 09:22:31AM -0500, Tejun Heo wrote:
> > > We have a small number of MSIs available, limited by hardware &
> > > firmware, if we don't impose a quota then the first device that probes
> > > will get most/all of the MSIs and other devices miss out.
> >
> > Out of curiosity - how pSeries has had done it without quotas before
> > 448e2ca ("powerpc/pseries: Implement a quota system for MSIs")?
>
> Hmmm... do we need to treat this any differently? If the platform
> can't allocate full range of requested MSIs, just failing should be
> enough regardless of why such allocation can't be met, no?
That depends from what "full range of requested MSIs" is. If that is
a maximum number of MSIs the controller advertised, then no. As MSI
design essentially allows devices to operate in lower-than-maximum
modes it is responsibility of a caller to decide how many vectors to
request. So in case of pSeries I think it is completely legitimate to
request lessers to overcome the platform limitation and let all devices
work.
> I really think what we should do is
>
> * Determine the number of MSIs the controller wants. Don't worry
> about quotas or limits or anything. Just determine the number
> necessary to enable enhanced interrupt handling.
Actually, I do not see much contradiction with what I proposed. The
key words here "determine the number of MSIs the controller wants".
In general case it is not what pci_msix_table_size() returns (or at
least we should not limit ourselves to it) - there could be non-
standard means to report number of MSIs: hardcoded, version-dependant,
device-specific registers etc.
Next, if we opt to determine the number of MSIs by non-MSI standard
means then there is no reason not to call pci_get_msix_limit() (or
whatever) at this step.
The question how I see it - do we want pci_get_msix_limit() interface
as part of the MSI framework or do we want it pSeries-specific?
> * Try allocating that number of MSIs. If it fails, then just revert
> to single interrupt mode. It's not the end of the world and mostly
> guaranteed to work. Let's please not even try to do partial
> multiple interrupts. I really don't think it's worth the risk or
> complexity.
Being Captain Obvious here, but it is up to the device driver to handle
a failure. There could be no such option as single MSI mode after all :)
> Thanks.
>
> --
> tejun
--
Regards,
Alexander Gordeev
agordeev@redhat.com
^ permalink raw reply
* Re: [PATCH] powerpc/mpc85xx:Add initial device tree support of T104x
From: Scott Wood @ 2013-09-18 16:48 UTC (permalink / raw)
To: Kushwaha Prabhakar-B32579
Cc: Wood Scott-B07421, Aggrwal Poonam-B10812, Jain Priyanka-B32167,
Sethi Varun-B16395, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <071A08F2C6A57E4E94D980ECA553F874F8CA17@039-SN1MPN1-005.039d.mgd.msft.net>
On Mon, 2013-09-16 at 21:11 -0500, Kushwaha Prabhakar-B32579 wrote:
>
> > -----Original Message-----
> > From: Wood Scott-B07421
> > Sent: Tuesday, September 17, 2013 2:49 AM
> > To: Kushwaha Prabhakar-B32579
> > Cc: Wood Scott-B07421; linuxppc-dev@lists.ozlabs.org;
> > galak@kernel.crashing.org; Aggrwal Poonam-B10812; Jain Priyanka-B32167;
> > Sethi Varun-B16395
> > Subject: Re: [PATCH] powerpc/mpc85xx:Add initial device tree support of
> > T104x
> >
> > On Fri, 2013-09-13 at 02:30 -0500, Kushwaha Prabhakar-B32579 wrote:
> > > > I also question the need to define separate t1040 compatible values
> > > > for all of these, if the only difference is whether the onboard
> > > > switch is enabled or not.
> > > >
> > >
> > > so should I use T104x as compatible field. and in T1040 device tree add
> > extra node for l2 switch.
>
> I am using T1042 as base dts and T1040 includes T1040 + l2switch.
>
> so if I use T1042 in compatible. It will give wrong field for someone working on T1040QDS.
What is wrong about it? It is compatible, right?
-Scott
^ permalink raw reply
* [PATCH] Fixed typo on word accounting in kprobes.c in mutliple architectures
From: Anoop Thomas Mathew @ 2013-09-18 21:03 UTC (permalink / raw)
To: vgupta, tony.luck, davem
Cc: linux-s390, linux-ia64, linux-kernel, sparclinux, akpm,
linuxppc-dev
Signed-off-by: Anoop Thomas Mathew <atm@profoundis.com>
---
arch/arc/kernel/kprobes.c | 2 +-
arch/ia64/kernel/kprobes.c | 2 +-
arch/powerpc/kernel/kprobes.c | 2 +-
arch/s390/kernel/kprobes.c | 2 +-
arch/sparc/kernel/kprobes.c | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/arc/kernel/kprobes.c b/arch/arc/kernel/kprobes.c
index 72f9782..7446c8d 100644
--- a/arch/arc/kernel/kprobes.c
+++ b/arch/arc/kernel/kprobes.c
@@ -327,7 +327,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned long trapnr)
*/
/* We increment the nmissed count for accounting,
- * we can also use npre/npostfault count for accouting
+ * we can also use npre/npostfault count for accounting
* these specific fault cases.
*/
kprobes_inc_nmissed_count(cur);
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index f8280a7..074fde4 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -947,7 +947,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
case KPROBE_HIT_SSDONE:
/*
* We increment the nmissed count for accounting,
- * we can also use npre/npostfault count for accouting
+ * we can also use npre/npostfault count for accounting
* these specific fault cases.
*/
kprobes_inc_nmissed_count(cur);
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 2156ea9..90fab64 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -429,7 +429,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
case KPROBE_HIT_SSDONE:
/*
* We increment the nmissed count for accounting,
- * we can also use npre/npostfault count for accouting
+ * we can also use npre/npostfault count for accounting
* these specific fault cases.
*/
kprobes_inc_nmissed_count(cur);
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 0ce9fb2..018c1c4 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -673,7 +673,7 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
case KPROBE_HIT_SSDONE:
/*
* We increment the nmissed count for accounting,
- * we can also use npre/npostfault count for accouting
+ * we can also use npre/npostfault count for accounting
* these specific fault cases.
*/
kprobes_inc_nmissed_count(p);
diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c
index e722121..d3d5d38 100644
--- a/arch/sparc/kernel/kprobes.c
+++ b/arch/sparc/kernel/kprobes.c
@@ -349,7 +349,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
case KPROBE_HIT_SSDONE:
/*
* We increment the nmissed count for accounting,
- * we can also use npre/npostfault count for accouting
+ * we can also use npre/npostfault count for accounting
* these specific fault cases.
*/
kprobes_inc_nmissed_count(cur);
--
1.7.9.5
^ permalink raw reply related
* Linux 2.6.32 PowerPC MTD partition mounted at boot
From: Dorin D @ 2013-09-19 2:43 UTC (permalink / raw)
To: linuxppc-dev@lists.ozlabs.org
[-- Attachment #1: Type: text/plain, Size: 1319 bytes --]
I am working on bringing up two Linux systems, both based on Freescale PowerPC devices, one is a MPC8349, the other a P1020. I was able to build, install and boot the kernel on both cards. The kernel is 2.6.32 and the toolchains are coming from the LTIBs packages from Freescale. Both cards have a 32 MByte NOR flash memory (AMD) boot flash. I have Uboot, kernel, RAM disk image and DTB in the boot flash and I want to use the spare space (about 20 MBytes) as flash file system. I have the following problem : the P1020 board boots fine using the RAM disk with the flash in the device tree , shows the flash device partitions (JFFS2) and DOESN"T try to mount a flash partition as root. The MPC8349 boots fine from the RAM disk but, after identifying the flash partitions, the kernel panics because is looking for a flash partition to mount as root partition and none of them is usable (not formatted). If I remove the flash from the device tree, the card boots fine using the RAM disk.
I am not too familiar with Linux boot scripts and I didn't figure out where I can disable this tentative of mounting the MTD partition. I want the boards to boot and mount the RAM disk, as the P1020 board does. The flash partition will be initialized and mounted at a later time, but not as root partition.
TIADorin
[-- Attachment #2: Type: text/html, Size: 3470 bytes --]
^ permalink raw reply
* [PATCH 0/6 v5] kvm: powerpc: use cache attributes from linux pte
From: Bharat Bhushan @ 2013-09-19 6:02 UTC (permalink / raw)
To: benh, agraf, paulus, kvm, kvm-ppc, linuxppc-dev, scottwood; +Cc: Bharat Bhushan
From: Bharat Bhushan <bharat.bhushan@freescale.com>
First patch is a typo fix where book3e define _PAGE_LENDIAN while it
should be defined as _PAGE_ENDIAN. This seems to show that this is never exercised :-)
Second and third patch is to allow guest controlling "G"-Guarded and "E"-Endian TLB attributes respectively.
Fourth patch is moving functions/logic in common code so they can be used on booke also.
Fifth and Sixth patch is actually setting caching attributes (TLB.WIMGE) using corresponding Linux pte.
v3->v5
- Fix tlb-reference-flag clearing issue (patch 4/6)
- There was a patch (4/6 powerpc: move linux pte/hugepte search to more generic file)
in the last series of this patchset which was moving pte/hugepte search functions to
generic file. That patch is no more needed as some other patch is already applied to fix that :)
v2->v3
- now lookup_linux_pte() only have pte search logic and it does not
set any access flags in pte. There is already a function for setting
access flag which will be called explicitly where needed.
On booke we only need to search for pte to get WIMG.
v1->v2
- Earlier caching attributes (WIMGE) were set based of page is RAM or not
But now we get these attributes from corresponding Linux PTE.
Bharat Bhushan (6):
powerpc: book3e: _PAGE_LENDIAN must be _PAGE_ENDIAN
kvm: powerpc: allow guest control "E" attribute in mas2
kvm: powerpc: allow guest control "G" attribute in mas2
kvm: powerpc: keep only pte search logic in lookup_linux_pte
kvm: booke: clear host tlb reference flag on guest tlb invalidation
kvm: powerpc: use caching attributes as per linux pte
arch/powerpc/include/asm/kvm_host.h | 2 +-
arch/powerpc/include/asm/pgtable.h | 24 ++++++++++++++++
arch/powerpc/include/asm/pte-book3e.h | 2 +-
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 36 ++++++++----------------
arch/powerpc/kvm/booke.c | 2 +-
arch/powerpc/kvm/e500.h | 10 ++++--
arch/powerpc/kvm/e500_mmu_host.c | 50 +++++++++++++++++++--------------
7 files changed, 74 insertions(+), 52 deletions(-)
^ permalink raw reply
* [PATCH 1/6 v5] powerpc: book3e: _PAGE_LENDIAN must be _PAGE_ENDIAN
From: Bharat Bhushan @ 2013-09-19 6:02 UTC (permalink / raw)
To: benh, agraf, paulus, kvm, kvm-ppc, linuxppc-dev, scottwood; +Cc: Bharat Bhushan
In-Reply-To: <1379570566-3715-1-git-send-email-Bharat.Bhushan@freescale.com>
For booke3e _PAGE_ENDIAN is not defined. Infact what is defined
is "_PAGE_LENDIAN" which is wrong and that should be _PAGE_ENDIAN.
There are no compilation errors as
arch/powerpc/include/asm/pte-common.h defines _PAGE_ENDIAN to 0
as it is not defined anywhere.
Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
v1->v5
- no change
arch/powerpc/include/asm/pte-book3e.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/include/asm/pte-book3e.h b/arch/powerpc/include/asm/pte-book3e.h
index 0156702..576ad88 100644
--- a/arch/powerpc/include/asm/pte-book3e.h
+++ b/arch/powerpc/include/asm/pte-book3e.h
@@ -40,7 +40,7 @@
#define _PAGE_U1 0x010000
#define _PAGE_U0 0x020000
#define _PAGE_ACCESSED 0x040000
-#define _PAGE_LENDIAN 0x080000
+#define _PAGE_ENDIAN 0x080000
#define _PAGE_GUARDED 0x100000
#define _PAGE_COHERENT 0x200000 /* M: enforce memory coherence */
#define _PAGE_NO_CACHE 0x400000 /* I: cache inhibit */
--
1.7.0.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox