[PATCH 2/2] arm: mvebu: Add hardware I/O Coherency support

Yehuda Yitschak yehuday at marvell.com
Wed Oct 24 04:11:34 EDT 2012



> -----Original Message-----
> From: Gregory CLEMENT [mailto:gregory.clement at free-electrons.com]
> Sent: Wednesday, October 24, 2012 10:04 AM
> To: Jason Cooper; Andrew Lunn; Gregory Clement
> Cc: linux-arm-kernel at lists.infradead.org; Arnd Bergmann; Olof Johansson;
> Russell King; Rob Herring; Ben Dooks; Ian Molton; Nicolas Pitre; Lior
> Amsalem; Maen Suleiman; Tawfik Bayouk; Shadi Ammouri; Eran Ben-Avi;
> Yehuda Yitschak; Nadav Haklai; Ike Pan; Jani Monoses; Chris Van Hoof; Dan
> Frazier; Thomas Petazzoni; Leif Lindholm; Jon Masters; David Marlin;
> Sebastian Hesselbarth; linux-kernel at vger.kernel.org
> Subject: [PATCH 2/2] arm: mvebu: Add hardware I/O Coherency support
> 
> Armada 370 and XP come with an unit called coherency fabric. This unit
> allows to use the Armada XP as a nearly coherent architecture. The
> coherency mechanism uses snoop filters to ensure the coherency between
> caches, DRAM and devices. This mechanism needs a synchronization barrier
> which guarantees that all memory write initiated by the devices has
> reached their target and do not reside in intermediate write buffers. That's
> why the architecture is not totally coherent and we need to provide our
> own functions for some DMA operations.
> 
> Beside the use of the coherency fabric, the device units will have to set the
> attribute flag to select the accurate coherency process for the memory
> transaction. This is done each device driver programs the DRAM address
> windows. The value of the attribute set by the driver is retrieved through
> the orion_addr_map_cfg struct filled during the early initialization of the
> platform.
> 
> Signed-off-by: Gregory CLEMENT <gregory.clement at free-electrons.com>
> Reviewed-by: Yehuda Yitschak <yehuday at marvell.com>
> ---
>  arch/arm/boot/dts/armada-370-xp.dtsi |    3 +-
>  arch/arm/mach-mvebu/addr-map.c       |    3 ++
>  arch/arm/mach-mvebu/armada-370-xp.c  |    1 +
>  arch/arm/mach-mvebu/coherency.c      |   87
> ++++++++++++++++++++++++++++++++++
>  arch/arm/mach-mvebu/common.h         |    2 +
>  5 files changed, 95 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi
> b/arch/arm/boot/dts/armada-370-xp.dtsi
> index 18ba60b..af22e53 100644
> --- a/arch/arm/boot/dts/armada-370-xp.dtsi
> +++ b/arch/arm/boot/dts/armada-370-xp.dtsi
> @@ -38,7 +38,8 @@
> 
>  	coherency-fabric at d0020200 {
>  		compatible = "marvell,coherency-fabric";
> -		reg = <0xd0020200 0xb0>;
> +		reg = <0xd0020200 0xb0>,
> +		      <0xd0021010 0x1c>;
>  	};
> 
>  	soc {
> diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-
> mvebu/addr-map.c index fe454a4..595f6b7 100644
> --- a/arch/arm/mach-mvebu/addr-map.c
> +++ b/arch/arm/mach-mvebu/addr-map.c
> @@ -108,6 +108,9 @@ static int __init armada_setup_cpu_mbus(void)
> 
>  	addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base;
> 
> +	if (of_find_compatible_node(NULL, NULL, "marvell,coherency-
> fabric"))
> +		addr_map_cfg.hw_io_coherency = 1;
> +
>  	/*
>  	 * Disable, clear and configure windows.
>  	 */
> diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-
> mvebu/armada-370-xp.c
> index 41431a1..3517f7d 100644
> --- a/arch/arm/mach-mvebu/armada-370-xp.c
> +++ b/arch/arm/mach-mvebu/armada-370-xp.c
> @@ -49,6 +49,7 @@ struct sys_timer armada_370_xp_timer = {
> 
>  static void __init armada_370_xp_dt_init(void)  {
> +	armada_370_xp_coherency_iocache_init();
>  	of_platform_populate(NULL, of_default_bus_match_table, NULL,
> NULL);  }
> 
> diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-
> mvebu/coherency.c index 71e27ba..a596ca9 100644
> --- a/arch/arm/mach-mvebu/coherency.c
> +++ b/arch/arm/mach-mvebu/coherency.c
> @@ -22,6 +22,10 @@
>  #include <linux/of_address.h>
>  #include <linux/io.h>
>  #include <linux/smp.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/platform_device.h>
> +#include <asm/smp_plat.h>
> +
>  #include "armada-370-xp.h"
> 
>  /* Some functions in this file are called very early during SMP @@ -31,16
> +35,53 @@
>   * value matching its virtual mapping
>   */
>  static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE
> + 0x20200;
> +static void __iomem *coherency_cpu_base;
> +
> +struct dma_map_ops armada_xp_dma_ops;
> 
>  /* Coherency fabric registers */
>  #define COHERENCY_FABRIC_CTL_OFFSET		   0x0
>  #define COHERENCY_FABRIC_CFG_OFFSET		   0x4
> 
> +#define IO_SYNC_BARRIER_CTL_OFFSET		   0x0
> +
>  static struct of_device_id of_coherency_table[] = {
>  	{.compatible = "marvell,coherency-fabric"},
>  	{ /* end of list */ },
>  };
> 
> +static inline void armada_xp_sync_io_barrier(void) {
> +	writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
> +	while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET)
> & 0x1);
> +}
> +
> +dma_addr_t armada_xp_dma_map_page(struct device *dev, struct page
> *page,
> +				  unsigned long offset, size_t size,
> +				  enum dma_data_direction dir,
> +				  struct dma_attrs *attrs)
> +{
> +	if (dir != DMA_TO_DEVICE)
> +		armada_xp_sync_io_barrier();
> +	return pfn_to_dma(dev, page_to_pfn(page)) + offset; }
> +
> +
> +void armada_xp_dma_unmap_page(struct device *dev, dma_addr_t
> dma_handle,
> +			      size_t size, enum dma_data_direction dir,
> +			      struct dma_attrs *attrs)
> +{
> +	if (dir != DMA_TO_DEVICE)
> +		armada_xp_sync_io_barrier();
> +}
> +
> +void armada_xp_dma_sync(struct device *dev, dma_addr_t dma_handle,
> +			size_t size, enum dma_data_direction dir) {
> +	if (dir != DMA_TO_DEVICE)
> +		armada_xp_sync_io_barrier();
> +}
> +

Shouldn't all the 4 functions above start with armada_370_xp and not armada_xp ? 


>  int armada_xp_get_cpu_count(void)

This function can be limited to CONFIG_SP

>  {
>  	int reg, cnt;
> @@ -74,6 +115,42 @@ int armada_370_xp_set_cpu_coherent(unsigned int
> hw_cpu_id, int smp_group_id)
>  	return 0;
>  }
> 
> +static int armada_xp_platform_notifier(struct notifier_block *nb,
> +				       unsigned long event, void *__dev) {
> +	struct device *dev = __dev;
> +
> +	if (event != BUS_NOTIFY_ADD_DEVICE)
> +		return NOTIFY_DONE;
> +	set_dma_ops(dev, &armada_xp_dma_ops);
> +
> +	return NOTIFY_OK;
> +}
> +
> +static struct notifier_block armada_xp_platform_nb = {
> +	.notifier_call = armada_xp_platform_notifier, };
> +
> +void __init armada_370_xp_coherency_iocache_init(void)
> +{
> +	/* When the coherency fabric is available, the Armada XP and
> +	 * Aramada 370 are close to a coherent architecture, so we based
> +	 * our dma ops on the coherent one, and just changes the
> +	 * operations which need a arch io sync */
> +	if (of_find_compatible_node(NULL, NULL, "marvell,coherency-
> fabric")) {
> +		struct dma_map_ops *dma_ops = &armada_xp_dma_ops;
> +		memcpy(dma_ops, &arm_coherent_dma_ops,
> sizeof(*dma_ops));
> +		dma_ops->map_page = armada_xp_dma_map_page;
> +		dma_ops->unmap_page = armada_xp_dma_unmap_page;
> +		dma_ops->unmap_sg = arm_dma_ops.unmap_sg;
> +		dma_ops->sync_single_for_cpu = armada_xp_dma_sync;
> +		dma_ops->sync_single_for_device = armada_xp_dma_sync;
> +		dma_ops->sync_sg_for_cpu =
> arm_dma_ops.sync_sg_for_cpu;
> +		dma_ops->sync_sg_for_device =
> arm_dma_ops.sync_sg_for_device;
> +	}
> +	bus_register_notifier(&platform_bus_type,
> &armada_xp_platform_nb); }
> +
>  int __init armada_370_xp_coherency_init(void)
>  {
>  	struct device_node *np;
> @@ -82,7 +159,17 @@ int __init armada_370_xp_coherency_init(void)
>  	if (np) {
>  		pr_info("Initializing Coherency fabric\n");
>  		coherency_base = of_iomap(np, 0);
> +		coherency_cpu_base = of_iomap(np, 1);
> +	}
> +#ifndef CONFIG_SMP
> +	if (coherency_base) {
> +		/* In UP case, cpu coherency is enabled here, in SMP case
> cpu
> +		 * coherency is enabled for each CPU by
> +		 * armada_xp_smp_prepare_cpus() in platsmp.c */
> +		int hw_cpuid = cpu_logical_map(smp_processor_id());
> +		armada_370_xp_set_cpu_coherent(hw_cpuid, 0);
>  	}
> +#endif
> 
>  	return 0;
>  }
> diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-
> mvebu/common.h index 86484bb..fff952e 100644
> --- a/arch/arm/mach-mvebu/common.h
> +++ b/arch/arm/mach-mvebu/common.h
> @@ -23,6 +23,8 @@ void armada_370_xp_handle_irq(struct pt_regs *regs);
> 
>  void armada_xp_cpu_die(unsigned int cpu);
> 
> +void armada_370_xp_coherency_iocache_init(void);
> +
>  int armada_370_xp_coherency_init(void);
>  int armada_370_xp_pmsu_init(void);
>  void armada_xp_secondary_startup(void);
> --
> 1.7.9.5




More information about the linux-arm-kernel mailing list