aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Cooper <jason@lakedaemon.net>2012-11-21 15:02:46 -0500
committerJason Cooper <jason@lakedaemon.net>2012-11-21 15:02:46 -0500
commit32d6448a08bdbe6d22fcff1dfffb8399003282df (patch)
tree6e41aeca1077b430f2fc82b43463c68bec6478c4
parent86b7d3f7797908914735da83eb30df9d81fbd50a (diff)
parente60304f8cb7bb545e79fe62d9b9762460c254ec2 (diff)
Merge tag 'marvell-hwiocc-for-3.8' of git://github.com/MISL-EBU-System-SW/mainline-public into mvebu/everything
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 a dma operation function needed 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.
-rw-r--r--Documentation/devicetree/bindings/arm/coherency-fabric.txt9
-rw-r--r--arch/arm/boot/dts/armada-370-xp.dtsi3
-rw-r--r--arch/arm/include/asm/dma-mapping.h2
-rw-r--r--arch/arm/mach-mvebu/addr-map.c3
-rw-r--r--arch/arm/mach-mvebu/coherency.c73
-rw-r--r--arch/arm/mm/dma-mapping.c4
-rw-r--r--arch/arm/plat-orion/addr-map.c4
-rw-r--r--arch/arm/plat-orion/include/plat/addr-map.h1
8 files changed, 93 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/arm/coherency-fabric.txt b/Documentation/devicetree/bindings/arm/coherency-fabric.txt
index 2bfbf67dd77..17d8cd10755 100644
--- a/Documentation/devicetree/bindings/arm/coherency-fabric.txt
+++ b/Documentation/devicetree/bindings/arm/coherency-fabric.txt
@@ -5,12 +5,17 @@ Available on Marvell SOCs: Armada 370 and Armada XP
5Required properties: 5Required properties:
6 6
7- compatible: "marvell,coherency-fabric" 7- compatible: "marvell,coherency-fabric"
8- reg: Should contain,coherency fabric registers location and length. 8
9- reg: Should contain coherency fabric registers location and
10 length. First pair for the coherency fabric registers, second pair
11 for the per-CPU fabric registers registers.
9 12
10Example: 13Example:
11 14
12coherency-fabric@d0020200 { 15coherency-fabric@d0020200 {
13 compatible = "marvell,coherency-fabric"; 16 compatible = "marvell,coherency-fabric";
14 reg = <0xd0020200 0xb0>; 17 reg = <0xd0020200 0xb0>,
18 <0xd0021810 0x1c>;
19
15}; 20};
16 21
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index af7d16e5a02..9f43d0efe5d 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -38,7 +38,8 @@
38 38
39 coherency-fabric@d0020200 { 39 coherency-fabric@d0020200 {
40 compatible = "marvell,coherency-fabric"; 40 compatible = "marvell,coherency-fabric";
41 reg = <0xd0020200 0xb0>; 41 reg = <0xd0020200 0xb0>,
42 <0xd0021810 0x1c>;
42 }; 43 };
43 44
44 soc { 45 soc {
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 23004847bb0..98d4dabb2c1 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -111,6 +111,8 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size,
111 111
112extern int dma_supported(struct device *dev, u64 mask); 112extern int dma_supported(struct device *dev, u64 mask);
113 113
114extern int arm_dma_set_mask(struct device *dev, u64 dma_mask);
115
114/** 116/**
115 * arm_dma_alloc - allocate consistent memory for DMA 117 * arm_dma_alloc - allocate consistent memory for DMA
116 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices 118 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-mvebu/addr-map.c
index fe454a4430b..595f6b722a8 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)
108 108
109 addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base; 109 addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base;
110 110
111 if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"))
112 addr_map_cfg.hw_io_coherency = 1;
113
111 /* 114 /*
112 * Disable, clear and configure windows. 115 * Disable, clear and configure windows.
113 */ 116 */
diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c
index 596ee66a9cc..8278960066c 100644
--- a/arch/arm/mach-mvebu/coherency.c
+++ b/arch/arm/mach-mvebu/coherency.c
@@ -22,6 +22,8 @@
22#include <linux/of_address.h> 22#include <linux/of_address.h>
23#include <linux/io.h> 23#include <linux/io.h>
24#include <linux/smp.h> 24#include <linux/smp.h>
25#include <linux/dma-mapping.h>
26#include <linux/platform_device.h>
25#include <asm/smp_plat.h> 27#include <asm/smp_plat.h>
26#include "armada-370-xp.h" 28#include "armada-370-xp.h"
27 29
@@ -33,10 +35,13 @@
33 * value matching its virtual mapping 35 * value matching its virtual mapping
34 */ 36 */
35static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200; 37static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200;
38static void __iomem *coherency_cpu_base;
36 39
37/* Coherency fabric registers */ 40/* Coherency fabric registers */
38#define COHERENCY_FABRIC_CFG_OFFSET 0x4 41#define COHERENCY_FABRIC_CFG_OFFSET 0x4
39 42
43#define IO_SYNC_BARRIER_CTL_OFFSET 0x0
44
40static struct of_device_id of_coherency_table[] = { 45static struct of_device_id of_coherency_table[] = {
41 {.compatible = "marvell,coherency-fabric"}, 46 {.compatible = "marvell,coherency-fabric"},
42 { /* end of list */ }, 47 { /* end of list */ },
@@ -68,6 +73,70 @@ int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id)
68 return ll_set_cpu_coherent(coherency_base, hw_cpu_id); 73 return ll_set_cpu_coherent(coherency_base, hw_cpu_id);
69} 74}
70 75
76static inline void mvebu_hwcc_sync_io_barrier(void)
77{
78 writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
79 while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
80}
81
82static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page,
83 unsigned long offset, size_t size,
84 enum dma_data_direction dir,
85 struct dma_attrs *attrs)
86{
87 if (dir != DMA_TO_DEVICE)
88 mvebu_hwcc_sync_io_barrier();
89 return pfn_to_dma(dev, page_to_pfn(page)) + offset;
90}
91
92
93static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
94 size_t size, enum dma_data_direction dir,
95 struct dma_attrs *attrs)
96{
97 if (dir != DMA_TO_DEVICE)
98 mvebu_hwcc_sync_io_barrier();
99}
100
101static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle,
102 size_t size, enum dma_data_direction dir)
103{
104 if (dir != DMA_TO_DEVICE)
105 mvebu_hwcc_sync_io_barrier();
106}
107
108static struct dma_map_ops mvebu_hwcc_dma_ops = {
109 .alloc = arm_dma_alloc,
110 .free = arm_dma_free,
111 .mmap = arm_dma_mmap,
112 .map_page = mvebu_hwcc_dma_map_page,
113 .unmap_page = mvebu_hwcc_dma_unmap_page,
114 .get_sgtable = arm_dma_get_sgtable,
115 .map_sg = arm_dma_map_sg,
116 .unmap_sg = arm_dma_unmap_sg,
117 .sync_single_for_cpu = mvebu_hwcc_dma_sync,
118 .sync_single_for_device = mvebu_hwcc_dma_sync,
119 .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
120 .sync_sg_for_device = arm_dma_sync_sg_for_device,
121 .set_dma_mask = arm_dma_set_mask,
122};
123
124static int mvebu_hwcc_platform_notifier(struct notifier_block *nb,
125 unsigned long event, void *__dev)
126{
127 struct device *dev = __dev;
128
129 if (event != BUS_NOTIFY_ADD_DEVICE)
130 return NOTIFY_DONE;
131 set_dma_ops(dev, &mvebu_hwcc_dma_ops);
132
133 return NOTIFY_OK;
134}
135
136static struct notifier_block mvebu_hwcc_platform_nb = {
137 .notifier_call = mvebu_hwcc_platform_notifier,
138};
139
71int __init coherency_init(void) 140int __init coherency_init(void)
72{ 141{
73 struct device_node *np; 142 struct device_node *np;
@@ -76,6 +145,10 @@ int __init coherency_init(void)
76 if (np) { 145 if (np) {
77 pr_info("Initializing Coherency fabric\n"); 146 pr_info("Initializing Coherency fabric\n");
78 coherency_base = of_iomap(np, 0); 147 coherency_base = of_iomap(np, 0);
148 coherency_cpu_base = of_iomap(np, 1);
149 set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
150 bus_register_notifier(&platform_bus_type,
151 &mvebu_hwcc_platform_nb);
79 } 152 }
80 153
81 return 0; 154 return 0;
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 58bc3e4d3bd..5383bc01857 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -124,8 +124,6 @@ static void arm_dma_sync_single_for_device(struct device *dev,
124 __dma_page_cpu_to_dev(page, offset, size, dir); 124 __dma_page_cpu_to_dev(page, offset, size, dir);
125} 125}
126 126
127static int arm_dma_set_mask(struct device *dev, u64 dma_mask);
128
129struct dma_map_ops arm_dma_ops = { 127struct dma_map_ops arm_dma_ops = {
130 .alloc = arm_dma_alloc, 128 .alloc = arm_dma_alloc,
131 .free = arm_dma_free, 129 .free = arm_dma_free,
@@ -971,7 +969,7 @@ int dma_supported(struct device *dev, u64 mask)
971} 969}
972EXPORT_SYMBOL(dma_supported); 970EXPORT_SYMBOL(dma_supported);
973 971
974static int arm_dma_set_mask(struct device *dev, u64 dma_mask) 972int arm_dma_set_mask(struct device *dev, u64 dma_mask)
975{ 973{
976 if (!dev->dma_mask || !dma_supported(dev, dma_mask)) 974 if (!dev->dma_mask || !dma_supported(dev, dma_mask))
977 return -EIO; 975 return -EIO;
diff --git a/arch/arm/plat-orion/addr-map.c b/arch/arm/plat-orion/addr-map.c
index a7b8060c293..febe3862873 100644
--- a/arch/arm/plat-orion/addr-map.c
+++ b/arch/arm/plat-orion/addr-map.c
@@ -42,6 +42,8 @@ EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
42#define WIN_REMAP_LO_OFF 0x0008 42#define WIN_REMAP_LO_OFF 0x0008
43#define WIN_REMAP_HI_OFF 0x000c 43#define WIN_REMAP_HI_OFF 0x000c
44 44
45#define ATTR_HW_COHERENCY (0x1 << 4)
46
45/* 47/*
46 * Default implementation 48 * Default implementation
47 */ 49 */
@@ -163,6 +165,8 @@ void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg,
163 w = &orion_mbus_dram_info.cs[cs++]; 165 w = &orion_mbus_dram_info.cs[cs++];
164 w->cs_index = i; 166 w->cs_index = i;
165 w->mbus_attr = 0xf & ~(1 << i); 167 w->mbus_attr = 0xf & ~(1 << i);
168 if (cfg->hw_io_coherency)
169 w->mbus_attr |= ATTR_HW_COHERENCY;
166 w->base = base & 0xffff0000; 170 w->base = base & 0xffff0000;
167 w->size = (size | 0x0000ffff) + 1; 171 w->size = (size | 0x0000ffff) + 1;
168 } 172 }
diff --git a/arch/arm/plat-orion/include/plat/addr-map.h b/arch/arm/plat-orion/include/plat/addr-map.h
index ec63e4a627d..b76c06569fe 100644
--- a/arch/arm/plat-orion/include/plat/addr-map.h
+++ b/arch/arm/plat-orion/include/plat/addr-map.h
@@ -17,6 +17,7 @@ struct orion_addr_map_cfg {
17 const int num_wins; /* Total number of windows */ 17 const int num_wins; /* Total number of windows */
18 const int remappable_wins; 18 const int remappable_wins;
19 void __iomem *bridge_virt_base; 19 void __iomem *bridge_virt_base;
20 int hw_io_coherency;
20 21
21 /* If NULL, the default cpu_win_can_remap will be used, using 22 /* If NULL, the default cpu_win_can_remap will be used, using
22 the value in remappable_wins */ 23 the value in remappable_wins */