Skip to contentSkip to conversation

PCI: rcar: Driver model and physical address space update

PATCH Superseded Magnus Damm 5 participants 16 messages Feb 5, 2014 – Feb 13, 2014

Subsystems (3)

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Magnus Damm

author maintainer
#0 lore raw

cover PCI: rcar: Driver model and physical address space update

PCI: rcar: Driver model and physical address space update

[PATCH 01/04] PCI: rcar: Register each instance independently [PATCH 02/04] PCI: rcar: Break out window size handling [PATCH 03/04] PCI: rcar: Add DMABOUNCE support [PATCH 04/04] PCI: rcar: Enable BOUNCE in case of HIGHMEM

These patches update the pci-rcar-gen2.c driver in various ways including cleanups for driver model interface (1/4), readability update (2/4) and also bounce buffer support (3/4, 4/4). Basically the first two are just cleanups and the rest are fixes.

As it is today without these patches the system memory start address is hard coded at 0x4000000 and the window is fixed at 1GiB. So we have board specific code hidden in the driver which is good to avoid.

With these hard coded board specific constants there are some error cases that are not handled, in particular the issue that only maximum 1GiB of physical address space can be used for bus mastering with a single window. The common case of using ARM CONFIG_VMSPLIT_3G results in no visible issues as long as CONFIG_BOUNCE is used, but other CONFIG_VMSPLIT settings will break due to the hard coded 1GiB window not being enough. It has been verified that reducing the window size to 256MB makes the driver behave the same with VMSPLIT_3G as 1GiB window size and other VMSPLIT settings.

To handle the maximum 1GiB physical address space limitation two types of bounce buffers are added. The ARM specific DMABOUNCE code is in 3/4 hooked up to a chunk of local memory that is also handed of as coherent memory to the pci devices hanging off the PCI bridge. The driver makes sure to set the window so the local memory is always included. When the PCI devices are operating and in case memory is used outside the window then the DMABOUNCE buffers kicks in. This makes the driver support all kinds of VMSPLIT settings and window sizes. The BOUNCE code in 4/4 is selected to make sure bounce buffers are used for HIGHMEM.

With these patches this driver can be used with or without CMA and with or without DMA zone. Basically the system wide memory setup is left to the user. If a DMA zone is used then the PCI window will be setup to cover that. Same thing with CMA.

Tested with USB storage using LPAE and various VMSPLIT settings together with renesas git tag renesas-devel-v3.14-rc1-20140204 from kernel.org

---

Written against renesas.git tag renesas-devel-v3.14-rc1-20140204

 drivers/pci/host/Kconfig         |    3 
 drivers/pci/host/pci-rcar-gen2.c |  367 +++++++++++++++++++++++++++++++-------
 2 files changed, 306 insertions(+), 64 deletions(-)
author maintainer
#1 lore raw

PATCH 1/4 PCI: rcar: Register each instance independently

From: Magnus Damm <[email protected]>

Convert the code to allow per-device probe() like other device drivers. This also delays driver registration due to change from subsys_initcall() to regular module_platform_driver().

---

 drivers/pci/host/pci-rcar-gen2.c |   74 ++++++++------------------------------
 1 file changed, 16 insertions(+), 58 deletions(-)
drivers/pci/host/pci-rcar-gen2.c +16 -58
@@ -74,9 +74,6 @@
 
 #define RCAR_PCI_UNIT_REV_REG		(RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
 
-/* Number of internal PCI controllers */
-#define RCAR_PCI_NR_CONTROLLERS		3
-
 struct rcar_pci_priv {
 	struct device *dev;
 	void __iomem *reg;
@@ -228,6 +225,8 @@ static int __init rcar_pci_setup(int nr,
 	pci_add_resource(&sys->resources, &priv->io_res);
 	pci_add_resource(&sys->resources, &priv->mem_res);
 
+	/* Setup bus number based on platform device id */
+	sys->busnr = to_platform_device(priv->dev)->id;
 	return 1;
 }
 
@@ -236,48 +235,12 @@ static struct pci_ops rcar_pci_ops = {
 	.write	= rcar_pci_write_config,
 };
 
-static struct hw_pci rcar_hw_pci __initdata = {
-	.map_irq	= rcar_pci_map_irq,
-	.ops		= &rcar_pci_ops,
-	.setup		= rcar_pci_setup,
-};
-
-static int rcar_pci_count __initdata;
-
-static int __init rcar_pci_add_controller(struct rcar_pci_priv *priv)
-{
-	void **private_data;
-	int count;
-
-	if (rcar_hw_pci.nr_controllers < rcar_pci_count)
-		goto add_priv;
-
-	/* (Re)allocate private data pointer array if needed */
-	count = rcar_pci_count + RCAR_PCI_NR_CONTROLLERS;
-	private_data = kzalloc(count * sizeof(void *), GFP_KERNEL);
-	if (!private_data)
-		return -ENOMEM;
-
-	rcar_pci_count = count;
-	if (rcar_hw_pci.private_data) {
-		memcpy(private_data, rcar_hw_pci.private_data,
-		       rcar_hw_pci.nr_controllers * sizeof(void *));
-		kfree(rcar_hw_pci.private_data);
-	}
-
-	rcar_hw_pci.private_data = private_data;
-
-add_priv:
-	/* Add private data pointer to the array */
-	rcar_hw_pci.private_data[rcar_hw_pci.nr_controllers++] = priv;
-	return 0;
-}
-
-static int __init rcar_pci_probe(struct platform_device *pdev)
+static int rcar_pci_probe(struct platform_device *pdev)
 {
 	struct resource *cfg_res, *mem_res;
 	struct rcar_pci_priv *priv;
 	void __iomem *reg;
+	struct hw_pci hw;
 
 	cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	reg = devm_ioremap_resource(&pdev->dev, cfg_res);
@@ -308,31 +271,26 @@ static int __init rcar_pci_probe(struct
 	priv->reg = reg;
 	priv->dev = &pdev->dev;
 
-	return rcar_pci_add_controller(priv);
+	memset(&hw, 0, sizeof(hw));
+	hw.nr_controllers = 1;
+	hw.private_data = (void **)&priv;
+	hw.map_irq = rcar_pci_map_irq;
+	hw.ops = &rcar_pci_ops;
+	hw.setup = rcar_pci_setup;
+	pci_common_init_dev(&pdev->dev, &hw);
+	return 0;
 }
 
 static struct platform_driver rcar_pci_driver = {
 	.driver = {
 		.name = "pci-rcar-gen2",
+		.owner = THIS_MODULE,
+		.suppress_bind_attrs = true,
 	},
+	.probe = rcar_pci_probe,
 };
 
-static int __init rcar_pci_init(void)
-{
-	int retval;
-
-	retval = platform_driver_probe(&rcar_pci_driver, rcar_pci_probe);
-	if (!retval)
-		pci_common_init(&rcar_hw_pci);
-
-	/* Private data pointer array is not needed any more */
-	kfree(rcar_hw_pci.private_data);
-	rcar_hw_pci.private_data = NULL;
-
-	return retval;
-}
-
-subsys_initcall(rcar_pci_init);
+module_platform_driver(rcar_pci_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Renesas R-Car Gen2 internal PCI");
#2 lore raw

Re: [PATCH 01/04] PCI: rcar: Register each instance independently

Quoted 10 lines · Magnus Damm
drivers/pci/host/pci-rcar-gen2.c +2 -0
+static int rcar_pci_probe(struct platform_device *pdev)
 {
        struct resource *cfg_res, *mem_res;
        struct rcar_pci_priv *priv;
        void __iomem *reg;
+       struct hw_pci hw;
 
        cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        reg = devm_ioremap_resource(&pdev->dev, cfg_res);

drivers/pci/host/pci-rcar-gen2.c static int __init rcar_pci_probe(struct · line 276

Quoted 7 lines
drivers/pci/host/pci-rcar-gen2.c +3 -1
@@ -308,31 +271,26 @@ static int __init rcar_pci_probe(struct
        priv->reg = reg;
        priv->dev = &pdev->dev;
 
-       return rcar_pci_add_controller(priv);
+       memset(&hw, 0, sizeof(hw));
+       hw.nr_controllers = 1;
+       hw.private_data = (void **)&priv;

This raised a red flag: taking the address of a variable on the stack. I know it's correct, as hw.private_data is an array of pointers copied by pci_common_init_dev() below.
But perhaps it's a good idea to turn priv into an array with one element, to make this clearer, and avoid the ugly cast?

drivers/pci/host/pci-rcar-gen2.c static int __init rcar_pci_probe(struct · line 281

Quoted 5 lines
drivers/pci/host/pci-rcar-gen2.c +5 -0
+       hw.map_irq = rcar_pci_map_irq;
+       hw.ops = &rcar_pci_ops;
+       hw.setup = rcar_pci_setup;
+       pci_common_init_dev(&pdev->dev, &hw);
+       return 0;

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

author maintainer
#3 lore raw

Re: [PATCH 01/04] PCI: rcar: Register each instance independently

Quoted 14 lines · Geert Uytterhoeven
Quoted 13 lines · Magnus Damm
drivers/pci/host/pci-rcar-gen2.c +2 -0
+static int rcar_pci_probe(struct platform_device *pdev)
 {
        struct resource *cfg_res, *mem_res;
        struct rcar_pci_priv *priv;
        void __iomem *reg;
+       struct hw_pci hw;
 
        cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        reg = devm_ioremap_resource(&pdev->dev, cfg_res);
@@ -308,31 +271,26 @@ static int __init rcar_pci_probe(struct
        priv->reg = reg;
        priv->dev = &pdev->dev;
 
Quoted 10 lines

drivers/pci/host/pci-rcar-gen2.c static int __init rcar_pci_probe(struct · line 276

Quoted 4 lines
drivers/pci/host/pci-rcar-gen2.c +3 -1
-       return rcar_pci_add_controller(priv);
+       memset(&hw, 0, sizeof(hw));
+       hw.nr_controllers = 1;
+       hw.private_data = (void **)&priv;

This raised a red flag: taking the address of a variable on the stack. I know it's correct, as hw.private_data is an array of pointers copied by pci_common_init_dev() below.
But perhaps it's a good idea to turn priv into an array with one element, to make this clearer, and avoid the ugly cast?

I simply followed the same style as pci-tegra.c, but I agree that it can be made prettier. Also, there may be some better way how to register independent instances, not sure.

Thanks,

/ magnus

#4 lore raw

Re: [PATCH 01/04] PCI: rcar: Register each instance independently

In reply to Magnus Damm
Quoted 88 lines · Magnus Damm

From: Magnus Damm <[email protected]>

Convert the code to allow per-device probe() like other device drivers. This also delays driver registration due to change from subsys_initcall() to regular module_platform_driver().

---

  drivers/pci/host/pci-rcar-gen2.c |   74 ++++++++------------------------------
  1 file changed, 16 insertions(+), 58 deletions(-)
drivers/pci/host/pci-rcar-gen2.c +4 -41
@@ -74,9 +74,6 @@
 
  #define RCAR_PCI_UNIT_REV_REG		(RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
 
-/* Number of internal PCI controllers */
-#define RCAR_PCI_NR_CONTROLLERS		3
-
  struct rcar_pci_priv {
  	struct device *dev;
  	void __iomem *reg;
@@ -228,6 +225,8 @@ static int __init rcar_pci_setup(int nr,
  	pci_add_resource(&sys->resources, &priv->io_res);
  	pci_add_resource(&sys->resources, &priv->mem_res);
 
+	/* Setup bus number based on platform device id */
+	sys->busnr = to_platform_device(priv->dev)->id;
  	return 1;
  }
 
@@ -236,48 +235,12 @@ static struct pci_ops rcar_pci_ops = {
  	.write	= rcar_pci_write_config,
  };
 
-static struct hw_pci rcar_hw_pci __initdata = {
-	.map_irq	= rcar_pci_map_irq,
-	.ops		= &rcar_pci_ops,
-	.setup		= rcar_pci_setup,
-};
-
-static int rcar_pci_count __initdata;
-
-static int __init rcar_pci_add_controller(struct rcar_pci_priv *priv)
-{
-	void **private_data;
-	int count;
-
-	if (rcar_hw_pci.nr_controllers < rcar_pci_count)
-		goto add_priv;
-
-	/* (Re)allocate private data pointer array if needed */
-	count = rcar_pci_count + RCAR_PCI_NR_CONTROLLERS;
-	private_data = kzalloc(count * sizeof(void *), GFP_KERNEL);
-	if (!private_data)
-		return -ENOMEM;
-
-	rcar_pci_count = count;
-	if (rcar_hw_pci.private_data) {
-		memcpy(private_data, rcar_hw_pci.private_data,
-		       rcar_hw_pci.nr_controllers * sizeof(void *));
-		kfree(rcar_hw_pci.private_data);
-	}
-
-	rcar_hw_pci.private_data = private_data;
-
-add_priv:
-	/* Add private data pointer to the array */
-	rcar_hw_pci.private_data[rcar_hw_pci.nr_controllers++] = priv;
-	return 0;
-}
-
-static int __init rcar_pci_probe(struct platform_device *pdev)
+static int rcar_pci_probe(struct platform_device *pdev)
  {
  	struct resource *cfg_res, *mem_res;
  	struct rcar_pci_priv *priv;
  	void __iomem *reg;
+	struct hw_pci hw;
 
  	cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	reg = devm_ioremap_resource(&pdev->dev, cfg_res);
@@ -308,31 +271,26 @@ static int __init rcar_pci_probe(struct
  	priv->reg = reg;
  	priv->dev = &pdev->dev;
 

drivers/pci/host/pci-rcar-gen2.c static int __init rcar_pci_probe(struct · line 282

Quoted 10 lines
drivers/pci/host/pci-rcar-gen2.c +8 -1
-	return rcar_pci_add_controller(priv);
+	memset(&hw, 0, sizeof(hw));
+	hw.nr_controllers = 1;
+	hw.private_data = (void **)&priv;
+	hw.map_irq = rcar_pci_map_irq;
+	hw.ops = &rcar_pci_ops;
+	hw.setup = rcar_pci_setup;
+	pci_common_init_dev(&pdev->dev, &hw);
+	return 0;
  }

Do we really want to explicitly set the bus number here?

Quoted 9 lines
drivers/pci/host/pci-rcar-gen2.c +3 -0
  static struct platform_driver rcar_pci_driver = {
  	.driver = {
  		.name = "pci-rcar-gen2",
+		.owner = THIS_MODULE,
+		.suppress_bind_attrs = true,
  	},
+	.probe = rcar_pci_probe,
  };
Signature · 2 lines
Ben Dooks				http://www.codethink.co.uk/
Senior Engineer				Codethink - Providing Genius
author maintainer
#5 lore raw

Re: [PATCH 01/04] PCI: rcar: Register each instance independently

Quoted 92 lines · Ben Dooks
Quoted 91 lines · Magnus Damm

From: Magnus Damm <[email protected]>

Convert the code to allow per-device probe() like other device drivers. This also delays driver registration due to change from subsys_initcall() to regular module_platform_driver().

---

  drivers/pci/host/pci-rcar-gen2.c |   74
++++++++------------------------------
  1 file changed, 16 insertions(+), 58 deletions(-)
drivers/pci/host/pci-rcar-gen2.c 2014-02-04 renamed from drivers/pci/host/pci-rcar-gen2.c +0 -0

16:38:46.000000000 +0900

drivers/pci/host/pci-rcar-gen2.c 2014-02-04 renamed from drivers/pci/host/pci-rcar-gen2.c +4 -41
@@ -74,9 +74,6 @@
 
  #define RCAR_PCI_UNIT_REV_REG         (RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
 
-/* Number of internal PCI controllers */
-#define RCAR_PCI_NR_CONTROLLERS                3
-
  struct rcar_pci_priv {
        struct device *dev;
        void __iomem *reg;
@@ -228,6 +225,8 @@ static int __init rcar_pci_setup(int nr,
        pci_add_resource(&sys->resources, &priv->io_res);
        pci_add_resource(&sys->resources, &priv->mem_res);
 
+       /* Setup bus number based on platform device id */
+       sys->busnr = to_platform_device(priv->dev)->id;
        return 1;
  }
 
@@ -236,48 +235,12 @@ static struct pci_ops rcar_pci_ops = {
        .write  = rcar_pci_write_config,
  };
 
-static struct hw_pci rcar_hw_pci __initdata = {
-       .map_irq        = rcar_pci_map_irq,
-       .ops            = &rcar_pci_ops,
-       .setup          = rcar_pci_setup,
-};
-
-static int rcar_pci_count __initdata;
-
-static int __init rcar_pci_add_controller(struct rcar_pci_priv *priv)
-{
-       void **private_data;
-       int count;
-
-       if (rcar_hw_pci.nr_controllers < rcar_pci_count)
-               goto add_priv;
-
-       /* (Re)allocate private data pointer array if needed */
-       count = rcar_pci_count + RCAR_PCI_NR_CONTROLLERS;
-       private_data = kzalloc(count * sizeof(void *), GFP_KERNEL);
-       if (!private_data)
-               return -ENOMEM;
-
-       rcar_pci_count = count;
-       if (rcar_hw_pci.private_data) {
-               memcpy(private_data, rcar_hw_pci.private_data,
-                      rcar_hw_pci.nr_controllers * sizeof(void *));
-               kfree(rcar_hw_pci.private_data);
-       }
-
-       rcar_hw_pci.private_data = private_data;
-
-add_priv:
-       /* Add private data pointer to the array */
-       rcar_hw_pci.private_data[rcar_hw_pci.nr_controllers++] = priv;
-       return 0;
-}
-
-static int __init rcar_pci_probe(struct platform_device *pdev)
+static int rcar_pci_probe(struct platform_device *pdev)
  {
        struct resource *cfg_res, *mem_res;
        struct rcar_pci_priv *priv;
        void __iomem *reg;
+       struct hw_pci hw;
 
        cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        reg = devm_ioremap_resource(&pdev->dev, cfg_res);
@@ -308,31 +271,26 @@ static int __init rcar_pci_probe(struct
        priv->reg = reg;
        priv->dev = &pdev->dev;
 
Quoted 13 lines

drivers/pci/host/pci-rcar-gen2.c 2014-02-04 static int __init rcar_pci_probe(struct · line 282

Quoted 10 lines
drivers/pci/host/pci-rcar-gen2.c 2014-02-04 renamed from drivers/pci/host/pci-rcar-gen2.c +8 -1
-       return rcar_pci_add_controller(priv);
+       memset(&hw, 0, sizeof(hw));
+       hw.nr_controllers = 1;
+       hw.private_data = (void **)&priv;
+       hw.map_irq = rcar_pci_map_irq;
+       hw.ops = &rcar_pci_ops;
+       hw.setup = rcar_pci_setup;
+       pci_common_init_dev(&pdev->dev, &hw);
+       return 0;
  }

Do we really want to explicitly set the bus number here?

Right now the code in rcar_pci_setup() sets up the bus number. Ugly but better than before IMO. If you have any suggestions how to make this prettier then please let me know. =)

/ magnus

author maintainer
#6 lore raw

PATCH 2/4 PCI: rcar: Break out window size handling

In reply to Magnus Damm

From: Magnus Damm <[email protected]>

Break out the hard coded window size code to allow dynamic setup. The window size is still left at 1GiB but with this patch changing window size is easy for testing.

---

 drivers/pci/host/pci-rcar-gen2.c |   31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)
drivers/pci/host/pci-rcar-gen2.c +28 -3
@@ -18,6 +18,7 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 
 /* AHB-PCI Bridge PCI communication registers */
@@ -81,6 +82,7 @@ struct rcar_pci_priv {
 	struct resource mem_res;
 	struct resource *cfg_res;
 	int irq;
+	unsigned long window_size;
 };
 
 /* PCI configuration space operations */
@@ -180,10 +182,31 @@ static int __init rcar_pci_setup(int nr,
 	iowrite32(val, reg + RCAR_USBCTR_REG);
 	udelay(4);
 
-	/* De-assert reset and set PCIAHB window1 size to 1GB */
+	/* De-assert reset and reset PCIAHB window1 size */
 	val &= ~(RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK |
 		 RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST);
-	iowrite32(val | RCAR_USBCTR_PCIAHB_WIN1_1G, reg + RCAR_USBCTR_REG);
+
+	/* Setup PCIAHB window1 size */
+	switch (priv->window_size) {
+	case SZ_2G:
+		val |= RCAR_USBCTR_PCIAHB_WIN1_2G;
+		break;
+	case SZ_1G:
+		val |= RCAR_USBCTR_PCIAHB_WIN1_1G;
+		break;
+	case SZ_512M:
+		val |= RCAR_USBCTR_PCIAHB_WIN1_512M;
+		break;
+	default:
+		pr_warn("unknown window size %ld - defaulting to 256M\n",
+			priv->window_size);
+		priv->window_size = SZ_256M;
+		/* fall-through */
+	case SZ_256M:
+		val |= RCAR_USBCTR_PCIAHB_WIN1_256M;
+		break;
+	}
+	iowrite32(val, reg + RCAR_USBCTR_REG);
 
 	/* Configure AHB master and slave modes */
 	iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
@@ -194,7 +217,7 @@ static int __init rcar_pci_setup(int nr,
 	       RCAR_PCI_ARBITER_PCIBP_MODE;
 	iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
 
-	/* PCI-AHB mapping: 0x40000000-0x80000000 */
+	/* PCI-AHB mapping: 0x40000000 base */
 	iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
 		  reg + RCAR_PCIAHB_WIN1_CTR_REG);
 
@@ -271,6 +294,8 @@ static int rcar_pci_probe(struct platfor
 	priv->reg = reg;
 	priv->dev = &pdev->dev;
 
+	priv->window_size = SZ_1G;
+
 	memset(&hw, 0, sizeof(hw));
 	hw.nr_controllers = 1;
 	hw.private_data = (void **)&priv;
author maintainer
#7 lore raw

PATCH 3/4 PCI: rcar: Add DMABOUNCE support

In reply to Magnus Damm

From: Magnus Damm <[email protected]>

Add DMABOUNCE support together with a local memory area for all PCI devices hanging off this bridge. 4MiB of memory is set aside for coherent allocations which is shared between the on-chip OHCI and EHCI devices that are hanging off the PCI bridge. With this patch the driver will work for all CONFIG_VMSPLIT settings.

---

 drivers/pci/host/Kconfig         |    2 
 drivers/pci/host/pci-rcar-gen2.c |  262 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 261 insertions(+), 3 deletions(-)
drivers/pci/host/Kconfig +2 -0
@@ -28,6 +28,8 @@ config PCI_TEGRA
 config PCI_RCAR_GEN2
 	bool "Renesas R-Car Gen2 Internal PCI controller"
 	depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
+	select GENERIC_ALLOCATOR
+	select DMABOUNCE
 	help
 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
 	  There are 3 internal PCI controllers available with a single
drivers/pci/host/pci-rcar-gen2.c +259 -3

317 lines not on this page · raw message

author maintainer
#8 lore raw

PATCH 4/4 PCI: rcar: Enable BOUNCE in case of HIGHMEM

In reply to Magnus Damm

From: Magnus Damm <[email protected]>

Select BOUNCE in case of HIGHMEM to enable bounce buffers in the block layer. Without this patch the DMABOUNCE code will error out due to lack of HIGHMEM support, and without DMABOUNCE there will be silent errors.

---

 drivers/pci/host/Kconfig |    1 +
 1 file changed, 1 insertion(+)
drivers/pci/host/Kconfig +1 -0
@@ -30,6 +30,7 @@ config PCI_RCAR_GEN2
 	depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
 	select GENERIC_ALLOCATOR
 	select DMABOUNCE
+	select BOUNCE if HIGHMEM
 	help
 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
 	  There are 3 internal PCI controllers available with a single
#9 lore raw
In reply to Magnus Damm
Quoted 35 lines · Magnus Damm

PCI: rcar: Driver model and physical address space update

[PATCH 01/04] PCI: rcar: Register each instance independently [PATCH 02/04] PCI: rcar: Break out window size handling [PATCH 03/04] PCI: rcar: Add DMABOUNCE support [PATCH 04/04] PCI: rcar: Enable BOUNCE in case of HIGHMEM

These patches update the pci-rcar-gen2.c driver in various ways including cleanups for driver model interface (1/4), readability update (2/4) and also bounce buffer support (3/4, 4/4). Basically the first two are just cleanups and the rest are fixes.

As it is today without these patches the system memory start address is hard coded at 0x4000000 and the window is fixed at 1GiB. So we have board specific code hidden in the driver which is good to avoid.

With these hard coded board specific constants there are some error cases that are not handled, in particular the issue that only maximum 1GiB of physical address space can be used for bus mastering with a single window. The common case of using ARM CONFIG_VMSPLIT_3G results in no visible issues as long as CONFIG_BOUNCE is used, but other CONFIG_VMSPLIT settings will break due to the hard coded 1GiB window not being enough. It has been verified that reducing the window size to 256MB makes the driver behave the same with VMSPLIT_3G as 1GiB window size and other VMSPLIT settings.

To handle the maximum 1GiB physical address space limitation two types of bounce buffers are added. The ARM specific DMABOUNCE code is in 3/4 hooked up to a chunk of local memory that is also handed of as coherent memory to the pci devices hanging off the PCI bridge. The driver makes sure to set the window so the local memory is always included. When the PCI devices are operating and in case memory is used outside the window then the DMABOUNCE buffers kicks in. This makes the driver support all kinds of VMSPLIT settings and window sizes. The BOUNCE code in 4/4 is selected to make sure bounce buffers are used for HIGHMEM.

Quoted 7 lines

With these patches this driver can be used with or without CMA and with or without DMA zone. Basically the system wide memory setup is left to the user. If a DMA zone is used then the PCI window will be setup to cover that. Same thing with CMA.

Tested with USB storage using LPAE and various VMSPLIT settings together with renesas git tag renesas-devel-v3.14-rc1-20140204 from kernel.org

Ok, is it possible to build a set with my of updates ready for next merge window? I can update the set based on this if you like and try and make the necessary changes to deal with the modifications from this series.

Signature · 2 lines
Ben Dooks				http://www.codethink.co.uk/
Senior Engineer				Codethink - Providing Genius
author maintainer
#10 lore raw

Hi Ben,

Quoted 43 lines · Ben Dooks
Quoted 42 lines · Magnus Damm

PCI: rcar: Driver model and physical address space update

[PATCH 01/04] PCI: rcar: Register each instance independently [PATCH 02/04] PCI: rcar: Break out window size handling [PATCH 03/04] PCI: rcar: Add DMABOUNCE support [PATCH 04/04] PCI: rcar: Enable BOUNCE in case of HIGHMEM

These patches update the pci-rcar-gen2.c driver in various ways including cleanups for driver model interface (1/4), readability update (2/4) and also bounce buffer support (3/4, 4/4). Basically the first two are just cleanups and the rest are fixes.

As it is today without these patches the system memory start address is hard coded at 0x4000000 and the window is fixed at 1GiB. So we have board specific code hidden in the driver which is good to avoid.

With these hard coded board specific constants there are some error cases that are not handled, in particular the issue that only maximum 1GiB of physical address space can be used for bus mastering with a single window. The common case of using ARM CONFIG_VMSPLIT_3G results in no visible issues
as long as CONFIG_BOUNCE is used, but other CONFIG_VMSPLIT settings will break due to the hard coded 1GiB window not being enough. It has been verified that reducing the window size to 256MB makes the driver behave the same with VMSPLIT_3G as 1GiB window size and other VMSPLIT settings.

To handle the maximum 1GiB physical address space limitation two types of bounce buffers are added. The ARM specific DMABOUNCE code is in 3/4 hooked up to a chunk of local memory that is also handed of as coherent memory to the pci devices hanging off the PCI bridge. The driver makes sure to set the window so the local memory is always included. When the PCI devices are operating and in case memory is used outside the window then the DMABOUNCE buffers kicks in. This makes the driver support all kinds of VMSPLIT settings and window sizes. The BOUNCE code in 4/4 is selected to make sure bounce buffers are used for HIGHMEM.

With these patches this driver can be used with or without CMA and with or without DMA zone. Basically the system wide memory setup is left to the user. If a DMA zone is used then the PCI window will be setup to cover that. Same thing with CMA.

Quoted 8 lines
Quoted 2 lines

Tested with USB storage using LPAE and various VMSPLIT settings together with renesas git tag renesas-devel-v3.14-rc1-20140204 from kernel.org

Ok, is it possible to build a set with my of updates ready for next merge window? I can update the set based on this if you like and try and make the necessary changes to deal with the modifications from this series.

I think we should try to pick out the stuff that is ready to be merged first. I think these patches may require a bit of time before people start looking at them. I don't mind resending in the future.

To be honest, I have not been paying too much attention to other patches including yours - been focused trying to get the memory management part right.. So I'd like to focus on correctness over DT for now if possible. Of course we it all.

Would it be possible for you to provide a list of pci-rcar-gen2.c patches that you posted? Or perhaps you can resend your series and include acks that you received?

Thanks,

/ magnus

#11 lore raw
Quoted 1 line · Magnus Damm

Hi Ben,

[snip]

Quoted 4 lines

I think we should try to pick out the stuff that is ready to be merged first. I think these patches may require a bit of time before people start looking at them. I don't mind resending in the future.

Quoted 8 lines

To be honest, I have not been paying too much attention to other patches including yours - been focused trying to get the memory management part right.. So I'd like to focus on correctness over DT for now if possible. Of course we it all.

Would it be possible for you to provide a list of pci-rcar-gen2.c patches that you posted? Or perhaps you can resend your series and include acks that you received?

I don't think I have any acks, only review comments. I think the code itself is pretty much ready to be merged and has been tested here with the Lager board.

The big issue for us is that we /must/ boot with fdt, which means the less fdt support that is in the kernel then the more patches we end up carrying out of tree. This is why we have been pushing patches out to try and get the support in.

Signature · 2 lines
Ben Dooks				http://www.codethink.co.uk/
Senior Engineer				Codethink - Providing Genius
author maintainer
#12 lore raw
Quoted 16 lines · Ben Dooks
Quoted 2 lines · Magnus Damm

Hi Ben,

[snip]

Quoted 9 lines

I think we should try to pick out the stuff that is ready to be merged first. I think these patches may require a bit of time before people start looking at them. I don't mind resending in the future.

To be honest, I have not been paying too much attention to other patches including yours - been focused trying to get the memory management part right.. So I'd like to focus on correctness over DT for now if possible. Of course we it all.

Quoted 8 lines
Quoted 3 lines

Would it be possible for you to provide a list of pci-rcar-gen2.c patches that you posted? Or perhaps you can resend your series and include acks that you received?

I don't think I have any acks, only review comments. I think the code itself is pretty much ready to be merged and has been tested here with the Lager board.

Ok, thanks. I'd like to go through them myself if possible. I was looking for a cover letter or something that listed the patches but I can't seem to find it. Can you please provide a list?

Quoted 4 lines

The big issue for us is that we /must/ boot with fdt, which means the less fdt support that is in the kernel then the more patches we end up carrying out of tree. This is why we have been pushing patches out to try and get the support in.

Can you please define "boot with fdt"? As you probably know, both board-lager.c and board-lager-reference.c boot with DT. I suppose you mean that you want DT to describe the entire system, with no C code for the board? Please note that some devices like timers still don't use DT, so if you can live without those then... =)

Thanks,

/ magnus

#13 lore raw
Quoted 22 lines · Magnus Damm
Quoted 21 lines · Ben Dooks
Quoted 2 lines · Magnus Damm

Hi Ben,

[snip]

Quoted 12 lines

I think we should try to pick out the stuff that is ready to be merged first. I think these patches may require a bit of time before people start looking at them. I don't mind resending in the future.

To be honest, I have not been paying too much attention to other patches including yours - been focused trying to get the memory management part right.. So I'd like to focus on correctness over DT for now if possible. Of course we it all.

Would it be possible for you to provide a list of pci-rcar-gen2.c patches that you posted? Or perhaps you can resend your series and include acks that you received?

Quoted 7 lines
Quoted 3 lines

I don't think I have any acks, only review comments. I think the code itself is pretty much ready to be merged and has been tested here with the Lager board.

Ok, thanks. I'd like to go through them myself if possible. I was looking for a cover letter or something that listed the patches but I can't seem to find it. Can you please provide a list?

I will re-send the patches once I've applied the relevant fixups from the last round, hopefully within the next few hours.

Quoted 10 lines
Quoted 4 lines

The big issue for us is that we /must/ boot with fdt, which means the less fdt support that is in the kernel then the more patches we end up carrying out of tree. This is why we have been pushing patches out to try and get the support in.

Can you please define "boot with fdt"? As you probably know, both board-lager.c and board-lager-reference.c boot with DT. I suppose you mean that you want DT to describe the entire system, with no C code for the board? Please note that some devices like timers still don't use DT, so if you can live without those then... =)

We currently have enough to use the system. And yes, we boot with board-lager-reference.c which current seems to be turning up bugs in the up-stream (see the recent new bug with cpg clock code reported by my colleague).

Due to issues out of our control we can test with board-lager.c but we must use the board-lager-reference.c for actual product test. The only way we found around this is ugly hacking of the core driver code to link platform and fdt devices...

Signature · 2 lines
Ben Dooks				http://www.codethink.co.uk/
Senior Engineer				Codethink - Providing Genius
maintainer
#14 lore raw
In reply to Magnus Damm
Quoted 43 lines · Magnus Damm

PCI: rcar: Driver model and physical address space update

[PATCH 01/04] PCI: rcar: Register each instance independently [PATCH 02/04] PCI: rcar: Break out window size handling [PATCH 03/04] PCI: rcar: Add DMABOUNCE support [PATCH 04/04] PCI: rcar: Enable BOUNCE in case of HIGHMEM

These patches update the pci-rcar-gen2.c driver in various ways including cleanups for driver model interface (1/4), readability update (2/4) and also bounce buffer support (3/4, 4/4). Basically the first two are just cleanups and the rest are fixes.

As it is today without these patches the system memory start address is hard coded at 0x4000000 and the window is fixed at 1GiB. So we have board specific code hidden in the driver which is good to avoid.

With these hard coded board specific constants there are some error cases that are not handled, in particular the issue that only maximum 1GiB of physical address space can be used for bus mastering with a single window. The common case of using ARM CONFIG_VMSPLIT_3G results in no visible issues as long as CONFIG_BOUNCE is used, but other CONFIG_VMSPLIT settings will break due to the hard coded 1GiB window not being enough. It has been verified that reducing the window size to 256MB makes the driver behave the same with VMSPLIT_3G as 1GiB window size and other VMSPLIT settings.

To handle the maximum 1GiB physical address space limitation two types of bounce buffers are added. The ARM specific DMABOUNCE code is in 3/4 hooked up to a chunk of local memory that is also handed of as coherent memory to the pci devices hanging off the PCI bridge. The driver makes sure to set the window so the local memory is always included. When the PCI devices are operating and in case memory is used outside the window then the DMABOUNCE buffers kicks in. This makes the driver support all kinds of VMSPLIT settings and window sizes. The BOUNCE code in 4/4 is selected to make sure bounce buffers are used for HIGHMEM.

With these patches this driver can be used with or without CMA and with or without DMA zone. Basically the system wide memory setup is left to the user. If a DMA zone is used then the PCI window will be setup to cover that. Same thing with CMA.

Tested with USB storage using LPAE and various VMSPLIT settings together with renesas git tag renesas-devel-v3.14-rc1-20140204 from kernel.org

Quoted 8 lines

---

Written against renesas.git tag renesas-devel-v3.14-rc1-20140204

 drivers/pci/host/Kconfig         |    3 
 drivers/pci/host/pci-rcar-gen2.c |  367 +++++++++++++++++++++++++++++++-------
 2 files changed, 306 insertions(+), 64 deletions(-)

Simon, if you want to ack these, I'll be happy to merge them for v3.15. I'm not really qualified to review them myself.

Bjorn

#15 lore raw
Quoted 47 lines · Bjorn Helgaas
Quoted 46 lines · Magnus Damm

PCI: rcar: Driver model and physical address space update

[PATCH 01/04] PCI: rcar: Register each instance independently [PATCH 02/04] PCI: rcar: Break out window size handling [PATCH 03/04] PCI: rcar: Add DMABOUNCE support [PATCH 04/04] PCI: rcar: Enable BOUNCE in case of HIGHMEM

These patches update the pci-rcar-gen2.c driver in various ways including cleanups for driver model interface (1/4), readability update (2/4) and also bounce buffer support (3/4, 4/4). Basically the first two are just cleanups and the rest are fixes.

As it is today without these patches the system memory start address is hard coded at 0x4000000 and the window is fixed at 1GiB. So we have board specific code hidden in the driver which is good to avoid.

With these hard coded board specific constants there are some error cases that are not handled, in particular the issue that only maximum 1GiB of physical address space can be used for bus mastering with a single window. The common case of using ARM CONFIG_VMSPLIT_3G results in no visible issues as long as CONFIG_BOUNCE is used, but other CONFIG_VMSPLIT settings will break due to the hard coded 1GiB window not being enough. It has been verified that reducing the window size to 256MB makes the driver behave the same with VMSPLIT_3G as 1GiB window size and other VMSPLIT settings.

To handle the maximum 1GiB physical address space limitation two types of bounce buffers are added. The ARM specific DMABOUNCE code is in 3/4 hooked up to a chunk of local memory that is also handed of as coherent memory to the pci devices hanging off the PCI bridge. The driver makes sure to set the window so the local memory is always included. When the PCI devices are operating and in case memory is used outside the window then the DMABOUNCE buffers kicks in. This makes the driver support all kinds of VMSPLIT settings and window sizes. The BOUNCE code in 4/4 is selected to make sure bounce buffers are used for HIGHMEM.

With these patches this driver can be used with or without CMA and with or without DMA zone. Basically the system wide memory setup is left to the user. If a DMA zone is used then the PCI window will be setup to cover that. Same thing with CMA.

Tested with USB storage using LPAE and various VMSPLIT settings together with renesas git tag renesas-devel-v3.14-rc1-20140204 from kernel.org

---

Quoted 8 lines
Quoted 5 lines

Written against renesas.git tag renesas-devel-v3.14-rc1-20140204

 drivers/pci/host/Kconfig         |    3 
 drivers/pci/host/pci-rcar-gen2.c |  367 +++++++++++++++++++++++++++++++-------
 2 files changed, 306 insertions(+), 64 deletions(-)

Simon, if you want to ack these, I'll be happy to merge them for v3.15. I'm not really qualified to review them myself.

Hi Bjorn,

Magnus has reposted these patches as part of a larger series which includes some patches of his own. That series is "[PATCH 00/08] PCI: rcar: Recent driver patches from Ben Dooks and me". I am happy with it and will Ack it. Could you consider merging it?