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>
This commit is contained in:
Thomas Petazzoni 2013-07-29 17:42:14 +02:00 committed by Dan Williams
parent 5733c38ae3
commit e03bc654f8
2 changed files with 36 additions and 3 deletions

View File

@ -64,7 +64,7 @@ static u32 mv_desc_get_src_addr(struct mv_xor_desc_slot *desc,
int src_idx) int src_idx)
{ {
struct mv_xor_desc *hw_desc = desc->hw_desc; struct mv_xor_desc *hw_desc = desc->hw_desc;
return hw_desc->phy_src_addr[src_idx]; return hw_desc->phy_src_addr[mv_phy_src_idx(src_idx)];
} }
@ -107,7 +107,7 @@ static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc,
int index, dma_addr_t addr) int index, dma_addr_t addr)
{ {
struct mv_xor_desc *hw_desc = desc->hw_desc; struct mv_xor_desc *hw_desc = desc->hw_desc;
hw_desc->phy_src_addr[index] = addr; hw_desc->phy_src_addr[mv_phy_src_idx(index)] = addr;
if (desc->type == DMA_XOR) if (desc->type == DMA_XOR)
hw_desc->desc_command |= (1 << index); hw_desc->desc_command |= (1 << index);
} }
@ -192,6 +192,13 @@ static void mv_set_mode(struct mv_xor_chan *chan,
config &= ~0x7; config &= ~0x7;
config |= op_mode; config |= op_mode;
#if defined(__BIG_ENDIAN)
config |= XOR_DESCRIPTOR_SWAP;
#else
config &= ~XOR_DESCRIPTOR_SWAP;
#endif
writel_relaxed(config, XOR_CONFIG(chan)); writel_relaxed(config, XOR_CONFIG(chan));
chan->current_type = type; chan->current_type = type;
} }

View File

@ -29,8 +29,10 @@
#define MV_XOR_THRESHOLD 1 #define MV_XOR_THRESHOLD 1
#define MV_XOR_MAX_CHANNELS 2 #define MV_XOR_MAX_CHANNELS 2
/* Values for the XOR_CONFIG register */
#define XOR_OPERATION_MODE_XOR 0 #define XOR_OPERATION_MODE_XOR 0
#define XOR_OPERATION_MODE_MEMCPY 2 #define XOR_OPERATION_MODE_MEMCPY 2
#define XOR_DESCRIPTOR_SWAP BIT(14)
#define XOR_CURR_DESC(chan) (chan->mmr_base + 0x210 + (chan->idx * 4)) #define XOR_CURR_DESC(chan) (chan->mmr_base + 0x210 + (chan->idx * 4))
#define XOR_NEXT_DESC(chan) (chan->mmr_base + 0x200 + (chan->idx * 4)) #define XOR_NEXT_DESC(chan) (chan->mmr_base + 0x200 + (chan->idx * 4))
@ -143,7 +145,16 @@ struct mv_xor_desc_slot {
#endif #endif
}; };
/* This structure describes XOR descriptor size 64bytes */ /*
* This structure describes XOR descriptor size 64bytes. The
* mv_phy_src_idx() macro must be used when indexing the values of the
* phy_src_addr[] array. This is due to the fact that the 'descriptor
* swap' feature, used on big endian systems, swaps descriptors data
* within blocks of 8 bytes. So two consecutive values of the
* phy_src_addr[] array are actually swapped in big-endian, which
* explains the different mv_phy_src_idx() implementation.
*/
#if defined(__LITTLE_ENDIAN)
struct mv_xor_desc { struct mv_xor_desc {
u32 status; /* descriptor execution status */ u32 status; /* descriptor execution status */
u32 crc32_result; /* result of CRC-32 calculation */ u32 crc32_result; /* result of CRC-32 calculation */
@ -155,6 +166,21 @@ struct mv_xor_desc {
u32 reserved0; u32 reserved0;
u32 reserved1; u32 reserved1;
}; };
#define mv_phy_src_idx(src_idx) (src_idx)
#else
struct mv_xor_desc {
u32 crc32_result; /* result of CRC-32 calculation */
u32 status; /* descriptor execution status */
u32 phy_next_desc; /* next descriptor address pointer */
u32 desc_command; /* type of operation to be carried out */
u32 phy_dest_addr; /* destination block address */
u32 byte_count; /* size of src/dst blocks in bytes */
u32 phy_src_addr[8]; /* source block addresses */
u32 reserved1;
u32 reserved0;
};
#define mv_phy_src_idx(src_idx) (src_idx ^ 1)
#endif
#define to_mv_sw_desc(addr_hw_desc) \ #define to_mv_sw_desc(addr_hw_desc) \
container_of(addr_hw_desc, struct mv_xor_desc_slot, hw_desc) container_of(addr_hw_desc, struct mv_xor_desc_slot, hw_desc)