Re: [PATCH V3 1/5] powerpc/fsl-pci: Unify pci/pcie initialization code
From: Kumar Gala <hidden>
Date: 2012-07-26 17:53:17
On Jul 26, 2012, at 7:30 AM, Jia Hongtao wrote:
We unified the Freescale pci/pcie initialization by changing the =
fsl_pci
to a platform driver. In previous PCI code architecture the =
initialization
routine is called at board_setup_arch stage. Now the initialization is =
done
in probe function which is architectural better. Also It's convenient =
for
adding PM support for PCI controller in later patch. =20 One issue introduced by this architecture is the timing of =
swiotlb_init.
During PCI initialization the need of swiotlb is determined and this =
should
be done before swiotlb_init. So a new function to determine swiotlb by parsing pci ranges is made. This function is called at =
board_setup_arch
stage which is earlier than swiotlb_init. =20 Signed-off-by: Jia Hongtao <redacted> Signed-off-by: Li Yang <redacted> --- Changed for V3: - Rebase the patch set on the latest tree - merge PCI unify and swiotlb patch into one =20 arch/powerpc/sysdev/fsl_pci.c | 155 =
++++++++++++++++++++++++++++++++---------
quoted hunk ↗ jump to hunk
arch/powerpc/sysdev/fsl_pci.h | 9 +-- 2 files changed, 125 insertions(+), 39 deletions(-) =20diff --git a/arch/powerpc/sysdev/fsl_pci.c =
b/arch/powerpc/sysdev/fsl_pci.c
quoted hunk ↗ jump to hunk
index a7b2a60..5228b6b 100644--- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c@@ -823,56 +823,143 @@ static const struct of_device_id pci_ids[] =3D =
{ {},
};
=20
-struct device_node *fsl_pci_primary;
-
-void __devinit fsl_pci_init(void)
+#ifdef CONFIG_SWIOTLB
+void pci_determine_swiotlb(void)
{
+ const u32 *ranges;
+ int rlen;
+ int pna;
+ int np;
struct device_node *node;
- struct pci_controller *hose;
- dma_addr_t max =3D 0xffffffff;
-
- /* Callers can specify the primary bus using other means. */
- if (!fsl_pci_primary) {
- /* If a PCI host bridge contains an ISA node, it's =primary. */
- node =3D of_find_node_by_type(NULL, "isa");
- while ((fsl_pci_primary =3D of_get_parent(node))) {
- of_node_put(node);
- node =3D fsl_pci_primary;
-
- if (of_match_node(pci_ids, node))
- break;
- }
- }
+ int memno;
+ u32 pci_space;
+ unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
+ unsigned long long pci_addr_lo =3D ULLONG_MAX;
+ unsigned long long pci_addr_hi =3D 0x0;
+ dma_addr_t pci_dma_sz;
=20
- node =3D NULL;
for_each_node_by_type(node, "pci") {
if (of_match_node(pci_ids, node)) {
- /*
- * 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.
- */ - if (!fsl_pci_primary) - fsl_pci_primary =3D node; - - fsl_add_bridge(node, fsl_pci_primary =3D=3D =
node);
- hose =3D pci_find_hose_for_OF_device(node); - max =3D min(max, hose->dma_window_base_cur + - hose->dma_window_size); + memno =3D 0; + pna =3D of_n_addr_cells(node); + np =3D pna + 5;
Don't duplicate code from pci_process_bridge_OF_ranges(), refactor the = code to have a shared function:
+ /* Get ranges property */ + ranges =3D of_get_property(node, "ranges", =
&rlen);
+ if (ranges =3D=3D NULL)
+ return;
+
+ /* Parse outbound MEM window range */
+ while ((rlen -=3D np * 4) >=3D 0) {
+ /* Read next ranges element */
+ pci_space =3D ranges[0];
+ if (!((pci_space >> 24) & 0x2)) {
+ ranges +=3D np;
+ break;
+ }
+ pci_addr =3D of_read_number(ranges + 1, =2);
+ cpu_addr =3D of_translate_address( + node, ranges + 3); + size =3D of_read_number(ranges + pna + =
3, 2);
+ ranges +=3D 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 =3D=3D OF_BAD_ADDR || size =
=3D=3D 0)
+ continue; + + /* + * Now consume following elements while =
they
+ * are contiguous + */ + for (; rlen >=3D np * sizeof(u32); + ranges +=3D np, rlen -=3D =
np * 4) {+ if (ranges[0] !=3D pci_space) + break; + pci_next =3D =
of_read_number(ranges + 1,
+ 2); + cpu_next =3D =
of_translate_address(node,
+ ranges + 3); + if (pci_next !=3D pci_addr + =
size ||
+ cpu_next !=3D cpu_addr + =
size)
+ break; + size +=3D of_read_number( + ranges + pna + =
3, 2);
+ }
+
+ /* We support only 3 memory ranges */
+ if (memno >=3D 3) {
+ printk(KERN_INFO
+ " \\--> Skipped =(too many) !\n");
+ continue; + } + + pci_addr_lo =3D min(pci_addr, =
pci_addr_lo);
+ pci_addr_hi =3D max(pci_addr + size, =
pci_addr_hi);
+ memno++;
+ }
}
}
=20
-#ifdef CONFIG_SWIOTLB
+ /* Get PEXCSRBAR size (equal to CCSR size) */
+ node =3D of_find_node_by_type(NULL, "soc");
+ ranges =3D of_get_property(node, "ranges", &rlen);
+ if (ranges =3D=3D NULL)
+ return;
+
+ size =3D of_read_number(ranges + 3, 1);
+ of_node_put(node);
+
+ if (pci_addr_hi < (0x100000000ull - size))
+ pci_dma_sz =3D pci_addr_lo;
+ else
+ pci_dma_sz =3D 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() - 1 > max) {
+ if (memblock_end_of_DRAM() > pci_dma_sz) {
ppc_swiotlb_enable =3D 1;
set_pci_dma_ops(&swiotlb_dma_ops);
- ppc_md.pci_dma_dev_setup =3D pci_dma_dev_setup_swiotlb;
+ ppc_md.pci_dma_dev_setup =3D
+ pci_dma_dev_setup_swiotlb;why the line wrap change?
}
+}
#endif
+
+int primary_phb_addr;
+static int __devinit fsl_pci_probe(struct platform_device *pdev)
+{
+ struct pci_controller *hose;
+ bool is_primary;
+
+ if (of_match_node(pci_ids, pdev->dev.of_node)) {
+ struct resource rsrc;
+ of_address_to_resource(pdev->dev.of_node, 0, &rsrc);
+ is_primary =3D ((rsrc.start & 0xfffff) =3D=3D =primary_phb_addr);
+ fsl_add_bridge(pdev->dev.of_node, is_primary);
+ }
+
+ return 0;
+}
+
+static struct platform_driver fsl_pci_driver =3D {
+ .driver =3D {
+ .name =3D "fsl-pci",
+ .of_match_table =3D pci_ids,
+ },
+ .probe =3D fsl_pci_probe,
+};
+
+static int __init fsl_pci_init(void)
+{
+ return platform_driver_register(&fsl_pci_driver);
}
+arch_initcall(fsl_pci_init);
#endif