linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] dma: mv_xor: big endian support
@ 2013-07-29 15:05 Thomas Petazzoni
  2013-07-29 15:05 ` [PATCH 1/2] dma: mv_xor: use readl/writel instead of __raw_{readl, writel} Thomas Petazzoni
  2013-07-29 15:05 ` [PATCH 2/2] dma: mv_xor: support big endian systems using descriptor swap feature Thomas Petazzoni
  0 siblings, 2 replies; 5+ messages in thread
From: Thomas Petazzoni @ 2013-07-29 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

Vinod, Dan,

This small set of patches adds support for big endian operation in the
DMA mv_xor driver. It has been tested in both little-endian and
big-endian modes on the Armada XP GP board.

If possible, I'd like those to be merged for 3.12.

Thanks!

Thomas

Thomas Petazzoni (2):
  dma: mv_xor: use readl/writel instead of __raw_{readl,writel}
  dma: mv_xor: support big endian systems using descriptor swap feature

 drivers/dma/mv_xor.c | 47 +++++++++++++++++++++++++++--------------------
 drivers/dma/mv_xor.h | 28 +++++++++++++++++++++++++++-
 2 files changed, 54 insertions(+), 21 deletions(-)

-- 
1.8.1.2

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] dma: mv_xor: use readl/writel instead of __raw_{readl, writel}
  2013-07-29 15:05 [PATCH 0/2] dma: mv_xor: big endian support Thomas Petazzoni
@ 2013-07-29 15:05 ` Thomas Petazzoni
  2013-07-29 15:08   ` Russell King - ARM Linux
  2013-07-29 15:05 ` [PATCH 2/2] dma: mv_xor: support big endian systems using descriptor swap feature Thomas Petazzoni
  1 sibling, 1 reply; 5+ messages in thread
From: Thomas Petazzoni @ 2013-07-29 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

In order to support big-endian execution, the mv_xor driver is changed
to use thhe readl() and writel() accessors that properly convert from
the CPU endianess to the device endianess (which in the case of
Marvell XOR hardware is always little-endian).

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
 drivers/dma/mv_xor.c | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 200f1a3..e98966a 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -114,25 +114,25 @@ static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc,
 
 static u32 mv_chan_get_current_desc(struct mv_xor_chan *chan)
 {
-	return __raw_readl(XOR_CURR_DESC(chan));
+	return readl(XOR_CURR_DESC(chan));
 }
 
 static void mv_chan_set_next_descriptor(struct mv_xor_chan *chan,
 					u32 next_desc_addr)
 {
-	__raw_writel(next_desc_addr, XOR_NEXT_DESC(chan));
+	writel(next_desc_addr, XOR_NEXT_DESC(chan));
 }
 
 static void mv_chan_unmask_interrupts(struct mv_xor_chan *chan)
 {
-	u32 val = __raw_readl(XOR_INTR_MASK(chan));
+	u32 val = readl(XOR_INTR_MASK(chan));
 	val |= XOR_INTR_MASK_VALUE << (chan->idx * 16);
-	__raw_writel(val, XOR_INTR_MASK(chan));
+	writel(val, XOR_INTR_MASK(chan));
 }
 
 static u32 mv_chan_get_intr_cause(struct mv_xor_chan *chan)
 {
-	u32 intr_cause = __raw_readl(XOR_INTR_CAUSE(chan));
+	u32 intr_cause = readl(XOR_INTR_CAUSE(chan));
 	intr_cause = (intr_cause >> (chan->idx * 16)) & 0xFFFF;
 	return intr_cause;
 }
@@ -149,13 +149,13 @@ static void mv_xor_device_clear_eoc_cause(struct mv_xor_chan *chan)
 {
 	u32 val = ~(1 << (chan->idx * 16));
 	dev_dbg(mv_chan_to_devp(chan), "%s, val 0x%08x\n", __func__, val);
-	__raw_writel(val, XOR_INTR_CAUSE(chan));
+	writel(val, XOR_INTR_CAUSE(chan));
 }
 
 static void mv_xor_device_clear_err_status(struct mv_xor_chan *chan)
 {
 	u32 val = 0xFFFF0000 >> (chan->idx * 16);
-	__raw_writel(val, XOR_INTR_CAUSE(chan));
+	writel(val, XOR_INTR_CAUSE(chan));
 }
 
 static int mv_can_chain(struct mv_xor_desc_slot *desc)
@@ -173,7 +173,7 @@ static void mv_set_mode(struct mv_xor_chan *chan,
 			       enum dma_transaction_type type)
 {
 	u32 op_mode;
-	u32 config = __raw_readl(XOR_CONFIG(chan));
+	u32 config = readl(XOR_CONFIG(chan));
 
 	switch (type) {
 	case DMA_XOR:
@@ -192,7 +192,7 @@ static void mv_set_mode(struct mv_xor_chan *chan,
 
 	config &= ~0x7;
 	config |= op_mode;
-	__raw_writel(config, XOR_CONFIG(chan));
+	writel(config, XOR_CONFIG(chan));
 	chan->current_type = type;
 }
 
@@ -201,14 +201,14 @@ static void mv_chan_activate(struct mv_xor_chan *chan)
 	u32 activation;
 
 	dev_dbg(mv_chan_to_devp(chan), " activate chan.\n");
-	activation = __raw_readl(XOR_ACTIVATION(chan));
+	activation = readl(XOR_ACTIVATION(chan));
 	activation |= 0x1;
-	__raw_writel(activation, XOR_ACTIVATION(chan));
+	writel(activation, XOR_ACTIVATION(chan));
 }
 
 static char mv_chan_is_busy(struct mv_xor_chan *chan)
 {
-	u32 state = __raw_readl(XOR_ACTIVATION(chan));
+	u32 state = readl(XOR_ACTIVATION(chan));
 
 	state = (state >> 4) & 0x3;
 
@@ -755,22 +755,22 @@ static void mv_dump_xor_regs(struct mv_xor_chan *chan)
 {
 	u32 val;
 
-	val = __raw_readl(XOR_CONFIG(chan));
+	val = readl(XOR_CONFIG(chan));
 	dev_err(mv_chan_to_devp(chan), "config       0x%08x\n", val);
 
-	val = __raw_readl(XOR_ACTIVATION(chan));
+	val = readl(XOR_ACTIVATION(chan));
 	dev_err(mv_chan_to_devp(chan), "activation   0x%08x\n", val);
 
-	val = __raw_readl(XOR_INTR_CAUSE(chan));
+	val = readl(XOR_INTR_CAUSE(chan));
 	dev_err(mv_chan_to_devp(chan), "intr cause   0x%08x\n", val);
 
-	val = __raw_readl(XOR_INTR_MASK(chan));
+	val = readl(XOR_INTR_MASK(chan));
 	dev_err(mv_chan_to_devp(chan), "intr mask    0x%08x\n", val);
 
-	val = __raw_readl(XOR_ERROR_CAUSE(chan));
+	val = readl(XOR_ERROR_CAUSE(chan));
 	dev_err(mv_chan_to_devp(chan), "error cause  0x%08x\n", val);
 
-	val = __raw_readl(XOR_ERROR_ADDR(chan));
+	val = readl(XOR_ERROR_ADDR(chan));
 	dev_err(mv_chan_to_devp(chan), "error addr   0x%08x\n", val);
 }
 
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] dma: mv_xor: support big endian systems using descriptor swap feature
  2013-07-29 15:05 [PATCH 0/2] dma: mv_xor: big endian support Thomas Petazzoni
  2013-07-29 15:05 ` [PATCH 1/2] dma: mv_xor: use readl/writel instead of __raw_{readl, writel} Thomas Petazzoni
@ 2013-07-29 15:05 ` Thomas Petazzoni
  1 sibling, 0 replies; 5+ messages in thread
From: Thomas Petazzoni @ 2013-07-29 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

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>
---
 drivers/dma/mv_xor.c | 11 +++++++++--
 drivers/dma/mv_xor.h | 28 +++++++++++++++++++++++++++-
 2 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index e98966a..fc4d0e9 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,
 				int src_idx)
 {
 	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)
 {
 	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)
 		hw_desc->desc_command |= (1 << index);
 }
@@ -192,6 +192,13 @@ static void mv_set_mode(struct mv_xor_chan *chan,
 
 	config &= ~0x7;
 	config |= op_mode;
+
+#if defined(__BIG_ENDIAN)
+	config |= XOR_DESCRIPTOR_SWAP;
+#else
+	config &= ~XOR_DESCRIPTOR_SWAP;
+#endif
+
 	writel(config, XOR_CONFIG(chan));
 	chan->current_type = type;
 }
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index c619359..06b067f 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -29,8 +29,10 @@
 #define MV_XOR_THRESHOLD		1
 #define MV_XOR_MAX_CHANNELS             2
 
+/* Values for the XOR_CONFIG register */
 #define XOR_OPERATION_MODE_XOR		0
 #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_NEXT_DESC(chan)	(chan->mmr_base + 0x200 + (chan->idx * 4))
@@ -143,7 +145,16 @@ struct mv_xor_desc_slot {
 #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 {
 	u32 status;		/* descriptor execution status */
 	u32 crc32_result;	/* result of CRC-32 calculation */
@@ -155,6 +166,21 @@ struct mv_xor_desc {
 	u32 reserved0;
 	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)		\
 	container_of(addr_hw_desc, struct mv_xor_desc_slot, hw_desc)
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 1/2] dma: mv_xor: use readl/writel instead of __raw_{readl, writel}
  2013-07-29 15:05 ` [PATCH 1/2] dma: mv_xor: use readl/writel instead of __raw_{readl, writel} Thomas Petazzoni
@ 2013-07-29 15:08   ` Russell King - ARM Linux
  2013-07-29 15:14     ` Thomas Petazzoni
  0 siblings, 1 reply; 5+ messages in thread
From: Russell King - ARM Linux @ 2013-07-29 15:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 29, 2013 at 05:05:09PM +0200, Thomas Petazzoni wrote:
> In order to support big-endian execution, the mv_xor driver is changed
> to use thhe readl() and writel() accessors that properly convert from
> the CPU endianess to the device endianess (which in the case of
> Marvell XOR hardware is always little-endian).

Is it necessary that all these be barrier-ied IO operations?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] dma: mv_xor: use readl/writel instead of __raw_{readl, writel}
  2013-07-29 15:08   ` Russell King - ARM Linux
@ 2013-07-29 15:14     ` Thomas Petazzoni
  0 siblings, 0 replies; 5+ messages in thread
From: Thomas Petazzoni @ 2013-07-29 15:14 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Russell King - ARM Linux,

On Mon, 29 Jul 2013 16:08:27 +0100, Russell King - ARM Linux wrote:
> On Mon, Jul 29, 2013 at 05:05:09PM +0200, Thomas Petazzoni wrote:
> > In order to support big-endian execution, the mv_xor driver is changed
> > to use thhe readl() and writel() accessors that properly convert from
> > the CPU endianess to the device endianess (which in the case of
> > Marvell XOR hardware is always little-endian).
> 
> Is it necessary that all these be barrier-ied IO operations?

As they used to be __raw_..., I presume that those barrier-ied
operations are not strictly needed, so I could use the relaxed
variants instead.

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-07-29 15:14 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-29 15:05 [PATCH 0/2] dma: mv_xor: big endian support Thomas Petazzoni
2013-07-29 15:05 ` [PATCH 1/2] dma: mv_xor: use readl/writel instead of __raw_{readl, writel} Thomas Petazzoni
2013-07-29 15:08   ` Russell King - ARM Linux
2013-07-29 15:14     ` Thomas Petazzoni
2013-07-29 15:05 ` [PATCH 2/2] dma: mv_xor: support big endian systems using descriptor swap feature Thomas Petazzoni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).