Add hardware I/O coherency support for Armada 370/XP
Subsystems (5)
v4 cover Add hardware I/O coherency support for Armada 370/XP
The purpose of this patch set is to add hardware I/O Coherency support for Armada 370 and Armada XP. Theses SoCs come with an unit called coherency fabric. A beginning of the support for this unit have been introduced with the SMP patch set. This series extend this support:
the coherency fabric unit allows to use the Armada XP and the Armada 370 as nearly coherent architectures.
The third patches enables this new feature and register our own set of DMA ops, to benefit this hardware enhancement.
The first patches exports dma operation functions needed by to register our own set of dma ops.
The second patch introduces a new flag for the address decoding configuration in order to be able to set the memory windows as shared memory.
This series depend on the SMP patch set (V5 was posted few minutes earlier)
The git branch called HWIOCC-for-3.8-V3 is also available at
https://github.com/MISL-EBU-System-SW/mainline-public.git.
Changelog:V3->V4:
- Exposed only the needed dma ops function
V2 -> V3:
- Rebased on to ArmadaXP-SMP-for-3.8-V5
- Use the coherent version of dma ops for .alloc() and .free()
V1 -> V2:
- Rebased on to v3.7-rc5
- Added a new patch to exports the dma ops functions
- Renamed the function for a more generic name mvebu_hwcc
- removed the non SMP case during init
- spelling and wording issues
- updating the binding documentation for coherency fabric
Gregory CLEMENT (3):
arm: dma mapping: Export a dma ops function arm_dma_set_mask
arm: plat-orion: Add coherency attribute when setup mbus target
arm: mvebu: Add hardware I/O Coherency support
.../devicetree/bindings/arm/coherency-fabric.txt | 9 ++- arch/arm/boot/dts/armada-370-xp.dtsi | 3 +- arch/arm/include/asm/dma-mapping.h | 2 + arch/arm/mach-mvebu/addr-map.c | 3 + arch/arm/mach-mvebu/coherency.c | 73 ++++++++++++++++++++ arch/arm/mm/dma-mapping.c | 4 +- arch/arm/plat-orion/addr-map.c | 4 ++ arch/arm/plat-orion/include/plat/addr-map.h | 1 + 8 files changed, 93 insertions(+), 6 deletions(-)
Signature · 1 line
1.7.9.5
PATCH v4 1/3 arm: dma mapping: Export a dma ops function arm_dma_set_mask
Expose another DMA operations function: arm_dma_set_mask. This function will be added to a custom DMA ops for Armada 370/XP. Depending of its configuration Armada 370/XP can be set as a "nearly" coherent architecture. In this case the DMA ops is made of:
- specific functions for this architecture
- already exposed arm DMA related functions
- the arm_dma_set_mask which was not exposed yet.
--- arch/arm/include/asm/dma-mapping.h | 2 ++ arch/arm/mm/dma-mapping.c | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-)
arch/arm/include/asm/dma-mapping.h +2 -0
@@ -111,6 +111,8 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size,extern int dma_supported (struct device *dev,u64 mask); +extern int arm_dma_set_mask (struct device *dev,u64 dma_mask); +/** * arm_dma_alloc - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
arch/arm/mm/dma-mapping.c +1 -3
@@ -124,8 +124,6 @@ static void arm_dma_sync_single_for_device(struct device *dev,__dma_page_cpu_to_dev (page, offset, size, dir); } -static int arm_dma_set_mask (struct device *dev,u64 dma_mask); -struct dma_map_ops arm_dma_ops = { .alloc = arm_dma_alloc, .free = arm_dma_free,
@@ -971,7 +969,7 @@ int dma_supported(struct device *dev, u64 mask) }EXPORT_SYMBOL (dma_supported); -static int arm_dma_set_mask (struct device *dev,u64 dma_mask) +int arm_dma_set_mask (struct device *dev,u64 dma_mask) {if (!dev->dma_mask || !dma_supported (dev, dma_mask))return -EIO ;
Signature · 1 line
1.7.9.5
PATCH v4 1/3 arm: dma mapping: Export a dma ops function arm_dma_set_mask
Hello,
Quoted 9 lines · Gregory CLEMENT
Expose another DMA operations function:
arm_dma_set_mask. This function will be added to a custom DMA ops for Armada 370/XP. Depending of its configuration Armada 370/XP can be set as a "nearly" coherent architecture. In this case the DMA ops is made of:
- specific functions for this architecture
- already exposed arm DMA related functions
- thearm_dma_set_maskwhich was not exposed yet.Signed-off-by Gregory CLEMENT <[email protected]>
Quoted 32 lines
--- arch/arm/include/asm/dma-mapping.h | 2 ++ arch/arm/mm/dma-mapping.c | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-)arch/arm/include/asm/dma-mapping.h +2
-0@@ -111,6 +111,8 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size,extern int dma_supported (struct device *dev,u64 mask); +extern int arm_dma_set_mask (struct device *dev,u64 dma_mask); +/** * arm_dma_alloc - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices arch/arm/mm/dma-mapping.c +0
-2@@ -124,8 +124,6 @@ static void arm_dma_sync_single_for_device(struct device *dev,__dma_page_cpu_to_dev (page, offset, size, dir); } -static int arm_dma_set_mask (struct device *dev,u64 dma_mask); -struct dma_map_ops arm_dma_ops = { .alloc = arm_dma_alloc, .free = arm_dma_free,
arch/arm/mm/dma-mapping.c int dma_supported(struct device *dev, u64 mask) · line 975
Quoted 8 lines
arch/arm/mm/dma-mapping.c +1
-1@@ -971,7 +969,7 @@ int dma_supported(struct device *dev, u64 mask) }EXPORT_SYMBOL (dma_supported); -static int arm_dma_set_mask (struct device *dev,u64 dma_mask) +int arm_dma_set_mask (struct device *dev,u64 dma_mask) {if (!dev->dma_mask || !dma_supported (dev, dma_mask))return -EIO ;
Best regards
Signature · 2 lines
Marek Szyprowski Samsung Poland R&D Center
PATCH v4 1/3 arm: dma mapping: Export a dma ops function arm_dma_set_mask
Quoted 11 lines · Marek Szyprowski
Hello,
Quoted 8 lines · Gregory CLEMENT
Expose another DMA operations function:
arm_dma_set_mask. This function will be added to a custom DMA ops for Armada 370/XP. Depending of its configuration Armada 370/XP can be set as a "nearly" coherent architecture. In this case the DMA ops is made of:
- specific functions for this architecture
- already exposed arm DMA related functions
- thearm_dma_set_maskwhich was not exposed yet.
Quoted 3 lines
Quoted 1 line
Signed-off-by Gregory CLEMENT <[email protected]>Acked-by Marek Szyprowski <[email protected]>
Thanks!
Quoted 44 lines
Quoted 33 lines
--- arch/arm/include/asm/dma-mapping.h | 2 ++ arch/arm/mm/dma-mapping.c | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-)arch/arm/include/asm/dma-mapping.h +2
-0@@ -111,6 +111,8 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size,extern int dma_supported (struct device *dev,u64 mask); +extern int arm_dma_set_mask (struct device *dev,u64 dma_mask); +/** * arm_dma_alloc - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices arch/arm/mm/dma-mapping.c +0
-2@@ -124,8 +124,6 @@ static void arm_dma_sync_single_for_device(struct device *dev,__dma_page_cpu_to_dev (page, offset, size, dir); } -static int arm_dma_set_mask (struct device *dev,u64 dma_mask); -struct dma_map_ops arm_dma_ops = { .alloc = arm_dma_alloc, .free = arm_dma_free,arch/arm/mm/dma-mapping.c int dma_supported(struct device *dev, u64 mask) · line 975
Quoted 8 lines
arch/arm/mm/dma-mapping.c +1
-1@@ -971,7 +969,7 @@ int dma_supported(struct device *dev, u64 mask) }EXPORT_SYMBOL (dma_supported); -static int arm_dma_set_mask (struct device *dev,u64 dma_mask) +int arm_dma_set_mask (struct device *dev,u64 dma_mask) {if (!dev->dma_mask || !dma_supported (dev, dma_mask))return -EIO ;Best regards
Signature · 4 lines
Gregory Clement, Free Electrons Kernel, drivers, real-time and embedded Linux development, consulting, training and support. http://free-electrons.com
PATCH v4 2/3 arm: plat-orion: Add coherency attribute when setup mbus target
In reply to Gregory CLEMENTRecent SoC such as Armada 370/XP came with the possibility to deal with the I/O coherency by hardware. In this case the transaction attribute of the window must be flagged as "Shared transaction". Once this flag is set, then the transactions will be forced to be sent through the coherency block, in other case transaction is driven directly to DRAM.
--- arch/arm/plat-orion/addr-map.c | 4 ++++ arch/arm/plat-orion/include/plat/addr-map.h | 1 + 2 files changed, 5 insertions(+)
arch/arm/plat-orion/addr-map.c +4 -0
@@ -42,6 +42,8 @@ EXPORT_SYMBOL_GPL(mv_mbus_dram_info);#define WIN_REMAP_LO_OFF 0x0008#define WIN_REMAP_HI_OFF 0x000c +#define ATTR_HW_COHERENCY (0x1 << 4) +/* * Default implementation */
@@ -163,6 +165,8 @@ void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg, w = &orion_mbus_dram_info.cs[cs++]; w->cs_index = i; w->mbus_attr =0xf & ~(1 << i); +if (cfg->hw_io_coherency) + w->mbus_attr |=ATTR_HW_COHERENCY ; w->base = base &0xffff0000 ; w->size = (size |0x0000ffff ) +1 ; }
arch/arm/plat-orion/include/plat/addr-map.h +1 -0
@@ -17,6 +17,7 @@ struct orion_addr_map_cfg {const int num_wins;/* Total number of windows */ const int remappable_wins;void __iomem *bridge_virt_base; +int hw_io_coherency;/* If NULL, the default cpu_win_can_remap will be used, using the value in remappable_wins */
Signature · 1 line
1.7.9.5
PATCH v4 3/3 arm: mvebu: Add hardware I/O Coherency support
In reply to Gregory CLEMENTArmada 370 and XP come with an unit called coherency fabric. This unit allows to use the Armada 370/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 the memory writes initiated by the devices have 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 of the decoding address window 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.
--- .../devicetree/bindings/arm/coherency-fabric.txt | 9 ++- arch/arm/boot/dts/armada-370-xp.dtsi | 3 +- arch/arm/mach-mvebu/addr-map.c | 3 + arch/arm/mach-mvebu/coherency.c | 73 ++++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-)
Documentation/devicetree/bindings/arm/coherency-fabric.txt +7 -2
@@ -5,12 +5,17 @@ Available on Marvell SOCs: Armada 370 and Armada XP Required properties: - compatible: "marvell,coherency-fabric" -- reg: Should contain,coherency fabric registers location and length. + +- reg: Should contain coherency fabric registers location and + length. First pair for the coherency fabric registers, second pair + for the per-CPU fabric registers registers. Example: coherency-fabric at d0020200 { compatible = "marvell,coherency-fabric"; - reg = <0xd0020200 0xb0>; + reg = <0xd0020200 0xb0>, + <0xd0021810 0x1c>; + };
arch/arm/boot/dts/armada-370-xp.dtsi +2 -1
@@ -38,7 +38,8 @@ coherency-fabric at d0020200 { compatible = "marvell,coherency-fabric"; - reg = <0xd0020200 0xb0>; + reg = <0xd0020200 0xb0>, + <0xd0021810 0x1c>; }; soc {
arch/arm/mach-mvebu/addr-map.c +3 -0
@@ -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. */
arch/arm/mach-mvebu/coherency.c +73 -0
101 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH v4 3/3 arm: mvebu: Add hardware I/O Coherency support
Hello,
Quoted 17 lines · Gregory CLEMENT
Armada 370 and XP come with an unit called coherency fabric. This unit allows to use the Armada 370/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 the memory writes initiated by the devices have 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 of the decoding address window 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_cfgstruct filled during the early initialization of the platform.
Quoted 2 lines
Signed-off-by Gregory CLEMENT <[email protected]>Reviewed-by Yehuda Yitschak <[email protected]>
Quoted 158 lines
--- .../devicetree/bindings/arm/coherency-fabric.txt | 9 ++- arch/arm/boot/dts/armada-370-xp.dtsi | 3 +- arch/arm/mach-mvebu/addr-map.c | 3 + arch/arm/mach-mvebu/coherency.c | 73 ++++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-)Documentation/devicetree/bindings/arm/coherency-fabric.txt +7
-2@@ -5,12 +5,17 @@ Available on Marvell SOCs: Armada 370 and Armada XP Required properties: - compatible: "marvell,coherency-fabric" -- reg: Should contain,coherency fabric registers location and length. + +- reg: Should contain coherency fabric registers location and + length. First pair for the coherency fabric registers, second pair + for the per-CPU fabric registers registers. Example: coherency-fabric at d0020200 { compatible = "marvell,coherency-fabric"; - reg = <0xd0020200 0xb0>; + reg = <0xd0020200 0xb0>, + <0xd0021810 0x1c>; + };arch/arm/boot/dts/armada-370-xp.dtsi +2
-1@@ -38,7 +38,8 @@ coherency-fabric at d0020200 { compatible = "marvell,coherency-fabric"; - reg = <0xd0020200 0xb0>; + reg = <0xd0020200 0xb0>, + <0xd0021810 0x1c>; }; soc {arch/arm/mach-mvebu/addr-map.c +3
-0@@ -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. */ arch/arm/mach-mvebu/coherency.c +69
-0@@ -22,6 +22,8 @@#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" @@ -32,10 +34,13 @@* value matching its virtual mapping */ static void __iomem *coherency_base =ARMADA_370_XP_REGS_VIRT_BASE +0x20200 ; +static void __iomem *coherency_cpu_base;/* Coherency fabric registers */ #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 */ },@@ -66,6 +71,70 @@ int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id)return 0 ; } +static inline void mvebu_hwcc_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 ); +} + +static dma_addr_t mvebu_hwcc_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 ) +mvebu_hwcc_sync_io_barrier (); +return pfn_to_dma (dev,page_to_pfn (page)) + offset; +} + + +static void mvebu_hwcc_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 ) +mvebu_hwcc_sync_io_barrier (); +} + +static void mvebu_hwcc_dma_sync (struct device *dev,dma_addr_t dma_handle, +size_t size,enum dma_data_direction dir) +{ +if (dir !=DMA_TO_DEVICE ) +mvebu_hwcc_sync_io_barrier (); +} + +static struct dma_map_ops mvebu_hwcc_dma_ops = { + .alloc = arm_dma_alloc, + .free = arm_dma_free, + .mmap = arm_dma_mmap, + .map_page = mvebu_hwcc_dma_map_page, + .unmap_page = mvebu_hwcc_dma_unmap_page, + .get_sgtable = arm_dma_get_sgtable, + .map_sg = arm_dma_map_sg, + .unmap_sg = arm_dma_unmap_sg, + .sync_single_for_cpu = mvebu_hwcc_dma_sync, + .sync_single_for_device = mvebu_hwcc_dma_sync, + .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu, + .sync_sg_for_device = arm_dma_sync_sg_for_device, + .set_dma_mask = arm_dma_set_mask, +}; + +static int mvebu_hwcc_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, &mvebu_hwcc_dma_ops); + +return NOTIFY_OK ; +} + +static struct notifier_block mvebu_hwcc_platform_nb = { + .notifier_call = mvebu_hwcc_platform_notifier, +}; +int __init coherency_init (void ) {struct device_node *np;
arch/arm/mach-mvebu/coherency.c int __init coherency_init(void) · line 152
Quoted 10 lines
arch/arm/mach-mvebu/coherency.c +4
-0@@ -74,6 +143,10 @@ int __init coherency_init(void)if (np) {pr_info ("Initializing Coherency fabric\n" ); coherency_base =of_iomap (np,0 ); + coherency_cpu_base =of_iomap (np,1 ); +set_cpu_coherent (cpu_logical_map (smp_processor_id ()),0 ); +bus_register_notifier (&platform_bus_type, + &mvebu_hwcc_platform_nb); }return 0 ;
Best regards
Signature · 2 lines
Marek Szyprowski Samsung Poland R&D Center