aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorThomas Petazzoni <thomas.petazzoni@free-electrons.com>2013-07-29 11:42:14 -0400
committerDan Williams <djbw@fb.com>2013-08-23 01:57:37 -0400
commite03bc654f85604bcd5304debb597f398d1d03778 (patch)
tree380052c9f15b3b01034dac678acc1b3fcf21bf37 /drivers
parent5733c38ae3473115ac7df3fe19bd2502149d8c51 (diff)
mv_xor: support big endian systems using descriptor swap feature
The mv_xor driver had never been used in a big-endian context, and therefore was not using the hardware features to support such an execution environment. The hardware provides a "descriptor swap" bit that automatically swaps the bytes of the DMA descriptors, within blocks of 8 bytes. This requires a different DMA descriptor layout on big-endian systems, as well as enabling this "descriptor swap" bit. This mechanism is exactly identical to the one already used in the mv643xx_eth network driver and the mvneta network driver. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Signed-off-by: Dan Williams <djbw@fb.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma/mv_xor.c11
-rw-r--r--drivers/dma/mv_xor.h28
2 files changed, 36 insertions, 3 deletions
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index c026b27f76e1..d332b9e3f9ce 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -64,7 +64,7 @@ static u32 mv_desc_get_src_addr(struct mv_xor_desc_slot *desc,
64 int src_idx) 64 int src_idx)
65{ 65{
66 struct mv_xor_desc *hw_desc = desc->hw_desc; 66 struct mv_xor_desc *hw_desc = desc->hw_desc;
67 return hw_desc->phy_src_addr[src_idx]; 67 return hw_desc->phy_src_addr[mv_phy_src_idx(src_idx)];
68} 68}
69 69
70 70
@@ -107,7 +107,7 @@ static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc,
107 int index, dma_addr_t addr) 107 int index, dma_addr_t addr)
108{ 108{
109 struct mv_xor_desc *hw_desc = desc->hw_desc; 109 struct mv_xor_desc *hw_desc = desc->hw_desc;
110 hw_desc->phy_src_addr[index] = addr; 110 hw_desc->phy_src_addr[mv_phy_src_idx(index)] = addr;
111 if (desc->type == DMA_XOR) 111 if (desc->type == DMA_XOR)
112 hw_desc->desc_command |= (1 << index); 112 hw_desc->desc_command |= (1 << index);
113} 113}
@@ -192,6 +192,13 @@ static void mv_set_mode(struct mv_xor_chan *chan,
192 192
193 config &= ~0x7; 193 config &= ~0x7;
194 config |= op_mode; 194 config |= op_mode;
195
196#if defined(__BIG_ENDIAN)
197 config |= XOR_DESCRIPTOR_SWAP;
198#else
199 config &= ~XOR_DESCRIPTOR_SWAP;
200#endif
201
195 writel_relaxed(config, XOR_CONFIG(chan)); 202 writel_relaxed(config, XOR_CONFIG(chan));
196 chan->current_type = type; 203 chan->current_type = type;
197} 204}
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index c619359cb7fe..06b067f24c9b 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -29,8 +29,10 @@
29#define MV_XOR_THRESHOLD 1 29#define MV_XOR_THRESHOLD 1
30#define MV_XOR_MAX_CHANNELS 2 30#define MV_XOR_MAX_CHANNELS 2
31 31
32/* Values for the XOR_CONFIG register */
32#define XOR_OPERATION_MODE_XOR 0 33#define XOR_OPERATION_MODE_XOR 0
33#define XOR_OPERATION_MODE_MEMCPY 2 34#define XOR_OPERATION_MODE_MEMCPY 2
35#define XOR_DESCRIPTOR_SWAP BIT(14)
34 36
35#define XOR_CURR_DESC(chan) (chan->mmr_base + 0x210 + (chan->idx * 4)) 37#define XOR_CURR_DESC(chan) (chan->mmr_base + 0x210 + (chan->idx * 4))
36#define XOR_NEXT_DESC(chan) (chan->mmr_base + 0x200 + (chan->idx * 4)) 38#define XOR_NEXT_DESC(chan) (chan->mmr_base + 0x200 + (chan->idx * 4))
@@ -143,7 +145,16 @@ struct mv_xor_desc_slot {
143#endif 145#endif
144}; 146};
145 147
146/* This structure describes XOR descriptor size 64bytes */ 148/*
149 * This structure describes XOR descriptor size 64bytes. The
150 * mv_phy_src_idx() macro must be used when indexing the values of the
151 * phy_src_addr[] array. This is due to the fact that the 'descriptor
152 * swap' feature, used on big endian systems, swaps descriptors data
153 * within blocks of 8 bytes. So two consecutive values of the
154 * phy_src_addr[] array are actually swapped in big-endian, which
155 * explains the different mv_phy_src_idx() implementation.
156 */
157#if defined(__LITTLE_ENDIAN)
147struct mv_xor_desc { 158struct mv_xor_desc {
148 u32 status; /* descriptor execution status */ 159 u32 status; /* descriptor execution status */
149 u32 crc32_result; /* result of CRC-32 calculation */ 160 u32 crc32_result; /* result of CRC-32 calculation */
@@ -155,6 +166,21 @@ struct mv_xor_desc {
155 u32 reserved0; 166 u32 reserved0;
156 u32 reserved1; 167 u32 reserved1;
157}; 168};
169#define mv_phy_src_idx(src_idx) (src_idx)
170#else
171struct mv_xor_desc {
172 u32 crc32_result; /* result of CRC-32 calculation */
173 u32 status; /* descriptor execution status */
174 u32 phy_next_desc; /* next descriptor address pointer */
175 u32 desc_command; /* type of operation to be carried out */
176 u32 phy_dest_addr; /* destination block address */
177 u32 byte_count; /* size of src/dst blocks in bytes */
178 u32 phy_src_addr[8]; /* source block addresses */
179 u32 reserved1;
180 u32 reserved0;
181};
182#define mv_phy_src_idx(src_idx) (src_idx ^ 1)
183#endif
158 184
159#define to_mv_sw_desc(addr_hw_desc) \ 185#define to_mv_sw_desc(addr_hw_desc) \
160 container_of(addr_hw_desc, struct mv_xor_desc_slot, hw_desc) 186 container_of(addr_hw_desc, struct mv_xor_desc_slot, hw_desc)