Re: [PATCH] ppc440spe-adma: adds updated ppc440spe adma driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Anatolij Gustschin wrote:
This patch adds new version of the PPC440SPe ADMA driver.

Signed-off-by: Anatolij Gustschin <agust@xxxxxxx>

As Josh said please don't drop attribution tags. If you borrowed from Yuri's implementation you can forward his signed-off-by.

---
Before applying this patch the following patch to katmai.dts
should be applied first: http://patchwork.ozlabs.org/patch/36768/

The driver was updated to work with extended async_tx API.
Comments to previous PPC440SPe ADMA driver versions submitted to
the linuxppc-dev list were addressed. Please review and consider
for inclusion. Thanks.

 .../powerpc/dts-bindings/4xx/ppc440spe-adma.txt    |   93 +
 arch/powerpc/boot/dts/katmai.dts                   |   52 +-
 arch/powerpc/include/asm/async_tx.h                |   47 +
 arch/powerpc/include/asm/dcr-regs.h                |   26 +
 arch/powerpc/include/asm/ppc440spe_adma.h          |  195 +
 arch/powerpc/include/asm/ppc440spe_dma.h           |  224 +
 arch/powerpc/include/asm/ppc440spe_xor.h           |  110 +
 drivers/dma/Kconfig                                |   13 +
 drivers/dma/Makefile                               |    1 +
 drivers/dma/ppc440spe-adma.c                       | 4944 ++++++++++++++++++++
 10 files changed, 5704 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/powerpc/dts-bindings/4xx/ppc440spe-adma.txt
 create mode 100644 arch/powerpc/include/asm/async_tx.h
 create mode 100644 arch/powerpc/include/asm/ppc440spe_adma.h
 create mode 100644 arch/powerpc/include/asm/ppc440spe_dma.h
 create mode 100644 arch/powerpc/include/asm/ppc440spe_xor.h
 create mode 100644 drivers/dma/ppc440spe-adma.c
[..]
diff --git a/arch/powerpc/include/asm/ppc440spe_dma.h b/arch/powerpc/include/asm/ppc440spe_dma.h
new file mode 100644
index 0000000..7cce63e
--- /dev/null
+++ b/arch/powerpc/include/asm/ppc440spe_dma.h
[..]
+/*
+ * DMAx hardware registers (p.515 in 440SPe UM 1.22)
+ */
+typedef struct {
+       u32     cpfpl;
+       u32     cpfph;
+       u32     csfpl;
+       u32     csfph;
+       u32     dsts;
+       u32     cfg;
+       u8      pad0[0x8];
+       u16     cpfhp;
+       u16     cpftp;
+       u16     csfhp;
+       u16     csftp;
+       u8      pad1[0x8];
+       u32     acpl;
+       u32     acph;
+       u32     s1bpl;
+       u32     s1bph;
+       u32     s2bpl;
+       u32     s2bph;
+       u32     s3bpl;
+       u32     s3bph;
+       u8      pad2[0x10];
+       u32     earl;
+       u32     earh;
+       u8      pad3[0x8];
+       u32     seat;
+       u32     sead;
+       u32     op;
+       u32     fsiz;
+} dma_regs_t;
+
+/*
+ * I2O hardware registers (p.528 in 440SPe UM 1.22)
+ */
+typedef struct {
+       u32     ists;
+       u32     iseat;
+       u32     isead;
+       u8      pad0[0x14];
+       u32     idbel;
+       u8      pad1[0xc];
+       u32     ihis;
+       u32     ihim;
+       u8      pad2[0x8];
+       u32     ihiq;
+       u32     ihoq;
+       u8      pad3[0x8];
+       u32     iopis;
+       u32     iopim;
+       u32     iopiq;
+       u8      iopoq;
+       u8      pad4[3];
+       u16     iiflh;
+       u16     iiflt;
+       u16     iiplh;
+       u16     iiplt;
+       u16     ioflh;
+       u16     ioflt;
+       u16     ioplh;
+       u16     ioplt;
+       u32     iidc;
+       u32     ictl;
+       u32     ifcpp;
+       u8      pad5[0x4];
+       u16     mfac0;
+       u16     mfac1;
+       u16     mfac2;
+       u16     mfac3;
+       u16     mfac4;
+       u16     mfac5;
+       u16     mfac6;
+       u16     mfac7;
+       u16     ifcfh;
+       u16     ifcht;
+       u8      pad6[0x4];
+       u32     iifmc;
+       u32     iodb;
+       u32     iodbc;
+       u32     ifbal;
+       u32     ifbah;
+       u32     ifsiz;
+       u32     ispd0;
+       u32     ispd1;
+       u32     ispd2;
+       u32     ispd3;
+       u32     ihipl;
+       u32     ihiph;
+       u32     ihopl;
+       u32     ihoph;
+       u32     iiipl;
+       u32     iiiph;
+       u32     iiopl;
+       u32     iioph;
+       u32     ifcpl;
+       u32     ifcph;
+       u8      pad7[0x8];
+       u32     iopt;
+} i2o_regs_t;

I saw the use of "volatile" in the driver code which lead me back here. I think it is a reasonable expectation that all drivers use the accessors in asm/io.h to read/write mmio registers rather than volatile structure pointers. PPC folks feel free to correct me if this is common practice for PPC drivers.

A side note, checkpatch rightly says "do not add new typedefs".

[..]
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 5903a88..854d594 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -109,6 +109,19 @@ config SH_DMAE
        help
          Enable support for the Renesas SuperH DMA controllers.

+config AMCC_PPC440SPE_ADMA
+       tristate "AMCC PPC440SPe ADMA support"
+       depends on 440SPe || 440SP
+       select DMA_ENGINE
+       select ASYNC_TX_DMA

The user should have the option to turn off dma support on a per dma client basis, so please remove "select ASYNC_TX_DMA".

+       select ARCH_HAS_ASYNC_TX_FIND_CHANNEL
+       default y

New options should never default to y (except for backwards compatibility). This is better left to a defconfig.

+       help
+         Enable support for the AMCC PPC440SPe RAID engines.
+
+config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
+       bool
+
 config DMA_ENGINE
        bool

[..]
diff --git a/drivers/dma/ppc440spe-adma.c b/drivers/dma/ppc440spe-adma.c
new file mode 100644
index 0000000..40e5479
--- /dev/null
+++ b/drivers/dma/ppc440spe-adma.c
[..]
+#ifdef ADMA_LL_DEBUG
+static void print_cb(struct ppc440spe_adma_chan *chan, void *block)
+{
+       struct dma_cdb *cdb;
+       xor_cb_t *cb;
+       int i;
+
+       switch (chan->device->id) {
+       case 0:
+       case 1:
+               cdb = block;
+
+               printk("CDB at %p [%d]:\n"
+                       "\t attr 0x%02x opc 0x%02x cnt 0x%08x\n"
+                       "\t sg1u 0x%08x sg1l 0x%08x\n"
+                       "\t sg2u 0x%08x sg2l 0x%08x\n"
+                       "\t sg3u 0x%08x sg3l 0x%08x\n",
+                       cdb, chan->device->id,
+                       cdb->attr, cdb->opc, le32_to_cpu(cdb->cnt),
+                       le32_to_cpu(cdb->sg1u), le32_to_cpu(cdb->sg1l),
+                       le32_to_cpu(cdb->sg2u), le32_to_cpu(cdb->sg2l),
+                       le32_to_cpu(cdb->sg3u), le32_to_cpu(cdb->sg3l)

Debug ifdefs lead to code that does not get compile coverage and bitrots until someone later tries to debug. Converting these printk() calls to pr_debug() gets rid of most, but not all of print_cb(). Perhaps look into the coh-dma driver's approach of wrapping calls to debug functions with something like:

#ifdef VERBOSE_DEBUG
#define COH_DBG(x) ({ if (1) x; 0; })
#else
#define COH_DBG(x) ({ if (0) x; 0; })
#endif

Converting to pr_debug or dev_dbg will also make checkpatch happy: "printk() should include KERN_ facility level".

+               );
+               break;
+       case 2:
+               cb = block;
+
+               printk("CB at %p [%d]:\n"
+                       "\t cbc 0x%08x cbbc 0x%08x cbs 0x%08x\n"
+                       "\t cbtah 0x%08x cbtal 0x%08x\n"
+                       "\t cblah 0x%08x cblal 0x%08x\n",
+                       cb, chan->device->id,
+                       cb->cbc, cb->cbbc, cb->cbs,
+                       cb->cbtah, cb->cbtal,
+                       cb->cblah, cb->cblal);
+               for (i = 0; i < 16; i++) {
+                       if (i && !cb->ops[i].h && !cb->ops[i].l)
+                               continue;
+                       printk("\t ops[%2d]: h 0x%08x l 0x%08x\n",
+                               i, cb->ops[i].h, cb->ops[i].l);
+               }
+               break;
+       }
+}
+#endif
+
[..]
+/******************************************************************************
+ * ADMA channel low-level routines
+ ******************************************************************************/
+
+static inline u32
+ppc440spe_chan_get_current_descriptor(struct ppc440spe_adma_chan *chan);
+static inline void ppc440spe_chan_append(struct ppc440spe_adma_chan *chan);

sparse says:
drivers/dma/ppc440spe-adma.c:1078:41: error: marked inline, but without a definition drivers/dma/ppc440spe-adma.c:1077:38: error: marked inline, but without a definition

[..]
+/**
+ * ppc440spe_adma_prep_dma_pqzero_sum - prepare CDB group for
+ * a PQ_ZERO_SUM operation
+ */
+static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_pqzero_sum(
+               struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src,
+               unsigned int src_cnt, const unsigned char *scf, size_t len,
+               enum sum_check_flags *pqres, unsigned long flags)
+{
+       struct ppc440spe_adma_chan *ppc440spe_chan;
+       struct ppc440spe_adma_desc_slot *sw_desc, *iter;
+       dma_addr_t pdest, qdest;
+       int slot_cnt, slots_per_op, idst, dst_cnt;
+
+       ppc440spe_chan = to_ppc440spe_adma_chan(chan);
+
+       if (flags & DMA_PREP_PQ_DISABLE_P)
+               pdest = 0;
+       else
+               pdest = pq[0];
+
+       if (flags & DMA_PREP_PQ_DISABLE_Q)
+               qdest = 0;
+       else
+               qdest = pq[1];
+
+#ifdef ADMA_LL_DEBUG
+       printk("\n%s(%d):\n\tsrc(coef): ", __func__,
+               ppc440spe_chan->device->id);
+       for (idst = 0; idst < src_cnt; idst++)
+               printk("0x%08x(0x%02x) ", src[idst], scf[idst]);
+
+       printk("\n\tdst: ");
+       for (idst = 0; idst < 2; idst++)
+               printk("0x%08x ", src[src_cnt+idst]);
+       printk("\n");
+       printk("\n%s: src_cnt %d\n", __func__, src_cnt);
+#endif
+
+       /* Always use WXOR for P/Q calculations (two destinations).
+        * Need 1 or 2 extra slots to verify results are zero.
+        */
+       idst = dst_cnt = (pdest && qdest) ? 2 : 1;
+
+       /* One additional slot per destination to clone P/Q
+        * before calculation (we have to preserve destinations).
+        */
+       slot_cnt = src_cnt + dst_cnt * 2;
+       slots_per_op = 1;
+
+       spin_lock_bh(&ppc440spe_chan->lock);
+       sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt,
+                                            slots_per_op);
+       if (sw_desc) {
+               ppc440spe_desc_init_dma01pqzero_sum(sw_desc, dst_cnt, src_cnt);

It looks like you emulate pqzero_sum operations with PAGE_SIZE temporary buffer. Be sure to check 'len' because users of the api are allowed to submit > PAGE_SIZE requests.

[..]
+static void ppc440spe_adma_init_capabilities(struct ppc440spe_adma_device *adev)
[..]
+       if (dma_has_cap(DMA_PQ, adev->common.cap_mask)) {
+               switch (adev->id) {
+               case PPC440SPE_DMA0_ID:
+                       adev->common.max_pq = DMA0_FIFO_SIZE /
+                                               sizeof(dma_cdb_t);
+                       break;
+               case PPC440SPE_DMA1_ID:
+                       adev->common.max_pq = DMA1_FIFO_SIZE /
+                                               sizeof(dma_cdb_t);
+                       break;
+               case PPC440SPE_XOR_ID:
+                       adev->common.max_pq = XOR_MAX_OPS * 3;
+                       break;
+               }
+               adev->common.device_prep_dma_pq =
+                       ppc440spe_adma_prep_dma_pq;
+       }
+       if (dma_has_cap(DMA_PQ_VAL, adev->common.cap_mask)) {
+               switch (adev->id) {
+               case PPC440SPE_DMA0_ID:
+                       adev->common.max_pq = DMA0_FIFO_SIZE /
+                                               sizeof(dma_cdb_t);
+                       break;
+               case PPC440SPE_DMA1_ID:
+                       adev->common.max_pq = DMA1_FIFO_SIZE /
+                                               sizeof(dma_cdb_t);
+                       break;
+               }
+               adev->common.device_prep_dma_pq_val =
+                       ppc440spe_adma_prep_dma_pqzero_sum;
+       }

Please use dma_set_maxpq() when setting 'max_pq' above to make it clear whether this driver supports hardware continuation of pq operations. Otherwise the async_tx api will chop the number of sources it passes for operations larger than the hardware maximum.

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

[Index of Archives]     [Linux RAID Wiki]     [ATA RAID]     [Linux SCSI Target Infrastructure]     [Linux Block]     [Linux IDE]     [Linux SCSI]     [Linux Hams]     [Device Mapper]     [Device Mapper Cryptographics]     [Kernel]     [Linux Admin]     [Linux Net]     [GFS]     [RPM]     [git]     [Yosemite Forum]


  Powered by Linux