[PATCH 7/8] dmaengine: mv_xor: add support for a38x RAID6 support

From: Maxime Ripard
Date: Tue May 12 2015 - 11:40:34 EST


From: Lior Amsalem <alior@xxxxxxxxxxx>

The offload engine in A38x introduce RAID6 capability, this patch adds
RAID6 offload support for mv_xor driver.

Signed-off-by: Lior Amsalem <alior@xxxxxxxxxxx>
Reviewed-by: Ofer Heifetz <oferh@xxxxxxxxxxx>
Reviewed-by: Nadav Haklai <nadavh@xxxxxxxxxxx>
Tested-by: Nadav Haklai <nadavh@xxxxxxxxxxx>
Signed-off-by: Maxime Ripard <maxime.ripard@xxxxxxxxxxxxxxxxxx>
---
drivers/dma/mv_xor.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++----
drivers/dma/mv_xor.h | 5 ++-
2 files changed, 111 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 28980483eafb..9b5753dcbf76 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -36,6 +36,11 @@ enum mv_xor_mode {
XOR_MODE_IN_DESC,
};

+/* engine coefficients */
+static u8 mv_xor_raid6_coefs[8] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
+};
+
static void mv_xor_issue_pending(struct dma_chan *chan);

#define to_mv_xor_chan(chan) \
@@ -48,8 +53,7 @@ static void mv_xor_issue_pending(struct dma_chan *chan);
((chan)->dmadev.dev)

static void mv_desc_init(struct mv_xor_desc_slot *desc,
- dma_addr_t addr, u32 byte_count,
- enum dma_ctrl_flags flags)
+ u32 byte_count, enum dma_ctrl_flags flags)
{
struct mv_xor_desc *hw_desc = desc->hw_desc;

@@ -58,7 +62,6 @@ static void mv_desc_init(struct mv_xor_desc_slot *desc,
/* Enable end-of-descriptor interrupts only for DMA_PREP_INTERRUPT */
hw_desc->desc_command = (flags & DMA_PREP_INTERRUPT) ?
XOR_DESC_EOD_INT_EN : 0;
- hw_desc->phy_dest_addr = addr;
hw_desc->byte_count = byte_count;
}

@@ -74,6 +77,9 @@ static void mv_desc_set_mode(struct mv_xor_desc_slot *desc)
case DMA_MEMCPY:
hw_desc->desc_command |= XOR_DESC_OPERATION_MEMCPY;
break;
+ case DMA_PQ:
+ hw_desc->desc_command |= XOR_DESC_OPERATION_PQ;
+ break;
default:
BUG();
return;
@@ -84,16 +90,38 @@ static void mv_desc_set_next_desc(struct mv_xor_desc_slot *desc,
u32 next_desc_addr)
{
struct mv_xor_desc *hw_desc = desc->hw_desc;
+
BUG_ON(hw_desc->phy_next_desc);
hw_desc->phy_next_desc = next_desc_addr;
}

+static void mv_desc_set_dest_addr(struct mv_xor_desc_slot *desc,
+ dma_addr_t addr)
+{
+ struct mv_xor_desc *hw_desc = desc->hw_desc;
+
+ hw_desc->phy_dest_addr = addr;
+ if (desc->type == DMA_PQ)
+ hw_desc->desc_command |= (1 << 8);
+}
+
+static void mv_desc_set_q_dest_addr(struct mv_xor_desc_slot *desc,
+ dma_addr_t addr)
+{
+ struct mv_xor_desc *hw_desc = desc->hw_desc;
+
+ hw_desc->phy_q_dest_addr = addr;
+ if (desc->type == DMA_PQ)
+ hw_desc->desc_command |= (1 << 9);
+}
+
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[mv_phy_src_idx(index)] = addr;
- if (desc->type == DMA_XOR)
+ if ((desc->type == DMA_XOR) || (desc->type == DMA_PQ))
hw_desc->desc_command |= (1 << index);
}

@@ -520,7 +548,8 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
if (sw_desc) {
sw_desc->type = DMA_XOR;
sw_desc->async_tx.flags = flags;
- mv_desc_init(sw_desc, dest, len, flags);
+ mv_desc_init(sw_desc, len, flags);
+ mv_desc_set_dest_addr(sw_desc, dest);
if (mv_chan->op_in_desc == XOR_MODE_IN_DESC)
mv_desc_set_mode(sw_desc);
while (src_cnt--)
@@ -562,6 +591,69 @@ mv_xor_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags)
return mv_xor_prep_dma_xor(chan, dest, &src, 1, len, flags);
}

+static struct dma_async_tx_descriptor *
+mv_xor_prep_dma_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src,
+ unsigned int src_cnt, const unsigned char *scf,
+ size_t len, unsigned long flags)
+{
+ struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
+ struct mv_xor_desc_slot *sw_desc;
+ int src_i = 0;
+ int i = 0;
+
+ if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
+ return NULL;
+
+ BUG_ON(len > MV_XOR_MAX_BYTE_COUNT);
+
+ dev_dbg(mv_chan_to_devp(mv_chan),
+ "%s src_cnt: %d len: %u flags: %ld\n",
+ __func__, src_cnt, len, flags);
+
+ /*
+ * since the coefs on Marvell engine are hardcoded, do not
+ * support mult and sum product requests
+ */
+ if ((flags & DMA_PREP_PQ_MULT) || (flags & DMA_PREP_PQ_SUM_PRODUCT))
+ return NULL;
+
+ sw_desc = mv_chan_alloc_slot(mv_chan);
+ if (sw_desc) {
+ sw_desc->type = DMA_PQ;
+ sw_desc->async_tx.flags = flags;
+ mv_desc_init(sw_desc, len, flags);
+ if (mv_chan->op_in_desc == XOR_MODE_IN_DESC)
+ mv_desc_set_mode(sw_desc);
+ if (!(flags & DMA_PREP_PQ_DISABLE_P))
+ mv_desc_set_dest_addr(sw_desc, dst[0]);
+ if (!(flags & DMA_PREP_PQ_DISABLE_Q))
+ mv_desc_set_q_dest_addr(sw_desc, dst[1]);
+ while (src_cnt) {
+ /*
+ * probably we can do better coding below,
+ * hash table maybe?
+ */
+ if (scf[src_i] == mv_xor_raid6_coefs[i]) {
+ /*
+ * coefs are hardcoded, assign the src
+ * to the right place
+ */
+ mv_desc_set_src_addr(sw_desc, i, src[src_i]);
+ src_i++;
+ i++;
+ src_cnt--;
+ } else {
+ i++;
+ }
+ }
+ }
+
+ dev_dbg(mv_chan_to_devp(mv_chan),
+ "%s sw_desc %p async_tx %p\n",
+ __func__, sw_desc, &sw_desc->async_tx);
+ return sw_desc ? &sw_desc->async_tx : NULL;
+}
+
static void mv_xor_free_chan_resources(struct dma_chan *chan)
{
struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
@@ -1026,6 +1118,10 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
dma_dev->max_xor = 8;
dma_dev->device_prep_dma_xor = mv_xor_prep_dma_xor;
}
+ if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) {
+ dma_set_maxpq(dma_dev, 8, 0);
+ dma_dev->device_prep_dma_pq = mv_xor_prep_dma_pq;
+ }

mv_chan->mmr_base = xordev->xor_base;
mv_chan->mmr_high_base = xordev->xor_high_base;
@@ -1071,11 +1167,13 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
goto err_free_irq;
}

- dev_info(&pdev->dev, "Marvell XOR (%s): ( %s%s%s)\n",
+ dev_info(&pdev->dev, "Marvell XOR (%s): ( %s%s%s%s)\n",
mv_chan->op_in_desc ? "Descriptor Mode" : "Registers Mode",
dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "",
dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "",
- dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : "");
+ dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : "",
+ dma_has_cap(DMA_PQ, dma_dev->cap_mask) ? "pq " : "");
+

dma_async_device_register(dma_dev);
return mv_chan;
@@ -1199,6 +1297,8 @@ static int mv_xor_probe(struct platform_device *pdev)
dma_cap_set(DMA_XOR, cap_mask);
if (of_property_read_bool(np, "dmacap,interrupt"))
dma_cap_set(DMA_INTERRUPT, cap_mask);
+ if (of_property_read_bool(np, "dmacap,pq"))
+ dma_cap_set(DMA_PQ, cap_mask);

irq = irq_of_parse_and_map(np, 0);
if (!irq) {
@@ -1310,6 +1410,6 @@ static void __exit mv_xor_exit(void)
module_exit(mv_xor_exit);
#endif

-MODULE_AUTHOR("Saeed Bishara <saeed@xxxxxxxxxxx>");
+MODULE_AUTHOR("Lior Amsalem <alior@xxxxxxxxxxx>, Saeed Bishara <saeed@xxxxxxxxxxx>");
MODULE_DESCRIPTION("DMA engine driver for Marvell's XOR engine");
MODULE_LICENSE("GPL");
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index b7455b42137b..b72e7357c5c8 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -37,6 +37,7 @@
#define XOR_DESC_OPERATION_XOR (0 << 24)
#define XOR_DESC_OPERATION_CRC32C (1 << 24)
#define XOR_DESC_OPERATION_MEMCPY (2 << 24)
+#define XOR_DESC_OPERATION_PQ (5 << 24)

#define XOR_DESC_DMA_OWNED BIT(31)
#define XOR_DESC_EOD_INT_EN BIT(31)
@@ -164,7 +165,7 @@ struct mv_xor_desc {
u32 byte_count; /* size of src/dst blocks in bytes */
u32 phy_dest_addr; /* destination block address */
u32 phy_src_addr[8]; /* source block addresses */
- u32 reserved0;
+ u32 phy_q_dest_addr;
u32 reserved1;
};
#define mv_phy_src_idx(src_idx) (src_idx)
@@ -178,7 +179,7 @@ struct mv_xor_desc {
u32 byte_count; /* size of src/dst blocks in bytes */
u32 phy_src_addr[8]; /* source block addresses */
u32 reserved1;
- u32 reserved0;
+ u32 phy_q_dest_addr;
};
#define mv_phy_src_idx(src_idx) (src_idx ^ 1)
#endif
--
2.4.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/