[PATCH 2/6] powerpc/fsl-pci: Check swiotlb enable at board setup_arch stage
Jia Hongtao
B38951 at freescale.com
Tue Jul 24 20:20:06 EST 2012
PCI initialization is called later than swiotlb_init() due to PCI controller is
a platform driver now. So we provide a function which called at board setup_arch
stage to address swiotlb enable by parsing pci ranges.
Signed-off-by: Jia Hongtao <B38951 at freescale.com>
Signed-off-by: Li Yang <leoli at freescale.com>
---
arch/powerpc/sysdev/fsl_pci.c | 125 ++++++++++++++++++++++++++++++++++++-----
arch/powerpc/sysdev/fsl_pci.h | 6 ++
2 files changed, 116 insertions(+), 15 deletions(-)
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index feed364..99a3e78 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -822,6 +822,116 @@ static const struct of_device_id pci_ids[] = {
{},
};
+#ifdef CONFIG_SWIOTLB
+void pci_check_swiotlb(void)
+{
+ const u32 *ranges;
+ int rlen;
+ int pna;
+ int np;
+ struct device_node *node;
+ int memno;
+ u32 pci_space;
+ unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
+ unsigned long long pci_addr_lo = ULLONG_MAX;
+ unsigned long long pci_addr_hi = 0x0;
+ dma_addr_t pci_dma_sz;
+
+ for_each_node_by_type(node, "pci") {
+ if (of_match_node(pci_ids, node)) {
+ memno = 0;
+ pna = of_n_addr_cells(node);
+ np = pna + 5;
+ /* Get ranges property */
+ ranges = of_get_property(node, "ranges", &rlen);
+ if (ranges == NULL)
+ return;
+
+ /* Parse outbound MEM window range */
+ while ((rlen -= np * 4) >= 0) {
+ /* Read next ranges element */
+ pci_space = ranges[0];
+ if (!((pci_space >> 24) & 0x2)) {
+ ranges += np;
+ break;
+ }
+ pci_addr = of_read_number(ranges + 1, 2);
+ cpu_addr = of_translate_address(
+ node, ranges + 3);
+ size = of_read_number(ranges + pna + 3, 2);
+ ranges += np;
+
+ /*
+ * If we failed translation or got a zero-sized
+ * region (some FW try to feed us with non
+ * sensical zero sized regions such as power3
+ * which look like some kind of attempt at
+ * exposing the VGA memory hole)
+ */
+ if (cpu_addr == OF_BAD_ADDR || size == 0)
+ continue;
+
+ /*
+ * Now consume following elements while they
+ * are contiguous
+ */
+ for (; rlen >= np * sizeof(u32);
+ ranges += np, rlen -= np * 4) {
+ if (ranges[0] != pci_space)
+ break;
+ pci_next = of_read_number(ranges + 1,
+ 2);
+ cpu_next = of_translate_address(node,
+ ranges + 3);
+ if (pci_next != pci_addr + size ||
+ cpu_next != cpu_addr + size)
+ break;
+ size += of_read_number(
+ ranges + pna + 3, 2);
+ }
+
+ /* We support only 3 memory ranges */
+ if (memno >= 3) {
+ printk(KERN_INFO
+ " \\--> Skipped (too many) !\n");
+ continue;
+ }
+
+ pci_addr_lo = min(pci_addr, pci_addr_lo);
+ pci_addr_hi = max(pci_addr + size, pci_addr_hi);
+ memno++;
+ }
+ }
+ }
+
+ /* Get PEXCSRBAR size (equal to CCSR size) */
+ node = of_find_node_by_type(NULL, "soc");
+ ranges = of_get_property(node, "ranges", &rlen);
+ if (ranges == NULL)
+ return;
+
+ size = of_read_number(ranges + 3, 1);
+ of_node_put(node);
+
+ if (pci_addr_hi < (0x100000000ull - size))
+ pci_dma_sz = pci_addr_lo;
+ else
+ pci_dma_sz = pci_addr_lo - size;
+
+ /*
+ * 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() > pci_dma_sz) {
+ ppc_swiotlb_enable = 1;
+ set_pci_dma_ops(&swiotlb_dma_ops);
+ ppc_md.pci_dma_dev_setup =
+ pci_dma_dev_setup_swiotlb;
+ }
+}
+#endif
+
int primary_phb_addr;
static int __devinit fsl_pci_probe(struct platform_device *pdev)
{
@@ -833,21 +943,6 @@ static int __devinit fsl_pci_probe(struct platform_device *pdev)
of_address_to_resource(pdev->dev.of_node, 0, &rsrc);
is_primary = ((rsrc.start & 0xfffff) == primary_phb_addr);
fsl_add_bridge(pdev->dev.of_node, is_primary);
-
-#ifdef CONFIG_SWIOTLB
- hose = pci_find_hose_for_OF_device(pdev->dev.of_node);
- /*
- * 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() > hose->dma_window_base_cur
- + hose->dma_window_size) {
- ppc_swiotlb_enable = 1;
- set_pci_dma_ops(&swiotlb_dma_ops);
- ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
- }
-#endif
}
return 0;
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index df9fc44..c2c1de5 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -94,5 +94,11 @@ 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);
+#ifdef CONFIG_SWIOTLB
+extern void pci_check_swiotlb(void);
+#else
+static inline void pci_check_swiotlb(void) {}
+#endif
+
#endif /* __POWERPC_FSL_PCI_H */
#endif /* __KERNEL__ */
--
1.7.5.1
More information about the Linuxppc-dev
mailing list