From: Lior Amsalem <al...@marvell.com>

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

Signed-off-by: Lior Amsalem <al...@marvell.com>
Reviewed-by: Ofer Heifetz <of...@marvell.com>
Reviewed-by: Nadav Haklai <nad...@marvell.com>
Tested-by: Nadav Haklai <nad...@marvell.com>
Signed-off-by: Maxime Ripard <maxime.rip...@free-electrons.com>
---
 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 <sa...@marvell.com>");
+MODULE_AUTHOR("Lior Amsalem <al...@marvell.com>, Saeed Bishara 
<sa...@marvell.com>");
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to