* Re: [PATCH 1/2] powerpc: export ppc_tb_freq so that modules can reference it
From: Tabi Timur-B04825 @ 2010-09-18 14:36 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, kumar.gala, linux-watchdog
In-Reply-To: <1284779678.30449.108.camel@pasglop>
On Sep 17, 2010, at 10:14 PM, "Benjamin Herrenschmidt" =
<benh@kernel.crashing.org> wrote:
> On Fri, 2010-09-17 at 20:20 -0500, Timur Tabi wrote:
>> I don't see any reason to limit it to GPL drivers. Not only that, =
but
>> then we'll have this:
>=20
> I do
Can you elaborate on that, or are you just going to pull rank on me?
>=20
>> EXPORT_SYMBOL(ppc_proc_freq);
>> EXPORT_SYMBOL_GPL(ppc_tb_freq);
>>=20
>> That just looks dumb.=20
>=20
> Right, so send a patch to fix the first one too :-)
Then why doesn't someone post a patch to change all EXPORT_SYMBOL to =
EXPORT_SYMBOL_GPL? And why do we consider EXPORT_SYMBOL to be "broken"?
I'm not trying to be a troll, but I see a lot of inconsistency with =
respect to EXPORT_SYMBOL and EXPORT_SYMBOL_GPL. =20
>=20
^ permalink raw reply
* Re: [PATCH 1/2] powerpc: export ppc_tb_freq so that modules can reference it
From: Benjamin Herrenschmidt @ 2010-09-18 3:14 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, kumar.gala, linux-watchdog
In-Reply-To: <AANLkTinidrifo3ry7o=DPKF96f3o4+_2zt7rsn=Zvh9D@mail.gmail.com>
On Fri, 2010-09-17 at 20:20 -0500, Timur Tabi wrote:
> I don't see any reason to limit it to GPL drivers. Not only that, but
> then we'll have this:
I do
> EXPORT_SYMBOL(ppc_proc_freq);
> EXPORT_SYMBOL_GPL(ppc_tb_freq);
>
> That just looks dumb.
Right, so send a patch to fix the first one too :-)
Cheers,
Ben.
^ permalink raw reply
* [PATCH 1/2] PPC4xx: Generelizing drivers/dma/ppc4xx/adma.c
From: tmarri @ 2010-09-18 1:42 UTC (permalink / raw)
To: linux-raid
Cc: neilb, yur, herbert, linux-crypto, tmarri, dan.j.williams,
linuxppc-dev
From: Tirumala Marri <tmarri@apm.com>
This patch generalizes the existing drver/dma/ppc4xx/adma.c, so that
common code can be shared between different similar DMA engine
drivers in other SoCs.
Signed-off-by: Tirumala R Marri <tmarri@apm.com>
---
drivers/dma/ppc4xx/adma.c | 4370 +++-----------------------------------
drivers/dma/ppc4xx/adma.h | 116 +-
drivers/dma/ppc4xx/ppc4xx-adma.h | 4020 +++++++++++++++++++++++++++++++++++
3 files changed, 4357 insertions(+), 4149 deletions(-)
create mode 100644 drivers/dma/ppc4xx/ppc4xx-adma.h
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 0d58a4a..99fbfd6 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -26,7 +26,7 @@
/*
* This driver supports the asynchrounous DMA copy and RAID engines available
- * on the AMCC PPC440SPe Processors.
+ * on the AMCC PPC4XX Processors.
* Based on the Intel Xscale(R) family of I/O Processors (IOP 32x, 33x, 134x)
* ADMA driver written by D.Williams.
*/
@@ -46,149 +46,7 @@
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
#include "adma.h"
-
-enum ppc_adma_init_code {
- PPC_ADMA_INIT_OK = 0,
- PPC_ADMA_INIT_MEMRES,
- PPC_ADMA_INIT_MEMREG,
- PPC_ADMA_INIT_ALLOC,
- PPC_ADMA_INIT_COHERENT,
- PPC_ADMA_INIT_CHANNEL,
- PPC_ADMA_INIT_IRQ1,
- PPC_ADMA_INIT_IRQ2,
- PPC_ADMA_INIT_REGISTER
-};
-
-static char *ppc_adma_errors[] = {
- [PPC_ADMA_INIT_OK] = "ok",
- [PPC_ADMA_INIT_MEMRES] = "failed to get memory resource",
- [PPC_ADMA_INIT_MEMREG] = "failed to request memory region",
- [PPC_ADMA_INIT_ALLOC] = "failed to allocate memory for adev "
- "structure",
- [PPC_ADMA_INIT_COHERENT] = "failed to allocate coherent memory for "
- "hardware descriptors",
- [PPC_ADMA_INIT_CHANNEL] = "failed to allocate memory for channel",
- [PPC_ADMA_INIT_IRQ1] = "failed to request first irq",
- [PPC_ADMA_INIT_IRQ2] = "failed to request second irq",
- [PPC_ADMA_INIT_REGISTER] = "failed to register dma async device",
-};
-
-static enum ppc_adma_init_code
-ppc440spe_adma_devices[PPC440SPE_ADMA_ENGINES_NUM];
-
-struct ppc_dma_chan_ref {
- struct dma_chan *chan;
- struct list_head node;
-};
-
-/* The list of channels exported by ppc440spe ADMA */
-struct list_head
-ppc440spe_adma_chan_list = LIST_HEAD_INIT(ppc440spe_adma_chan_list);
-
-/* This flag is set when want to refetch the xor chain in the interrupt
- * handler
- */
-static u32 do_xor_refetch;
-
-/* Pointer to DMA0, DMA1 CP/CS FIFO */
-static void *ppc440spe_dma_fifo_buf;
-
-/* Pointers to last submitted to DMA0, DMA1 CDBs */
-static struct ppc440spe_adma_desc_slot *chan_last_sub[3];
-static struct ppc440spe_adma_desc_slot *chan_first_cdb[3];
-
-/* Pointer to last linked and submitted xor CB */
-static struct ppc440spe_adma_desc_slot *xor_last_linked;
-static struct ppc440spe_adma_desc_slot *xor_last_submit;
-
-/* This array is used in data-check operations for storing a pattern */
-static char ppc440spe_qword[16];
-
-static atomic_t ppc440spe_adma_err_irq_ref;
-static dcr_host_t ppc440spe_mq_dcr_host;
-static unsigned int ppc440spe_mq_dcr_len;
-
-/* Since RXOR operations use the common register (MQ0_CF2H) for setting-up
- * the block size in transactions, then we do not allow to activate more than
- * only one RXOR transactions simultaneously. So use this var to store
- * the information about is RXOR currently active (PPC440SPE_RXOR_RUN bit is
- * set) or not (PPC440SPE_RXOR_RUN is clear).
- */
-static unsigned long ppc440spe_rxor_state;
-
-/* These are used in enable & check routines
- */
-static u32 ppc440spe_r6_enabled;
-static struct ppc440spe_adma_chan *ppc440spe_r6_tchan;
-static struct completion ppc440spe_r6_test_comp;
-
-static int ppc440spe_adma_dma2rxor_prep_src(
- struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_rxor *cursor, int index,
- int src_cnt, u32 addr);
-static void ppc440spe_adma_dma2rxor_set_src(
- struct ppc440spe_adma_desc_slot *desc,
- int index, dma_addr_t addr);
-static void ppc440spe_adma_dma2rxor_set_mult(
- struct ppc440spe_adma_desc_slot *desc,
- int index, u8 mult);
-
-#ifdef ADMA_LL_DEBUG
-#define ADMA_LL_DBG(x) ({ if (1) x; 0; })
-#else
-#define ADMA_LL_DBG(x) ({ if (0) x; 0; })
-#endif
-
-static void print_cb(struct ppc440spe_adma_chan *chan, void *block)
-{
- struct dma_cdb *cdb;
- struct xor_cb *cb;
- int i;
-
- switch (chan->device->id) {
- case 0:
- case 1:
- cdb = block;
-
- pr_debug("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)
- );
- break;
- case 2:
- cb = block;
-
- pr_debug("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;
- pr_debug("\t ops[%2d]: h 0x%08x l 0x%08x\n",
- i, cb->ops[i].h, cb->ops[i].l);
- }
- break;
- }
-}
-
-static void print_cb_list(struct ppc440spe_adma_chan *chan,
- struct ppc440spe_adma_desc_slot *iter)
-{
- for (; iter; iter = iter->hw_next)
- print_cb(chan, iter->hw_desc);
-}
+#include "ppc4xx-adma.h"
static void prep_dma_xor_dbg(int id, dma_addr_t dst, dma_addr_t *src,
unsigned int src_cnt)
@@ -234,790 +92,13 @@ static void prep_dma_pqzero_sum_dbg(int id, dma_addr_t *src,
pr_debug("\t0x%016llx ", src[src_cnt + i]);
}
-/******************************************************************************
- * Command (Descriptor) Blocks low-level routines
- ******************************************************************************/
-/**
- * ppc440spe_desc_init_interrupt - initialize the descriptor for INTERRUPT
- * pseudo operation
- */
-static void ppc440spe_desc_init_interrupt(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan)
-{
- struct xor_cb *p;
-
- switch (chan->device->id) {
- case PPC440SPE_XOR_ID:
- p = desc->hw_desc;
- memset(desc->hw_desc, 0, sizeof(struct xor_cb));
- /* NOP with Command Block Complete Enable */
- p->cbc = XOR_CBCR_CBCE_BIT;
- break;
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- memset(desc->hw_desc, 0, sizeof(struct dma_cdb));
- /* NOP with interrupt */
- set_bit(PPC440SPE_DESC_INT, &desc->flags);
- break;
- default:
- printk(KERN_ERR "Unsupported id %d in %s\n", chan->device->id,
- __func__);
- break;
- }
-}
-
-/**
- * ppc440spe_desc_init_null_xor - initialize the descriptor for NULL XOR
- * pseudo operation
- */
-static void ppc440spe_desc_init_null_xor(struct ppc440spe_adma_desc_slot *desc)
-{
- memset(desc->hw_desc, 0, sizeof(struct xor_cb));
- desc->hw_next = NULL;
- desc->src_cnt = 0;
- desc->dst_cnt = 1;
-}
-
-/**
- * ppc440spe_desc_init_xor - initialize the descriptor for XOR operation
- */
-static void ppc440spe_desc_init_xor(struct ppc440spe_adma_desc_slot *desc,
- int src_cnt, unsigned long flags)
-{
- struct xor_cb *hw_desc = desc->hw_desc;
-
- memset(desc->hw_desc, 0, sizeof(struct xor_cb));
- desc->hw_next = NULL;
- desc->src_cnt = src_cnt;
- desc->dst_cnt = 1;
-
- hw_desc->cbc = XOR_CBCR_TGT_BIT | src_cnt;
- if (flags & DMA_PREP_INTERRUPT)
- /* Enable interrupt on completion */
- hw_desc->cbc |= XOR_CBCR_CBCE_BIT;
-}
-
-/**
- * ppc440spe_desc_init_dma2pq - initialize the descriptor for PQ
- * operation in DMA2 controller
- */
-static void ppc440spe_desc_init_dma2pq(struct ppc440spe_adma_desc_slot *desc,
- int dst_cnt, int src_cnt, unsigned long flags)
-{
- struct xor_cb *hw_desc = desc->hw_desc;
-
- memset(desc->hw_desc, 0, sizeof(struct xor_cb));
- desc->hw_next = NULL;
- desc->src_cnt = src_cnt;
- desc->dst_cnt = dst_cnt;
- memset(desc->reverse_flags, 0, sizeof(desc->reverse_flags));
- desc->descs_per_op = 0;
-
- hw_desc->cbc = XOR_CBCR_TGT_BIT;
- if (flags & DMA_PREP_INTERRUPT)
- /* Enable interrupt on completion */
- hw_desc->cbc |= XOR_CBCR_CBCE_BIT;
-}
-
-#define DMA_CTRL_FLAGS_LAST DMA_PREP_FENCE
-#define DMA_PREP_ZERO_P (DMA_CTRL_FLAGS_LAST << 1)
-#define DMA_PREP_ZERO_Q (DMA_PREP_ZERO_P << 1)
-
-/**
- * ppc440spe_desc_init_dma01pq - initialize the descriptors for PQ operation
- * with DMA0/1
- */
-static void ppc440spe_desc_init_dma01pq(struct ppc440spe_adma_desc_slot *desc,
- int dst_cnt, int src_cnt, unsigned long flags,
- unsigned long op)
-{
- struct dma_cdb *hw_desc;
- struct ppc440spe_adma_desc_slot *iter;
- u8 dopc;
-
- /* Common initialization of a PQ descriptors chain */
- set_bits(op, &desc->flags);
- desc->src_cnt = src_cnt;
- desc->dst_cnt = dst_cnt;
-
- /* WXOR MULTICAST if both P and Q are being computed
- * MV_SG1_SG2 if Q only
- */
- dopc = (desc->dst_cnt == DMA_DEST_MAX_NUM) ?
- DMA_CDB_OPC_MULTICAST : DMA_CDB_OPC_MV_SG1_SG2;
-
- list_for_each_entry(iter, &desc->group_list, chain_node) {
- hw_desc = iter->hw_desc;
- memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
-
- if (likely(!list_is_last(&iter->chain_node,
- &desc->group_list))) {
- /* set 'next' pointer */
- iter->hw_next = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot, chain_node);
- clear_bit(PPC440SPE_DESC_INT, &iter->flags);
- } else {
- /* this is the last descriptor.
- * this slot will be pasted from ADMA level
- * each time it wants to configure parameters
- * of the transaction (src, dst, ...)
- */
- iter->hw_next = NULL;
- if (flags & DMA_PREP_INTERRUPT)
- set_bit(PPC440SPE_DESC_INT, &iter->flags);
- else
- clear_bit(PPC440SPE_DESC_INT, &iter->flags);
- }
- }
-
- /* Set OPS depending on WXOR/RXOR type of operation */
- if (!test_bit(PPC440SPE_DESC_RXOR, &desc->flags)) {
- /* This is a WXOR only chain:
- * - first descriptors are for zeroing destinations
- * if PPC440SPE_ZERO_P/Q set;
- * - descriptors remained are for GF-XOR operations.
- */
- iter = list_first_entry(&desc->group_list,
- struct ppc440spe_adma_desc_slot,
- chain_node);
-
- if (test_bit(PPC440SPE_ZERO_P, &desc->flags)) {
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
- iter = list_first_entry(&iter->chain_node,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- }
-
- if (test_bit(PPC440SPE_ZERO_Q, &desc->flags)) {
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
- iter = list_first_entry(&iter->chain_node,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- }
-
- list_for_each_entry_from(iter, &desc->group_list, chain_node) {
- hw_desc = iter->hw_desc;
- hw_desc->opc = dopc;
- }
- } else {
- /* This is either RXOR-only or mixed RXOR/WXOR */
-
- /* The first 1 or 2 slots in chain are always RXOR,
- * if need to calculate P & Q, then there are two
- * RXOR slots; if only P or only Q, then there is one
- */
- iter = list_first_entry(&desc->group_list,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
-
- if (desc->dst_cnt == DMA_DEST_MAX_NUM) {
- iter = list_first_entry(&iter->chain_node,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
- }
-
- /* The remaining descs (if any) are WXORs */
- if (test_bit(PPC440SPE_DESC_WXOR, &desc->flags)) {
- iter = list_first_entry(&iter->chain_node,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- list_for_each_entry_from(iter, &desc->group_list,
- chain_node) {
- hw_desc = iter->hw_desc;
- hw_desc->opc = dopc;
- }
- }
- }
-}
-
-/**
- * ppc440spe_desc_init_dma01pqzero_sum - initialize the descriptor
- * for PQ_ZERO_SUM operation
- */
-static void ppc440spe_desc_init_dma01pqzero_sum(
- struct ppc440spe_adma_desc_slot *desc,
- int dst_cnt, int src_cnt)
-{
- struct dma_cdb *hw_desc;
- struct ppc440spe_adma_desc_slot *iter;
- int i = 0;
- u8 dopc = (dst_cnt == 2) ? DMA_CDB_OPC_MULTICAST :
- DMA_CDB_OPC_MV_SG1_SG2;
- /*
- * Initialize starting from 2nd or 3rd descriptor dependent
- * on dst_cnt. First one or two slots are for cloning P
- * and/or Q to chan->pdest and/or chan->qdest as we have
- * to preserve original P/Q.
- */
- iter = list_first_entry(&desc->group_list,
- struct ppc440spe_adma_desc_slot, chain_node);
- iter = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot, chain_node);
-
- if (dst_cnt > 1) {
- iter = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot, chain_node);
- }
- /* initialize each source descriptor in chain */
- list_for_each_entry_from(iter, &desc->group_list, chain_node) {
- hw_desc = iter->hw_desc;
- memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
- iter->src_cnt = 0;
- iter->dst_cnt = 0;
-
- /* This is a ZERO_SUM operation:
- * - <src_cnt> descriptors starting from 2nd or 3rd
- * descriptor are for GF-XOR operations;
- * - remaining <dst_cnt> descriptors are for checking the result
- */
- if (i++ < src_cnt)
- /* MV_SG1_SG2 if only Q is being verified
- * MULTICAST if both P and Q are being verified
- */
- hw_desc->opc = dopc;
- else
- /* DMA_CDB_OPC_DCHECK128 operation */
- hw_desc->opc = DMA_CDB_OPC_DCHECK128;
-
- if (likely(!list_is_last(&iter->chain_node,
- &desc->group_list))) {
- /* set 'next' pointer */
- iter->hw_next = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- } else {
- /* this is the last descriptor.
- * this slot will be pasted from ADMA level
- * each time it wants to configure parameters
- * of the transaction (src, dst, ...)
- */
- iter->hw_next = NULL;
- /* always enable interrupt generation since we get
- * the status of pqzero from the handler
- */
- set_bit(PPC440SPE_DESC_INT, &iter->flags);
- }
- }
- desc->src_cnt = src_cnt;
- desc->dst_cnt = dst_cnt;
-}
-
-/**
- * ppc440spe_desc_init_memcpy - initialize the descriptor for MEMCPY operation
- */
-static void ppc440spe_desc_init_memcpy(struct ppc440spe_adma_desc_slot *desc,
- unsigned long flags)
-{
- struct dma_cdb *hw_desc = desc->hw_desc;
-
- memset(desc->hw_desc, 0, sizeof(struct dma_cdb));
- desc->hw_next = NULL;
- desc->src_cnt = 1;
- desc->dst_cnt = 1;
-
- if (flags & DMA_PREP_INTERRUPT)
- set_bit(PPC440SPE_DESC_INT, &desc->flags);
- else
- clear_bit(PPC440SPE_DESC_INT, &desc->flags);
-
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
-}
-
-/**
- * ppc440spe_desc_init_memset - initialize the descriptor for MEMSET operation
- */
-static void ppc440spe_desc_init_memset(struct ppc440spe_adma_desc_slot *desc,
- int value, unsigned long flags)
-{
- struct dma_cdb *hw_desc = desc->hw_desc;
-
- memset(desc->hw_desc, 0, sizeof(struct dma_cdb));
- desc->hw_next = NULL;
- desc->src_cnt = 1;
- desc->dst_cnt = 1;
-
- if (flags & DMA_PREP_INTERRUPT)
- set_bit(PPC440SPE_DESC_INT, &desc->flags);
- else
- clear_bit(PPC440SPE_DESC_INT, &desc->flags);
-
- hw_desc->sg1u = hw_desc->sg1l = cpu_to_le32((u32)value);
- hw_desc->sg3u = hw_desc->sg3l = cpu_to_le32((u32)value);
- hw_desc->opc = DMA_CDB_OPC_DFILL128;
-}
-
-/**
- * ppc440spe_desc_set_src_addr - set source address into the descriptor
- */
-static void ppc440spe_desc_set_src_addr(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan,
- int src_idx, dma_addr_t addrh,
- dma_addr_t addrl)
-{
- struct dma_cdb *dma_hw_desc;
- struct xor_cb *xor_hw_desc;
- phys_addr_t addr64, tmplow, tmphi;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- if (!addrh) {
- addr64 = addrl;
- tmphi = (addr64 >> 32);
- tmplow = (addr64 & 0xFFFFFFFF);
- } else {
- tmphi = addrh;
- tmplow = addrl;
- }
- dma_hw_desc = desc->hw_desc;
- dma_hw_desc->sg1l = cpu_to_le32((u32)tmplow);
- dma_hw_desc->sg1u |= cpu_to_le32((u32)tmphi);
- break;
- case PPC440SPE_XOR_ID:
- xor_hw_desc = desc->hw_desc;
- xor_hw_desc->ops[src_idx].l = addrl;
- xor_hw_desc->ops[src_idx].h |= addrh;
- break;
- }
-}
-
-/**
- * ppc440spe_desc_set_src_mult - set source address mult into the descriptor
- */
-static void ppc440spe_desc_set_src_mult(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan, u32 mult_index,
- int sg_index, unsigned char mult_value)
-{
- struct dma_cdb *dma_hw_desc;
- struct xor_cb *xor_hw_desc;
- u32 *psgu;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- dma_hw_desc = desc->hw_desc;
-
- switch (sg_index) {
- /* for RXOR operations set multiplier
- * into source cued address
- */
- case DMA_CDB_SG_SRC:
- psgu = &dma_hw_desc->sg1u;
- break;
- /* for WXOR operations set multiplier
- * into destination cued address(es)
- */
- case DMA_CDB_SG_DST1:
- psgu = &dma_hw_desc->sg2u;
- break;
- case DMA_CDB_SG_DST2:
- psgu = &dma_hw_desc->sg3u;
- break;
- default:
- BUG();
- }
-
- *psgu |= cpu_to_le32(mult_value << mult_index);
- break;
- case PPC440SPE_XOR_ID:
- xor_hw_desc = desc->hw_desc;
- break;
- default:
- BUG();
- }
-}
-
-/**
- * ppc440spe_desc_set_dest_addr - set destination address into the descriptor
- */
-static void ppc440spe_desc_set_dest_addr(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan,
- dma_addr_t addrh, dma_addr_t addrl,
- u32 dst_idx)
-{
- struct dma_cdb *dma_hw_desc;
- struct xor_cb *xor_hw_desc;
- phys_addr_t addr64, tmphi, tmplow;
- u32 *psgu, *psgl;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- if (!addrh) {
- addr64 = addrl;
- tmphi = (addr64 >> 32);
- tmplow = (addr64 & 0xFFFFFFFF);
- } else {
- tmphi = addrh;
- tmplow = addrl;
- }
- dma_hw_desc = desc->hw_desc;
-
- psgu = dst_idx ? &dma_hw_desc->sg3u : &dma_hw_desc->sg2u;
- psgl = dst_idx ? &dma_hw_desc->sg3l : &dma_hw_desc->sg2l;
-
- *psgl = cpu_to_le32((u32)tmplow);
- *psgu |= cpu_to_le32((u32)tmphi);
- break;
- case PPC440SPE_XOR_ID:
- xor_hw_desc = desc->hw_desc;
- xor_hw_desc->cbtal = addrl;
- xor_hw_desc->cbtah |= addrh;
- break;
- }
-}
-
-/**
- * ppc440spe_desc_set_byte_count - set number of data bytes involved
- * into the operation
- */
-static void ppc440spe_desc_set_byte_count(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan,
- u32 byte_count)
-{
- struct dma_cdb *dma_hw_desc;
- struct xor_cb *xor_hw_desc;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- dma_hw_desc = desc->hw_desc;
- dma_hw_desc->cnt = cpu_to_le32(byte_count);
- break;
- case PPC440SPE_XOR_ID:
- xor_hw_desc = desc->hw_desc;
- xor_hw_desc->cbbc = byte_count;
- break;
- }
-}
-
-/**
- * ppc440spe_desc_set_rxor_block_size - set RXOR block size
- */
-static inline void ppc440spe_desc_set_rxor_block_size(u32 byte_count)
-{
- /* assume that byte_count is aligned on the 512-boundary;
- * thus write it directly to the register (bits 23:31 are
- * reserved there).
- */
- dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_CF2H, byte_count);
-}
-
-/**
- * ppc440spe_desc_set_dcheck - set CHECK pattern
- */
-static void ppc440spe_desc_set_dcheck(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan, u8 *qword)
-{
- struct dma_cdb *dma_hw_desc;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- dma_hw_desc = desc->hw_desc;
- iowrite32(qword[0], &dma_hw_desc->sg3l);
- iowrite32(qword[4], &dma_hw_desc->sg3u);
- iowrite32(qword[8], &dma_hw_desc->sg2l);
- iowrite32(qword[12], &dma_hw_desc->sg2u);
- break;
- default:
- BUG();
- }
-}
-
-/**
- * ppc440spe_xor_set_link - set link address in xor CB
- */
-static void ppc440spe_xor_set_link(struct ppc440spe_adma_desc_slot *prev_desc,
- struct ppc440spe_adma_desc_slot *next_desc)
-{
- struct xor_cb *xor_hw_desc = prev_desc->hw_desc;
-
- if (unlikely(!next_desc || !(next_desc->phys))) {
- printk(KERN_ERR "%s: next_desc=0x%p; next_desc->phys=0x%llx\n",
- __func__, next_desc,
- next_desc ? next_desc->phys : 0);
- BUG();
- }
-
- xor_hw_desc->cbs = 0;
- xor_hw_desc->cblal = next_desc->phys;
- xor_hw_desc->cblah = 0;
- xor_hw_desc->cbc |= XOR_CBCR_LNK_BIT;
-}
/**
- * ppc440spe_desc_set_link - set the address of descriptor following this
- * descriptor in chain
- */
-static void ppc440spe_desc_set_link(struct ppc440spe_adma_chan *chan,
- struct ppc440spe_adma_desc_slot *prev_desc,
- struct ppc440spe_adma_desc_slot *next_desc)
-{
- unsigned long flags;
- struct ppc440spe_adma_desc_slot *tail = next_desc;
-
- if (unlikely(!prev_desc || !next_desc ||
- (prev_desc->hw_next && prev_desc->hw_next != next_desc))) {
- /* If previous next is overwritten something is wrong.
- * though we may refetch from append to initiate list
- * processing; in this case - it's ok.
- */
- printk(KERN_ERR "%s: prev_desc=0x%p; next_desc=0x%p; "
- "prev->hw_next=0x%p\n", __func__, prev_desc,
- next_desc, prev_desc ? prev_desc->hw_next : 0);
- BUG();
- }
-
- local_irq_save(flags);
-
- /* do s/w chaining both for DMA and XOR descriptors */
- prev_desc->hw_next = next_desc;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- break;
- case PPC440SPE_XOR_ID:
- /* bind descriptor to the chain */
- while (tail->hw_next)
- tail = tail->hw_next;
- xor_last_linked = tail;
-
- if (prev_desc == xor_last_submit)
- /* do not link to the last submitted CB */
- break;
- ppc440spe_xor_set_link(prev_desc, next_desc);
- break;
- }
-
- local_irq_restore(flags);
-}
-
-/**
- * ppc440spe_desc_get_src_addr - extract the source address from the descriptor
- */
-static u32 ppc440spe_desc_get_src_addr(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan, int src_idx)
-{
- struct dma_cdb *dma_hw_desc;
- struct xor_cb *xor_hw_desc;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- dma_hw_desc = desc->hw_desc;
- /* May have 0, 1, 2, or 3 sources */
- switch (dma_hw_desc->opc) {
- case DMA_CDB_OPC_NO_OP:
- case DMA_CDB_OPC_DFILL128:
- return 0;
- case DMA_CDB_OPC_DCHECK128:
- if (unlikely(src_idx)) {
- printk(KERN_ERR "%s: try to get %d source for"
- " DCHECK128\n", __func__, src_idx);
- BUG();
- }
- return le32_to_cpu(dma_hw_desc->sg1l);
- case DMA_CDB_OPC_MULTICAST:
- case DMA_CDB_OPC_MV_SG1_SG2:
- if (unlikely(src_idx > 2)) {
- printk(KERN_ERR "%s: try to get %d source from"
- " DMA descr\n", __func__, src_idx);
- BUG();
- }
- if (src_idx) {
- if (le32_to_cpu(dma_hw_desc->sg1u) &
- DMA_CUED_XOR_WIN_MSK) {
- u8 region;
-
- if (src_idx == 1)
- return le32_to_cpu(
- dma_hw_desc->sg1l) +
- desc->unmap_len;
-
- region = (le32_to_cpu(
- dma_hw_desc->sg1u)) >>
- DMA_CUED_REGION_OFF;
-
- region &= DMA_CUED_REGION_MSK;
- switch (region) {
- case DMA_RXOR123:
- return le32_to_cpu(
- dma_hw_desc->sg1l) +
- (desc->unmap_len << 1);
- case DMA_RXOR124:
- return le32_to_cpu(
- dma_hw_desc->sg1l) +
- (desc->unmap_len * 3);
- case DMA_RXOR125:
- return le32_to_cpu(
- dma_hw_desc->sg1l) +
- (desc->unmap_len << 2);
- default:
- printk(KERN_ERR
- "%s: try to"
- " get src3 for region %02x"
- "PPC440SPE_DESC_RXOR12?\n",
- __func__, region);
- BUG();
- }
- } else {
- printk(KERN_ERR
- "%s: try to get %d"
- " source for non-cued descr\n",
- __func__, src_idx);
- BUG();
- }
- }
- return le32_to_cpu(dma_hw_desc->sg1l);
- default:
- printk(KERN_ERR "%s: unknown OPC 0x%02x\n",
- __func__, dma_hw_desc->opc);
- BUG();
- }
- return le32_to_cpu(dma_hw_desc->sg1l);
- case PPC440SPE_XOR_ID:
- /* May have up to 16 sources */
- xor_hw_desc = desc->hw_desc;
- return xor_hw_desc->ops[src_idx].l;
- }
- return 0;
-}
-
-/**
- * ppc440spe_desc_get_dest_addr - extract the destination address from the
- * descriptor
- */
-static u32 ppc440spe_desc_get_dest_addr(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan, int idx)
-{
- struct dma_cdb *dma_hw_desc;
- struct xor_cb *xor_hw_desc;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- dma_hw_desc = desc->hw_desc;
-
- if (likely(!idx))
- return le32_to_cpu(dma_hw_desc->sg2l);
- return le32_to_cpu(dma_hw_desc->sg3l);
- case PPC440SPE_XOR_ID:
- xor_hw_desc = desc->hw_desc;
- return xor_hw_desc->cbtal;
- }
- return 0;
-}
-
-/**
- * ppc440spe_desc_get_src_num - extract the number of source addresses from
- * the descriptor
- */
-static u32 ppc440spe_desc_get_src_num(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan)
-{
- struct dma_cdb *dma_hw_desc;
- struct xor_cb *xor_hw_desc;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- dma_hw_desc = desc->hw_desc;
-
- switch (dma_hw_desc->opc) {
- case DMA_CDB_OPC_NO_OP:
- case DMA_CDB_OPC_DFILL128:
- return 0;
- case DMA_CDB_OPC_DCHECK128:
- return 1;
- case DMA_CDB_OPC_MV_SG1_SG2:
- case DMA_CDB_OPC_MULTICAST:
- /*
- * Only for RXOR operations we have more than
- * one source
- */
- if (le32_to_cpu(dma_hw_desc->sg1u) &
- DMA_CUED_XOR_WIN_MSK) {
- /* RXOR op, there are 2 or 3 sources */
- if (((le32_to_cpu(dma_hw_desc->sg1u) >>
- DMA_CUED_REGION_OFF) &
- DMA_CUED_REGION_MSK) == DMA_RXOR12) {
- /* RXOR 1-2 */
- return 2;
- } else {
- /* RXOR 1-2-3/1-2-4/1-2-5 */
- return 3;
- }
- }
- return 1;
- default:
- printk(KERN_ERR "%s: unknown OPC 0x%02x\n",
- __func__, dma_hw_desc->opc);
- BUG();
- }
- case PPC440SPE_XOR_ID:
- /* up to 16 sources */
- xor_hw_desc = desc->hw_desc;
- return xor_hw_desc->cbc & XOR_CDCR_OAC_MSK;
- default:
- BUG();
- }
- return 0;
-}
-
-/**
- * ppc440spe_desc_get_dst_num - get the number of destination addresses in
- * this descriptor
- */
-static u32 ppc440spe_desc_get_dst_num(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan)
-{
- struct dma_cdb *dma_hw_desc;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- /* May be 1 or 2 destinations */
- dma_hw_desc = desc->hw_desc;
- switch (dma_hw_desc->opc) {
- case DMA_CDB_OPC_NO_OP:
- case DMA_CDB_OPC_DCHECK128:
- return 0;
- case DMA_CDB_OPC_MV_SG1_SG2:
- case DMA_CDB_OPC_DFILL128:
- return 1;
- case DMA_CDB_OPC_MULTICAST:
- if (desc->dst_cnt == 2)
- return 2;
- else
- return 1;
- default:
- printk(KERN_ERR "%s: unknown OPC 0x%02x\n",
- __func__, dma_hw_desc->opc);
- BUG();
- }
- case PPC440SPE_XOR_ID:
- /* Always only 1 destination */
- return 1;
- default:
- BUG();
- }
- return 0;
-}
-
-/**
- * ppc440spe_desc_get_link - get the address of the descriptor that
+ * ppc4xx_desc_get_link - get the address of the descriptor that
* follows this one
*/
-static inline u32 ppc440spe_desc_get_link(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan)
+static inline u32 ppc4xx_desc_get_link(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan)
{
if (!desc->hw_next)
return 0;
@@ -1026,19 +107,19 @@ static inline u32 ppc440spe_desc_get_link(struct ppc440spe_adma_desc_slot *desc,
}
/**
- * ppc440spe_desc_is_aligned - check alignment
+ * ppc4xx_desc_is_aligned - check alignment
*/
-static inline int ppc440spe_desc_is_aligned(
- struct ppc440spe_adma_desc_slot *desc, int num_slots)
+static inline int ppc4xx_desc_is_aligned(
+ struct ppc4xx_adma_desc_slot *desc, int num_slots)
{
return (desc->idx & (num_slots - 1)) ? 0 : 1;
}
/**
- * ppc440spe_chan_xor_slot_count - get the number of slots necessary for
+ * ppc4xx_chan_xor_slot_count - get the number of slots necessary for
* XOR operation
*/
-static int ppc440spe_chan_xor_slot_count(size_t len, int src_cnt,
+static int ppc4xx_chan_xor_slot_count(size_t len, int src_cnt,
int *slots_per_op)
{
int slot_cnt;
@@ -1046,631 +127,33 @@ static int ppc440spe_chan_xor_slot_count(size_t len, int src_cnt,
/* each XOR descriptor provides up to 16 source operands */
slot_cnt = *slots_per_op = (src_cnt + XOR_MAX_OPS - 1)/XOR_MAX_OPS;
- if (likely(len <= PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT))
+ if (likely(len <= PPC4XX_ADMA_XOR_MAX_BYTE_COUNT))
return slot_cnt;
printk(KERN_ERR "%s: len %d > max %d !!\n",
- __func__, len, PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT);
+ __func__, len, PPC4XX_ADMA_XOR_MAX_BYTE_COUNT);
BUG();
return slot_cnt;
}
-/**
- * ppc440spe_dma2_pq_slot_count - get the number of slots necessary for
- * DMA2 PQ operation
- */
-static int ppc440spe_dma2_pq_slot_count(dma_addr_t *srcs,
- int src_cnt, size_t len)
-{
- signed long long order = 0;
- int state = 0;
- int addr_count = 0;
- int i;
- for (i = 1; i < src_cnt; i++) {
- dma_addr_t cur_addr = srcs[i];
- dma_addr_t old_addr = srcs[i-1];
- switch (state) {
- case 0:
- if (cur_addr == old_addr + len) {
- /* direct RXOR */
- order = 1;
- state = 1;
- if (i == src_cnt-1)
- addr_count++;
- } else if (old_addr == cur_addr + len) {
- /* reverse RXOR */
- order = -1;
- state = 1;
- if (i == src_cnt-1)
- addr_count++;
- } else {
- state = 3;
- }
- break;
- case 1:
- if (i == src_cnt-2 || (order == -1
- && cur_addr != old_addr - len)) {
- order = 0;
- state = 0;
- addr_count++;
- } else if (cur_addr == old_addr + len*order) {
- state = 2;
- if (i == src_cnt-1)
- addr_count++;
- } else if (cur_addr == old_addr + 2*len) {
- state = 2;
- if (i == src_cnt-1)
- addr_count++;
- } else if (cur_addr == old_addr + 3*len) {
- state = 2;
- if (i == src_cnt-1)
- addr_count++;
- } else {
- order = 0;
- state = 0;
- addr_count++;
- }
- break;
- case 2:
- order = 0;
- state = 0;
- addr_count++;
- break;
- }
- if (state == 3)
- break;
- }
- if (src_cnt <= 1 || (state != 1 && state != 2)) {
- pr_err("%s: src_cnt=%d, state=%d, addr_count=%d, order=%lld\n",
- __func__, src_cnt, state, addr_count, order);
- for (i = 0; i < src_cnt; i++)
- pr_err("\t[%d] 0x%llx \n", i, srcs[i]);
- BUG();
- }
-
- return (addr_count + XOR_MAX_OPS - 1) / XOR_MAX_OPS;
-}
-
-
-/******************************************************************************
- * ADMA channel low-level routines
- ******************************************************************************/
-
-static u32
-ppc440spe_chan_get_current_descriptor(struct ppc440spe_adma_chan *chan);
-static void ppc440spe_chan_append(struct ppc440spe_adma_chan *chan);
-
-/**
- * ppc440spe_adma_device_clear_eot_status - interrupt ack to XOR or DMA engine
- */
-static void ppc440spe_adma_device_clear_eot_status(
- struct ppc440spe_adma_chan *chan)
-{
- struct dma_regs *dma_reg;
- struct xor_regs *xor_reg;
- u8 *p = chan->device->dma_desc_pool_virt;
- struct dma_cdb *cdb;
- u32 rv, i;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- /* read FIFO to ack */
- dma_reg = chan->device->dma_reg;
- while ((rv = ioread32(&dma_reg->csfpl))) {
- i = rv & DMA_CDB_ADDR_MSK;
- cdb = (struct dma_cdb *)&p[i -
- (u32)chan->device->dma_desc_pool];
-
- /* Clear opcode to ack. This is necessary for
- * ZeroSum operations only
- */
- cdb->opc = 0;
-
- if (test_bit(PPC440SPE_RXOR_RUN,
- &ppc440spe_rxor_state)) {
- /* probably this is a completed RXOR op,
- * get pointer to CDB using the fact that
- * physical and virtual addresses of CDB
- * in pools have the same offsets
- */
- if (le32_to_cpu(cdb->sg1u) &
- DMA_CUED_XOR_BASE) {
- /* this is a RXOR */
- clear_bit(PPC440SPE_RXOR_RUN,
- &ppc440spe_rxor_state);
- }
- }
-
- if (rv & DMA_CDB_STATUS_MSK) {
- /* ZeroSum check failed
- */
- struct ppc440spe_adma_desc_slot *iter;
- dma_addr_t phys = rv & ~DMA_CDB_MSK;
-
- /*
- * Update the status of corresponding
- * descriptor.
- */
- list_for_each_entry(iter, &chan->chain,
- chain_node) {
- if (iter->phys == phys)
- break;
- }
- /*
- * if cannot find the corresponding
- * slot it's a bug
- */
- BUG_ON(&iter->chain_node == &chan->chain);
-
- if (iter->xor_check_result) {
- if (test_bit(PPC440SPE_DESC_PCHECK,
- &iter->flags)) {
- *iter->xor_check_result |=
- SUM_CHECK_P_RESULT;
- } else
- if (test_bit(PPC440SPE_DESC_QCHECK,
- &iter->flags)) {
- *iter->xor_check_result |=
- SUM_CHECK_Q_RESULT;
- } else
- BUG();
- }
- }
- }
-
- rv = ioread32(&dma_reg->dsts);
- if (rv) {
- pr_err("DMA%d err status: 0x%x\n",
- chan->device->id, rv);
- /* write back to clear */
- iowrite32(rv, &dma_reg->dsts);
- }
- break;
- case PPC440SPE_XOR_ID:
- /* reset status bits to ack */
- xor_reg = chan->device->xor_reg;
- rv = ioread32be(&xor_reg->sr);
- iowrite32be(rv, &xor_reg->sr);
-
- if (rv & (XOR_IE_ICBIE_BIT|XOR_IE_ICIE_BIT|XOR_IE_RPTIE_BIT)) {
- if (rv & XOR_IE_RPTIE_BIT) {
- /* Read PLB Timeout Error.
- * Try to resubmit the CB
- */
- u32 val = ioread32be(&xor_reg->ccbalr);
-
- iowrite32be(val, &xor_reg->cblalr);
-
- val = ioread32be(&xor_reg->crsr);
- iowrite32be(val | XOR_CRSR_XAE_BIT,
- &xor_reg->crsr);
- } else
- pr_err("XOR ERR 0x%x status\n", rv);
- break;
- }
-
- /* if the XORcore is idle, but there are unprocessed CBs
- * then refetch the s/w chain here
- */
- if (!(ioread32be(&xor_reg->sr) & XOR_SR_XCP_BIT) &&
- do_xor_refetch)
- ppc440spe_chan_append(chan);
- break;
- }
-}
-
-/**
- * ppc440spe_chan_is_busy - get the channel status
- */
-static int ppc440spe_chan_is_busy(struct ppc440spe_adma_chan *chan)
-{
- struct dma_regs *dma_reg;
- struct xor_regs *xor_reg;
- int busy = 0;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- dma_reg = chan->device->dma_reg;
- /* if command FIFO's head and tail pointers are equal and
- * status tail is the same as command, then channel is free
- */
- if (ioread16(&dma_reg->cpfhp) != ioread16(&dma_reg->cpftp) ||
- ioread16(&dma_reg->cpftp) != ioread16(&dma_reg->csftp))
- busy = 1;
- break;
- case PPC440SPE_XOR_ID:
- /* use the special status bit for the XORcore
- */
- xor_reg = chan->device->xor_reg;
- busy = (ioread32be(&xor_reg->sr) & XOR_SR_XCP_BIT) ? 1 : 0;
- break;
- }
-
- return busy;
-}
-
-/**
- * ppc440spe_chan_set_first_xor_descriptor - init XORcore chain
- */
-static void ppc440spe_chan_set_first_xor_descriptor(
- struct ppc440spe_adma_chan *chan,
- struct ppc440spe_adma_desc_slot *next_desc)
-{
- struct xor_regs *xor_reg = chan->device->xor_reg;
-
- if (ioread32be(&xor_reg->sr) & XOR_SR_XCP_BIT)
- printk(KERN_INFO "%s: Warn: XORcore is running "
- "when try to set the first CDB!\n",
- __func__);
-
- xor_last_submit = xor_last_linked = next_desc;
-
- iowrite32be(XOR_CRSR_64BA_BIT, &xor_reg->crsr);
-
- iowrite32be(next_desc->phys, &xor_reg->cblalr);
- iowrite32be(0, &xor_reg->cblahr);
- iowrite32be(ioread32be(&xor_reg->cbcr) | XOR_CBCR_LNK_BIT,
- &xor_reg->cbcr);
-
- chan->hw_chain_inited = 1;
-}
-
-/**
- * ppc440spe_dma_put_desc - put DMA0,1 descriptor to FIFO.
- * called with irqs disabled
- */
-static void ppc440spe_dma_put_desc(struct ppc440spe_adma_chan *chan,
- struct ppc440spe_adma_desc_slot *desc)
-{
- u32 pcdb;
- struct dma_regs *dma_reg = chan->device->dma_reg;
-
- pcdb = desc->phys;
- if (!test_bit(PPC440SPE_DESC_INT, &desc->flags))
- pcdb |= DMA_CDB_NO_INT;
-
- chan_last_sub[chan->device->id] = desc;
-
- ADMA_LL_DBG(print_cb(chan, desc->hw_desc));
-
- iowrite32(pcdb, &dma_reg->cpfpl);
-}
-
-/**
- * ppc440spe_chan_append - update the h/w chain in the channel
- */
-static void ppc440spe_chan_append(struct ppc440spe_adma_chan *chan)
-{
- struct xor_regs *xor_reg;
- struct ppc440spe_adma_desc_slot *iter;
- struct xor_cb *xcb;
- u32 cur_desc;
- unsigned long flags;
-
- local_irq_save(flags);
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- cur_desc = ppc440spe_chan_get_current_descriptor(chan);
-
- if (likely(cur_desc)) {
- iter = chan_last_sub[chan->device->id];
- BUG_ON(!iter);
- } else {
- /* first peer */
- iter = chan_first_cdb[chan->device->id];
- BUG_ON(!iter);
- ppc440spe_dma_put_desc(chan, iter);
- chan->hw_chain_inited = 1;
- }
-
- /* is there something new to append */
- if (!iter->hw_next)
- break;
-
- /* flush descriptors from the s/w queue to fifo */
- list_for_each_entry_continue(iter, &chan->chain, chain_node) {
- ppc440spe_dma_put_desc(chan, iter);
- if (!iter->hw_next)
- break;
- }
- break;
- case PPC440SPE_XOR_ID:
- /* update h/w links and refetch */
- if (!xor_last_submit->hw_next)
- break;
-
- xor_reg = chan->device->xor_reg;
- /* the last linked CDB has to generate an interrupt
- * that we'd be able to append the next lists to h/w
- * regardless of the XOR engine state at the moment of
- * appending of these next lists
- */
- xcb = xor_last_linked->hw_desc;
- xcb->cbc |= XOR_CBCR_CBCE_BIT;
-
- if (!(ioread32be(&xor_reg->sr) & XOR_SR_XCP_BIT)) {
- /* XORcore is idle. Refetch now */
- do_xor_refetch = 0;
- ppc440spe_xor_set_link(xor_last_submit,
- xor_last_submit->hw_next);
-
- ADMA_LL_DBG(print_cb_list(chan,
- xor_last_submit->hw_next));
-
- xor_last_submit = xor_last_linked;
- iowrite32be(ioread32be(&xor_reg->crsr) |
- XOR_CRSR_RCBE_BIT | XOR_CRSR_64BA_BIT,
- &xor_reg->crsr);
- } else {
- /* XORcore is running. Refetch later in the handler */
- do_xor_refetch = 1;
- }
-
- break;
- }
-
- local_irq_restore(flags);
-}
-
-/**
- * ppc440spe_chan_get_current_descriptor - get the currently executed descriptor
- */
-static u32
-ppc440spe_chan_get_current_descriptor(struct ppc440spe_adma_chan *chan)
-{
- struct dma_regs *dma_reg;
- struct xor_regs *xor_reg;
-
- if (unlikely(!chan->hw_chain_inited))
- /* h/w descriptor chain is not initialized yet */
- return 0;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- dma_reg = chan->device->dma_reg;
- return ioread32(&dma_reg->acpl) & (~DMA_CDB_MSK);
- case PPC440SPE_XOR_ID:
- xor_reg = chan->device->xor_reg;
- return ioread32be(&xor_reg->ccbalr);
- }
- return 0;
-}
-
-/**
- * ppc440spe_chan_run - enable the channel
- */
-static void ppc440spe_chan_run(struct ppc440spe_adma_chan *chan)
-{
- struct xor_regs *xor_reg;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- /* DMAs are always enabled, do nothing */
- break;
- case PPC440SPE_XOR_ID:
- /* drain write buffer */
- xor_reg = chan->device->xor_reg;
-
- /* fetch descriptor pointed to in <link> */
- iowrite32be(XOR_CRSR_64BA_BIT | XOR_CRSR_XAE_BIT,
- &xor_reg->crsr);
- break;
- }
-}
-
/******************************************************************************
* ADMA device level
******************************************************************************/
-static void ppc440spe_chan_start_null_xor(struct ppc440spe_adma_chan *chan);
-static int ppc440spe_adma_alloc_chan_resources(struct dma_chan *chan);
+static void ppc4xx_chan_start_null_xor(struct ppc4xx_adma_chan *chan);
+static int ppc4xx_adma_alloc_chan_resources(struct dma_chan *chan);
static dma_cookie_t
-ppc440spe_adma_tx_submit(struct dma_async_tx_descriptor *tx);
-
-static void ppc440spe_adma_set_dest(struct ppc440spe_adma_desc_slot *tx,
- dma_addr_t addr, int index);
-static void
-ppc440spe_adma_memcpy_xor_set_src(struct ppc440spe_adma_desc_slot *tx,
- dma_addr_t addr, int index);
-
-static void
-ppc440spe_adma_pq_set_dest(struct ppc440spe_adma_desc_slot *tx,
- dma_addr_t *paddr, unsigned long flags);
-static void
-ppc440spe_adma_pq_set_src(struct ppc440spe_adma_desc_slot *tx,
- dma_addr_t addr, int index);
-static void
-ppc440spe_adma_pq_set_src_mult(struct ppc440spe_adma_desc_slot *tx,
- unsigned char mult, int index, int dst_pos);
-static void
-ppc440spe_adma_pqzero_sum_set_dest(struct ppc440spe_adma_desc_slot *tx,
- dma_addr_t paddr, dma_addr_t qaddr);
-
-static struct page *ppc440spe_rxor_srcs[32];
-
-/**
- * ppc440spe_can_rxor - check if the operands may be processed with RXOR
- */
-static int ppc440spe_can_rxor(struct page **srcs, int src_cnt, size_t len)
-{
- int i, order = 0, state = 0;
- int idx = 0;
-
- if (unlikely(!(src_cnt > 1)))
- return 0;
-
- BUG_ON(src_cnt > ARRAY_SIZE(ppc440spe_rxor_srcs));
-
- /* Skip holes in the source list before checking */
- for (i = 0; i < src_cnt; i++) {
- if (!srcs[i])
- continue;
- ppc440spe_rxor_srcs[idx++] = srcs[i];
- }
- src_cnt = idx;
-
- for (i = 1; i < src_cnt; i++) {
- char *cur_addr = page_address(ppc440spe_rxor_srcs[i]);
- char *old_addr = page_address(ppc440spe_rxor_srcs[i - 1]);
-
- switch (state) {
- case 0:
- if (cur_addr == old_addr + len) {
- /* direct RXOR */
- order = 1;
- state = 1;
- } else if (old_addr == cur_addr + len) {
- /* reverse RXOR */
- order = -1;
- state = 1;
- } else
- goto out;
- break;
- case 1:
- if ((i == src_cnt - 2) ||
- (order == -1 && cur_addr != old_addr - len)) {
- order = 0;
- state = 0;
- } else if ((cur_addr == old_addr + len * order) ||
- (cur_addr == old_addr + 2 * len) ||
- (cur_addr == old_addr + 3 * len)) {
- state = 2;
- } else {
- order = 0;
- state = 0;
- }
- break;
- case 2:
- order = 0;
- state = 0;
- break;
- }
- }
-
-out:
- if (state == 1 || state == 2)
- return 1;
-
- return 0;
-}
-
-/**
- * ppc440spe_adma_device_estimate - estimate the efficiency of processing
- * the operation given on this channel. It's assumed that 'chan' is
- * capable to process 'cap' type of operation.
- * @chan: channel to use
- * @cap: type of transaction
- * @dst_lst: array of destination pointers
- * @dst_cnt: number of destination operands
- * @src_lst: array of source pointers
- * @src_cnt: number of source operands
- * @src_sz: size of each source operand
- */
-static int ppc440spe_adma_estimate(struct dma_chan *chan,
- enum dma_transaction_type cap, struct page **dst_lst, int dst_cnt,
- struct page **src_lst, int src_cnt, size_t src_sz)
-{
- int ef = 1;
-
- if (cap == DMA_PQ || cap == DMA_PQ_VAL) {
- /* If RAID-6 capabilities were not activated don't try
- * to use them
- */
- if (unlikely(!ppc440spe_r6_enabled))
- return -1;
- }
- /* In the current implementation of ppc440spe ADMA driver it
- * makes sense to pick out only pq case, because it may be
- * processed:
- * (1) either using Biskup method on DMA2;
- * (2) or on DMA0/1.
- * Thus we give a favour to (1) if the sources are suitable;
- * else let it be processed on one of the DMA0/1 engines.
- * In the sum_product case where destination is also the
- * source process it on DMA0/1 only.
- */
- if (cap == DMA_PQ && chan->chan_id == PPC440SPE_XOR_ID) {
-
- if (dst_cnt == 1 && src_cnt == 2 && dst_lst[0] == src_lst[1])
- ef = 0; /* sum_product case, process on DMA0/1 */
- else if (ppc440spe_can_rxor(src_lst, src_cnt, src_sz))
- ef = 3; /* override (DMA0/1 + idle) */
- else
- ef = 0; /* can't process on DMA2 if !rxor */
- }
-
- /* channel idleness increases the priority */
- if (likely(ef) &&
- !ppc440spe_chan_is_busy(to_ppc440spe_adma_chan(chan)))
- ef++;
-
- return ef;
-}
-
-struct dma_chan *
-ppc440spe_async_tx_find_best_channel(enum dma_transaction_type cap,
- struct page **dst_lst, int dst_cnt, struct page **src_lst,
- int src_cnt, size_t src_sz)
-{
- struct dma_chan *best_chan = NULL;
- struct ppc_dma_chan_ref *ref;
- int best_rank = -1;
-
- if (unlikely(!src_sz))
- return NULL;
- if (src_sz > PAGE_SIZE) {
- /*
- * should a user of the api ever pass > PAGE_SIZE requests
- * we sort out cases where temporary page-sized buffers
- * are used.
- */
- switch (cap) {
- case DMA_PQ:
- if (src_cnt == 1 && dst_lst[1] == src_lst[0])
- return NULL;
- if (src_cnt == 2 && dst_lst[1] == src_lst[1])
- return NULL;
- break;
- case DMA_PQ_VAL:
- case DMA_XOR_VAL:
- return NULL;
- default:
- break;
- }
- }
-
- list_for_each_entry(ref, &ppc440spe_adma_chan_list, node) {
- if (dma_has_cap(cap, ref->chan->device->cap_mask)) {
- int rank;
-
- rank = ppc440spe_adma_estimate(ref->chan, cap, dst_lst,
- dst_cnt, src_lst, src_cnt, src_sz);
- if (rank > best_rank) {
- best_rank = rank;
- best_chan = ref->chan;
- }
- }
- }
-
- return best_chan;
-}
-EXPORT_SYMBOL_GPL(ppc440spe_async_tx_find_best_channel);
+ppc4xx_adma_tx_submit(struct dma_async_tx_descriptor *tx);
/**
- * ppc440spe_get_group_entry - get group entry with index idx
+ * ppc4xx_get_group_entry - get group entry with index idx
* @tdesc: is the last allocated slot in the group.
*/
-static struct ppc440spe_adma_desc_slot *
-ppc440spe_get_group_entry(struct ppc440spe_adma_desc_slot *tdesc, u32 entry_idx)
+static struct ppc4xx_adma_desc_slot *
+ppc4xx_get_group_entry(struct ppc4xx_adma_desc_slot *tdesc, u32 entry_idx)
{
- struct ppc440spe_adma_desc_slot *iter = tdesc->group_head;
+ struct ppc4xx_adma_desc_slot *iter = tdesc->group_head;
int i = 0;
if (entry_idx < 0 || entry_idx >= (tdesc->src_cnt + tdesc->dst_cnt)) {
@@ -1687,25 +170,25 @@ ppc440spe_get_group_entry(struct ppc440spe_adma_desc_slot *tdesc, u32 entry_idx)
}
/**
- * ppc440spe_adma_free_slots - flags descriptor slots for reuse
+ * ppc4xx_adma_free_slots - flags descriptor slots for reuse
* @slot: Slot to free
- * Caller must hold &ppc440spe_chan->lock while calling this function
+ * Caller must hold &ppc4xx_chan->lock while calling this function
*/
-static void ppc440spe_adma_free_slots(struct ppc440spe_adma_desc_slot *slot,
- struct ppc440spe_adma_chan *chan)
+static void ppc4xx_adma_free_slots(struct ppc4xx_adma_desc_slot *slot,
+ struct ppc4xx_adma_chan *chan)
{
int stride = slot->slots_per_op;
while (stride--) {
slot->slots_per_op = 0;
slot = list_entry(slot->slot_node.next,
- struct ppc440spe_adma_desc_slot,
+ struct ppc4xx_adma_desc_slot,
slot_node);
}
}
-static void ppc440spe_adma_unmap(struct ppc440spe_adma_chan *chan,
- struct ppc440spe_adma_desc_slot *desc)
+static void ppc4xx_adma_unmap(struct ppc4xx_adma_chan *chan,
+ struct ppc4xx_adma_desc_slot *desc)
{
u32 src_cnt, dst_cnt;
dma_addr_t addr;
@@ -1715,13 +198,13 @@ static void ppc440spe_adma_unmap(struct ppc440spe_adma_chan *chan,
* included in this descriptor and unmap
* them all
*/
- src_cnt = ppc440spe_desc_get_src_num(desc, chan);
- dst_cnt = ppc440spe_desc_get_dst_num(desc, chan);
+ src_cnt = ppc4xx_desc_get_src_num(desc, chan);
+ dst_cnt = ppc4xx_desc_get_dst_num(desc, chan);
/* unmap destinations */
if (!(desc->async_tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
while (dst_cnt--) {
- addr = ppc440spe_desc_get_dest_addr(
+ addr = ppc4xx_desc_get_dest_addr(
desc, chan, dst_cnt);
dma_unmap_page(chan->device->dev,
addr, desc->unmap_len,
@@ -1732,7 +215,7 @@ static void ppc440spe_adma_unmap(struct ppc440spe_adma_chan *chan,
/* unmap sources */
if (!(desc->async_tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
while (src_cnt--) {
- addr = ppc440spe_desc_get_src_addr(
+ addr = ppc4xx_desc_get_src_addr(
desc, chan, src_cnt);
dma_unmap_page(chan->device->dev,
addr, desc->unmap_len,
@@ -1742,12 +225,12 @@ static void ppc440spe_adma_unmap(struct ppc440spe_adma_chan *chan,
}
/**
- * ppc440spe_adma_run_tx_complete_actions - call functions to be called
+ * ppc4xx_adma_run_tx_complete_actions - call functions to be called
* upon completion
*/
-static dma_cookie_t ppc440spe_adma_run_tx_complete_actions(
- struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan,
+static dma_cookie_t ppc4xx_adma_run_tx_complete_actions(
+ struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan,
dma_cookie_t cookie)
{
int i;
@@ -1772,7 +255,7 @@ static dma_cookie_t ppc440spe_adma_run_tx_complete_actions(
*/
if (chan && chan->needs_unmap && desc->group_head &&
desc->unmap_len) {
- struct ppc440spe_adma_desc_slot *unmap =
+ struct ppc4xx_adma_desc_slot *unmap =
desc->group_head;
/* assume 1 slot per op always */
u32 slot_count = unmap->slot_cnt;
@@ -1780,7 +263,7 @@ static dma_cookie_t ppc440spe_adma_run_tx_complete_actions(
/* Run through the group list and unmap addresses */
for (i = 0; i < slot_count; i++) {
BUG_ON(!unmap);
- ppc440spe_adma_unmap(chan, unmap);
+ ppc4xx_adma_unmap(chan, unmap);
unmap = unmap->hw_next;
}
}
@@ -1792,64 +275,23 @@ static dma_cookie_t ppc440spe_adma_run_tx_complete_actions(
return cookie;
}
-/**
- * ppc440spe_adma_clean_slot - clean up CDB slot (if ack is set)
- */
-static int ppc440spe_adma_clean_slot(struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_adma_chan *chan)
-{
- /* the client is allowed to attach dependent operations
- * until 'ack' is set
- */
- if (!async_tx_test_ack(&desc->async_tx))
- return 0;
-
- /* leave the last descriptor in the chain
- * so we can append to it
- */
- if (list_is_last(&desc->chain_node, &chan->chain) ||
- desc->phys == ppc440spe_chan_get_current_descriptor(chan))
- return 1;
-
- if (chan->device->id != PPC440SPE_XOR_ID) {
- /* our DMA interrupt handler clears opc field of
- * each processed descriptor. For all types of
- * operations except for ZeroSum we do not actually
- * need ack from the interrupt handler. ZeroSum is a
- * special case since the result of this operation
- * is available from the handler only, so if we see
- * such type of descriptor (which is unprocessed yet)
- * then leave it in chain.
- */
- struct dma_cdb *cdb = desc->hw_desc;
- if (cdb->opc == DMA_CDB_OPC_DCHECK128)
- return 1;
- }
-
- dev_dbg(chan->device->common.dev, "\tfree slot %llx: %d stride: %d\n",
- desc->phys, desc->idx, desc->slots_per_op);
-
- list_del(&desc->chain_node);
- ppc440spe_adma_free_slots(desc, chan);
- return 0;
-}
/**
- * __ppc440spe_adma_slot_cleanup - this is the common clean-up routine
+ * __ppc4xx_adma_slot_cleanup - this is the common clean-up routine
* which runs through the channel CDBs list until reach the descriptor
* currently processed. When routine determines that all CDBs of group
* are completed then corresponding callbacks (if any) are called and slots
* are freed.
*/
-static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
+static void __ppc4xx_adma_slot_cleanup(struct ppc4xx_adma_chan *chan)
{
- struct ppc440spe_adma_desc_slot *iter, *_iter, *group_start = NULL;
+ struct ppc4xx_adma_desc_slot *iter, *_iter, *group_start = NULL;
dma_cookie_t cookie = 0;
- u32 current_desc = ppc440spe_chan_get_current_descriptor(chan);
- int busy = ppc440spe_chan_is_busy(chan);
+ u32 current_desc = ppc4xx_chan_get_current_descriptor(chan);
+ int busy = ppc4xx_chan_is_busy(chan);
int seen_current = 0, slot_cnt = 0, slots_per_op = 0;
- dev_dbg(chan->device->common.dev, "ppc440spe adma%d: %s\n",
+ dev_dbg(chan->device->common.dev, "ppc4xx adma%d: %s\n",
chan->device->id, __func__);
if (!current_desc) {
@@ -1868,7 +310,7 @@ static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
"busy: %d this_desc: %#llx next_desc: %#x "
"cur: %#x ack: %d\n",
iter->async_tx.cookie, iter->idx, busy, iter->phys,
- ppc440spe_desc_get_link(iter, chan), current_desc,
+ ppc4xx_desc_get_link(iter, chan), current_desc,
async_tx_test_ack(&iter->async_tx));
prefetch(_iter);
prefetch(&_iter->async_tx);
@@ -1886,7 +328,7 @@ static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
*/
if (iter->phys == current_desc) {
BUG_ON(seen_current++);
- if (busy || ppc440spe_desc_get_link(iter, chan)) {
+ if (busy || ppc4xx_desc_get_link(iter, chan)) {
/* not all descriptors of the group have
* been completed; exit.
*/
@@ -1912,7 +354,7 @@ static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
/* all the members of a group are complete */
if (slots_per_op != 0 && slot_cnt == 0) {
- struct ppc440spe_adma_desc_slot *grp_iter, *_grp_iter;
+ struct ppc4xx_adma_desc_slot *grp_iter, *_grp_iter;
int end_of_chain = 0;
/* clean up the group */
@@ -1921,11 +363,11 @@ static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
list_for_each_entry_safe_from(grp_iter, _grp_iter,
&chan->chain, chain_node) {
- cookie = ppc440spe_adma_run_tx_complete_actions(
+ cookie = ppc4xx_adma_run_tx_complete_actions(
grp_iter, chan, cookie);
slot_cnt -= slots_per_op;
- end_of_chain = ppc440spe_adma_clean_slot(
+ end_of_chain = ppc4xx_adma_clean_slot(
grp_iter, chan);
if (end_of_chain && slot_cnt) {
/* Should wait for ZeroSum completion */
@@ -1950,10 +392,10 @@ static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
} else if (slots_per_op) /* wait for group completion */
continue;
- cookie = ppc440spe_adma_run_tx_complete_actions(iter, chan,
+ cookie = ppc4xx_adma_run_tx_complete_actions(iter, chan,
cookie);
- if (ppc440spe_adma_clean_slot(iter, chan))
+ if (ppc4xx_adma_clean_slot(iter, chan))
break;
}
@@ -1967,36 +409,36 @@ static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
}
/**
- * ppc440spe_adma_tasklet - clean up watch-dog initiator
+ * ppc4xx_adma_tasklet - clean up watch-dog initiator
*/
-static void ppc440spe_adma_tasklet(unsigned long data)
+static void ppc4xx_adma_tasklet(unsigned long data)
{
- struct ppc440spe_adma_chan *chan = (struct ppc440spe_adma_chan *) data;
+ struct ppc4xx_adma_chan *chan = (struct ppc4xx_adma_chan *) data;
spin_lock_nested(&chan->lock, SINGLE_DEPTH_NESTING);
- __ppc440spe_adma_slot_cleanup(chan);
+ __ppc4xx_adma_slot_cleanup(chan);
spin_unlock(&chan->lock);
}
/**
- * ppc440spe_adma_slot_cleanup - clean up scheduled initiator
+ * ppc4xx_adma_slot_cleanup - clean up scheduled initiator
*/
-static void ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
+static void ppc4xx_adma_slot_cleanup(struct ppc4xx_adma_chan *chan)
{
spin_lock_bh(&chan->lock);
- __ppc440spe_adma_slot_cleanup(chan);
+ __ppc4xx_adma_slot_cleanup(chan);
spin_unlock_bh(&chan->lock);
}
/**
- * ppc440spe_adma_alloc_slots - allocate free slots (if any)
+ * ppc4xx_adma_alloc_slots - allocate free slots (if any)
*/
-static struct ppc440spe_adma_desc_slot *ppc440spe_adma_alloc_slots(
- struct ppc440spe_adma_chan *chan, int num_slots,
+static struct ppc4xx_adma_desc_slot *ppc4xx_adma_alloc_slots(
+ struct ppc4xx_adma_chan *chan, int num_slots,
int slots_per_op)
{
- struct ppc440spe_adma_desc_slot *iter = NULL, *_iter;
- struct ppc440spe_adma_desc_slot *alloc_start = NULL;
+ struct ppc4xx_adma_desc_slot *iter = NULL, *_iter;
+ struct ppc4xx_adma_desc_slot *alloc_start = NULL;
struct list_head chain = LIST_HEAD_INIT(chain);
int slots_found, retry = 0;
@@ -2012,7 +454,7 @@ retry:
iter = chan->last_used;
else
iter = list_entry(&chan->all_slots,
- struct ppc440spe_adma_desc_slot,
+ struct ppc4xx_adma_desc_slot,
slot_node);
list_for_each_entry_safe_continue(iter, _iter, &chan->all_slots,
slot_node) {
@@ -2028,8 +470,8 @@ retry:
alloc_start = iter;
if (slots_found == num_slots) {
- struct ppc440spe_adma_desc_slot *alloc_tail = NULL;
- struct ppc440spe_adma_desc_slot *last_used = NULL;
+ struct ppc4xx_adma_desc_slot *alloc_tail = NULL;
+ struct ppc4xx_adma_desc_slot *last_used = NULL;
iter = alloc_start;
while (num_slots) {
@@ -2049,7 +491,7 @@ retry:
iter->slots_per_op = slots_per_op - i;
last_used = iter;
iter = list_entry(iter->slot_node.next,
- struct ppc440spe_adma_desc_slot,
+ struct ppc4xx_adma_desc_slot,
slot_node);
}
num_slots -= slots_per_op;
@@ -2070,29 +512,26 @@ retry:
}
/**
- * ppc440spe_adma_alloc_chan_resources - allocate pools for CDB slots
+ * ppc4xx_adma_alloc_chan_resources - allocate pools for CDB slots
*/
-static int ppc440spe_adma_alloc_chan_resources(struct dma_chan *chan)
+static int ppc4xx_adma_alloc_chan_resources(struct dma_chan *chan)
{
- struct ppc440spe_adma_chan *ppc440spe_chan;
- struct ppc440spe_adma_desc_slot *slot = NULL;
+ struct ppc4xx_adma_chan *ppc4xx_chan;
+ struct ppc4xx_adma_desc_slot *slot = NULL;
char *hw_desc;
int i, db_sz;
int init;
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
- init = ppc440spe_chan->slots_allocated ? 0 : 1;
- chan->chan_id = ppc440spe_chan->device->id;
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
+ init = ppc4xx_chan->slots_allocated ? 0 : 1;
+ chan->chan_id = ppc4xx_chan->device->id;
/* Allocate descriptor slots */
- i = ppc440spe_chan->slots_allocated;
- if (ppc440spe_chan->device->id != PPC440SPE_XOR_ID)
- db_sz = sizeof(struct dma_cdb);
- else
- db_sz = sizeof(struct xor_cb);
+ i = ppc4xx_chan->slots_allocated;
+ db_sz = ppc4xx_get_cdb_size(ppc4xx_chan);
- for (; i < (ppc440spe_chan->device->pool_size / db_sz); i++) {
- slot = kzalloc(sizeof(struct ppc440spe_adma_desc_slot),
+ for (; i < (ppc4xx_chan->device->pool_size / db_sz); i++) {
+ slot = kzalloc(sizeof(struct ppc4xx_adma_desc_slot),
GFP_KERNEL);
if (!slot) {
printk(KERN_INFO "SPE ADMA Channel only initialized"
@@ -2100,61 +539,48 @@ static int ppc440spe_adma_alloc_chan_resources(struct dma_chan *chan)
break;
}
- hw_desc = (char *) ppc440spe_chan->device->dma_desc_pool_virt;
+ hw_desc = (char *) ppc4xx_chan->device->dma_desc_pool_virt;
slot->hw_desc = (void *) &hw_desc[i * db_sz];
dma_async_tx_descriptor_init(&slot->async_tx, chan);
- slot->async_tx.tx_submit = ppc440spe_adma_tx_submit;
+ slot->async_tx.tx_submit = ppc4xx_adma_tx_submit;
INIT_LIST_HEAD(&slot->chain_node);
INIT_LIST_HEAD(&slot->slot_node);
INIT_LIST_HEAD(&slot->group_list);
- slot->phys = ppc440spe_chan->device->dma_desc_pool + i * db_sz;
+ slot->phys = ppc4xx_chan->device->dma_desc_pool + i * db_sz;
slot->idx = i;
- spin_lock_bh(&ppc440spe_chan->lock);
- ppc440spe_chan->slots_allocated++;
- list_add_tail(&slot->slot_node, &ppc440spe_chan->all_slots);
- spin_unlock_bh(&ppc440spe_chan->lock);
+ spin_lock_bh(&ppc4xx_chan->lock);
+ ppc4xx_chan->slots_allocated++;
+ list_add_tail(&slot->slot_node, &ppc4xx_chan->all_slots);
+ spin_unlock_bh(&ppc4xx_chan->lock);
}
- if (i && !ppc440spe_chan->last_used) {
- ppc440spe_chan->last_used =
- list_entry(ppc440spe_chan->all_slots.next,
- struct ppc440spe_adma_desc_slot,
+ if (i && !ppc4xx_chan->last_used) {
+ ppc4xx_chan->last_used =
+ list_entry(ppc4xx_chan->all_slots.next,
+ struct ppc4xx_adma_desc_slot,
slot_node);
}
- dev_dbg(ppc440spe_chan->device->common.dev,
- "ppc440spe adma%d: allocated %d descriptor slots\n",
- ppc440spe_chan->device->id, i);
+ dev_dbg(ppc4xx_chan->device->common.dev,
+ "ppc4xx adma%d: allocated %d descriptor slots\n",
+ ppc4xx_chan->device->id, i);
/* initialize the channel and the chain with a null operation */
if (init) {
- switch (ppc440spe_chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- ppc440spe_chan->hw_chain_inited = 0;
- /* Use WXOR for self-testing */
- if (!ppc440spe_r6_tchan)
- ppc440spe_r6_tchan = ppc440spe_chan;
- break;
- case PPC440SPE_XOR_ID:
- ppc440spe_chan_start_null_xor(ppc440spe_chan);
- break;
- default:
- BUG();
- }
- ppc440spe_chan->needs_unmap = 1;
+ ppc4xx_init_chan_null_op(ppc4xx_chan);
+ ppc4xx_chan->needs_unmap = 1;
}
return (i > 0) ? i : -ENOMEM;
}
/**
- * ppc440spe_desc_assign_cookie - assign a cookie
+ * ppc4xx_desc_assign_cookie - assign a cookie
*/
-static dma_cookie_t ppc440spe_desc_assign_cookie(
- struct ppc440spe_adma_chan *chan,
- struct ppc440spe_adma_desc_slot *desc)
+static dma_cookie_t ppc4xx_desc_assign_cookie(
+ struct ppc4xx_adma_chan *chan,
+ struct ppc4xx_adma_desc_slot *desc)
{
dma_cookie_t cookie = chan->common.cookie;
@@ -2165,70 +591,37 @@ static dma_cookie_t ppc440spe_desc_assign_cookie(
return cookie;
}
-/**
- * ppc440spe_rxor_set_region_data -
- */
-static void ppc440spe_rxor_set_region(struct ppc440spe_adma_desc_slot *desc,
- u8 xor_arg_no, u32 mask)
-{
- struct xor_cb *xcb = desc->hw_desc;
-
- xcb->ops[xor_arg_no].h |= mask;
-}
-
-/**
- * ppc440spe_rxor_set_src -
- */
-static void ppc440spe_rxor_set_src(struct ppc440spe_adma_desc_slot *desc,
- u8 xor_arg_no, dma_addr_t addr)
-{
- struct xor_cb *xcb = desc->hw_desc;
-
- xcb->ops[xor_arg_no].h |= DMA_CUED_XOR_BASE;
- xcb->ops[xor_arg_no].l = addr;
-}
/**
- * ppc440spe_rxor_set_mult -
- */
-static void ppc440spe_rxor_set_mult(struct ppc440spe_adma_desc_slot *desc,
- u8 xor_arg_no, u8 idx, u8 mult)
-{
- struct xor_cb *xcb = desc->hw_desc;
-
- xcb->ops[xor_arg_no].h |= mult << (DMA_CUED_MULT1_OFF + idx * 8);
-}
-
-/**
- * ppc440spe_adma_check_threshold - append CDBs to h/w chain if threshold
+ * ppc4xx_adma_check_threshold - append CDBs to h/w chain if threshold
* has been achieved
*/
-static void ppc440spe_adma_check_threshold(struct ppc440spe_adma_chan *chan)
+static void ppc4xx_adma_check_threshold(struct ppc4xx_adma_chan *chan)
{
- dev_dbg(chan->device->common.dev, "ppc440spe adma%d: pending: %d\n",
+ dev_dbg(chan->device->common.dev, "ppc4xx adma%d: pending: %d\n",
chan->device->id, chan->pending);
- if (chan->pending >= PPC440SPE_ADMA_THRESHOLD) {
+ if (chan->pending >= PPC4XX_ADMA_THRESHOLD) {
chan->pending = 0;
- ppc440spe_chan_append(chan);
+ ppc4xx_chan_append(chan);
}
}
/**
- * ppc440spe_adma_tx_submit - submit new descriptor group to the channel
+ * ppc4xx_adma_tx_submit - submit new descriptor group to the channel
* (it's not necessary that descriptors will be submitted to the h/w
* chains too right now)
*/
-static dma_cookie_t ppc440spe_adma_tx_submit(struct dma_async_tx_descriptor *tx)
+static dma_cookie_t ppc4xx_adma_tx_submit(struct dma_async_tx_descriptor *tx)
{
- struct ppc440spe_adma_desc_slot *sw_desc;
- struct ppc440spe_adma_chan *chan = to_ppc440spe_adma_chan(tx->chan);
- struct ppc440spe_adma_desc_slot *group_start, *old_chain_tail;
+ struct ppc4xx_adma_desc_slot *sw_desc;
+ struct ppc4xx_adma_chan *chan = to_ppc4xx_adma_chan(tx->chan);
+ struct ppc4xx_adma_desc_slot *group_start, *old_chain_tail;
int slot_cnt;
int slots_per_op;
dma_cookie_t cookie;
- sw_desc = tx_to_ppc440spe_adma_slot(tx);
+ sw_desc = tx_to_ppc4xx_adma_slot(tx);
group_start = sw_desc->group_head;
slot_cnt = group_start->slot_cnt;
@@ -2236,7 +629,7 @@ static dma_cookie_t ppc440spe_adma_tx_submit(struct dma_async_tx_descriptor *tx)
spin_lock_bh(&chan->lock);
- cookie = ppc440spe_desc_assign_cookie(chan, sw_desc);
+ cookie = ppc4xx_desc_assign_cookie(chan, sw_desc);
if (unlikely(list_empty(&chan->chain))) {
/* first peer */
@@ -2245,21 +638,21 @@ static dma_cookie_t ppc440spe_adma_tx_submit(struct dma_async_tx_descriptor *tx)
} else {
/* isn't first peer, bind CDBs to chain */
old_chain_tail = list_entry(chan->chain.prev,
- struct ppc440spe_adma_desc_slot,
+ struct ppc4xx_adma_desc_slot,
chain_node);
list_splice_init(&sw_desc->group_list,
&old_chain_tail->chain_node);
/* fix up the hardware chain */
- ppc440spe_desc_set_link(chan, old_chain_tail, group_start);
+ ppc4xx_desc_set_link(chan, old_chain_tail, group_start);
}
/* increment the pending count by the number of operations */
chan->pending += slot_cnt / slots_per_op;
- ppc440spe_adma_check_threshold(chan);
+ ppc4xx_adma_check_threshold(chan);
spin_unlock_bh(&chan->lock);
dev_dbg(chan->device->common.dev,
- "ppc440spe adma%d: %s cookie: %d slot: %d tx %p\n",
+ "ppc4xx adma%d: %s cookie: %d slot: %d tx %p\n",
chan->device->id, __func__,
sw_desc->async_tx.cookie, sw_desc->idx, sw_desc);
@@ -2267,1666 +660,194 @@ static dma_cookie_t ppc440spe_adma_tx_submit(struct dma_async_tx_descriptor *tx)
}
/**
- * ppc440spe_adma_prep_dma_interrupt - prepare CDB for a pseudo DMA operation
+ * ppc4xx_adma_prep_dma_interrupt - prepare CDB for a pseudo DMA operation
*/
-static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_interrupt(
+static struct dma_async_tx_descriptor *ppc4xx_adma_prep_dma_interrupt(
struct dma_chan *chan, unsigned long flags)
{
- struct ppc440spe_adma_chan *ppc440spe_chan;
- struct ppc440spe_adma_desc_slot *sw_desc, *group_start;
+ struct ppc4xx_adma_chan *ppc4xx_chan;
+ struct ppc4xx_adma_desc_slot *sw_desc, *group_start;
int slot_cnt, slots_per_op;
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
- dev_dbg(ppc440spe_chan->device->common.dev,
- "ppc440spe adma%d: %s\n", ppc440spe_chan->device->id,
+ dev_dbg(ppc4xx_chan->device->common.dev,
+ "ppc4xx adma%d: %s\n", ppc4xx_chan->device->id,
__func__);
- spin_lock_bh(&ppc440spe_chan->lock);
+ spin_lock_bh(&ppc4xx_chan->lock);
slot_cnt = slots_per_op = 1;
- sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt,
+ sw_desc = ppc4xx_adma_alloc_slots(ppc4xx_chan, slot_cnt,
slots_per_op);
if (sw_desc) {
group_start = sw_desc->group_head;
- ppc440spe_desc_init_interrupt(group_start, ppc440spe_chan);
+ ppc4xx_desc_init_interrupt(group_start, ppc4xx_chan);
group_start->unmap_len = 0;
sw_desc->async_tx.flags = flags;
}
- spin_unlock_bh(&ppc440spe_chan->lock);
+ spin_unlock_bh(&ppc4xx_chan->lock);
return sw_desc ? &sw_desc->async_tx : NULL;
}
/**
- * ppc440spe_adma_prep_dma_memcpy - prepare CDB for a MEMCPY operation
+ * ppc4xx_adma_prep_dma_memcpy - prepare CDB for a MEMCPY operation
*/
-static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_memcpy(
+static struct dma_async_tx_descriptor *ppc4xx_adma_prep_dma_memcpy(
struct dma_chan *chan, dma_addr_t dma_dest,
dma_addr_t dma_src, size_t len, unsigned long flags)
{
- struct ppc440spe_adma_chan *ppc440spe_chan;
- struct ppc440spe_adma_desc_slot *sw_desc, *group_start;
+ struct ppc4xx_adma_chan *ppc4xx_chan;
+ struct ppc4xx_adma_desc_slot *sw_desc, *group_start;
int slot_cnt, slots_per_op;
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
if (unlikely(!len))
return NULL;
- BUG_ON(unlikely(len > PPC440SPE_ADMA_DMA_MAX_BYTE_COUNT));
+ BUG_ON(unlikely(len > PPC4XX_ADMA_DMA_MAX_BYTE_COUNT));
- spin_lock_bh(&ppc440spe_chan->lock);
+ spin_lock_bh(&ppc4xx_chan->lock);
- dev_dbg(ppc440spe_chan->device->common.dev,
- "ppc440spe adma%d: %s len: %u int_en %d\n",
- ppc440spe_chan->device->id, __func__, len,
+ dev_dbg(ppc4xx_chan->device->common.dev,
+ "ppc4xx adma%d: %s len: %u int_en %d\n",
+ ppc4xx_chan->device->id, __func__, len,
flags & DMA_PREP_INTERRUPT ? 1 : 0);
slot_cnt = slots_per_op = 1;
- sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt,
+ sw_desc = ppc4xx_adma_alloc_slots(ppc4xx_chan, slot_cnt,
slots_per_op);
if (sw_desc) {
group_start = sw_desc->group_head;
- ppc440spe_desc_init_memcpy(group_start, flags);
- ppc440spe_adma_set_dest(group_start, dma_dest, 0);
- ppc440spe_adma_memcpy_xor_set_src(group_start, dma_src, 0);
- ppc440spe_desc_set_byte_count(group_start, ppc440spe_chan, len);
+ ppc4xx_desc_init_memcpy(group_start, flags);
+ ppc4xx_adma_set_dest(group_start, dma_dest, 0);
+ ppc4xx_adma_memcpy_xor_set_src(group_start, dma_src, 0);
+ ppc4xx_desc_set_byte_count(group_start, ppc4xx_chan, len);
sw_desc->unmap_len = len;
sw_desc->async_tx.flags = flags;
}
- spin_unlock_bh(&ppc440spe_chan->lock);
+ spin_unlock_bh(&ppc4xx_chan->lock);
return sw_desc ? &sw_desc->async_tx : NULL;
}
/**
- * ppc440spe_adma_prep_dma_memset - prepare CDB for a MEMSET operation
+ * ppc4xx_adma_prep_dma_memset - prepare CDB for a MEMSET operation
*/
-static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_memset(
+static struct dma_async_tx_descriptor *ppc4xx_adma_prep_dma_memset(
struct dma_chan *chan, dma_addr_t dma_dest, int value,
size_t len, unsigned long flags)
{
- struct ppc440spe_adma_chan *ppc440spe_chan;
- struct ppc440spe_adma_desc_slot *sw_desc, *group_start;
+ struct ppc4xx_adma_chan *ppc4xx_chan;
+ struct ppc4xx_adma_desc_slot *sw_desc, *group_start;
int slot_cnt, slots_per_op;
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
if (unlikely(!len))
return NULL;
- BUG_ON(unlikely(len > PPC440SPE_ADMA_DMA_MAX_BYTE_COUNT));
+ BUG_ON(unlikely(len > PPC4XX_ADMA_DMA_MAX_BYTE_COUNT));
- spin_lock_bh(&ppc440spe_chan->lock);
+ spin_lock_bh(&ppc4xx_chan->lock);
- dev_dbg(ppc440spe_chan->device->common.dev,
- "ppc440spe adma%d: %s cal: %u len: %u int_en %d\n",
- ppc440spe_chan->device->id, __func__, value, len,
+ dev_dbg(ppc4xx_chan->device->common.dev,
+ "ppc4xx adma%d: %s cal: %u len: %u int_en %d\n",
+ ppc4xx_chan->device->id, __func__, value, len,
flags & DMA_PREP_INTERRUPT ? 1 : 0);
slot_cnt = slots_per_op = 1;
- sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt,
+ sw_desc = ppc4xx_adma_alloc_slots(ppc4xx_chan, slot_cnt,
slots_per_op);
if (sw_desc) {
group_start = sw_desc->group_head;
- ppc440spe_desc_init_memset(group_start, value, flags);
- ppc440spe_adma_set_dest(group_start, dma_dest, 0);
- ppc440spe_desc_set_byte_count(group_start, ppc440spe_chan, len);
+ ppc4xx_desc_init_memset(group_start, value, flags);
+ ppc4xx_adma_set_dest(group_start, dma_dest, 0);
+ ppc4xx_desc_set_byte_count(group_start, ppc4xx_chan, len);
sw_desc->unmap_len = len;
sw_desc->async_tx.flags = flags;
}
- spin_unlock_bh(&ppc440spe_chan->lock);
+ spin_unlock_bh(&ppc4xx_chan->lock);
return sw_desc ? &sw_desc->async_tx : NULL;
}
/**
- * ppc440spe_adma_prep_dma_xor - prepare CDB for a XOR operation
+ * ppc4xx_adma_prep_dma_xor - prepare CDB for a XOR operation
*/
-static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_xor(
+static struct dma_async_tx_descriptor *ppc4xx_adma_prep_dma_xor(
struct dma_chan *chan, dma_addr_t dma_dest,
dma_addr_t *dma_src, u32 src_cnt, size_t len,
unsigned long flags)
{
- struct ppc440spe_adma_chan *ppc440spe_chan;
- struct ppc440spe_adma_desc_slot *sw_desc, *group_start;
+ struct ppc4xx_adma_chan *ppc4xx_chan;
+ struct ppc4xx_adma_desc_slot *sw_desc, *group_start;
int slot_cnt, slots_per_op;
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
- ADMA_LL_DBG(prep_dma_xor_dbg(ppc440spe_chan->device->id,
+ ADMA_LL_DBG(prep_dma_xor_dbg(ppc4xx_chan->device->id,
dma_dest, dma_src, src_cnt));
if (unlikely(!len))
return NULL;
- BUG_ON(unlikely(len > PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT));
+ BUG_ON(unlikely(len > PPC4XX_ADMA_XOR_MAX_BYTE_COUNT));
- dev_dbg(ppc440spe_chan->device->common.dev,
- "ppc440spe adma%d: %s src_cnt: %d len: %u int_en: %d\n",
- ppc440spe_chan->device->id, __func__, src_cnt, len,
+ dev_dbg(ppc4xx_chan->device->common.dev,
+ "ppc4xx adma%d: %s src_cnt: %d len: %u int_en: %d\n",
+ ppc4xx_chan->device->id, __func__, src_cnt, len,
flags & DMA_PREP_INTERRUPT ? 1 : 0);
- spin_lock_bh(&ppc440spe_chan->lock);
- slot_cnt = ppc440spe_chan_xor_slot_count(len, src_cnt, &slots_per_op);
- sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt,
+ spin_lock_bh(&ppc4xx_chan->lock);
+ slot_cnt = ppc4xx_chan_xor_slot_count(len, src_cnt, &slots_per_op);
+ sw_desc = ppc4xx_adma_alloc_slots(ppc4xx_chan, slot_cnt,
slots_per_op);
if (sw_desc) {
group_start = sw_desc->group_head;
- ppc440spe_desc_init_xor(group_start, src_cnt, flags);
- ppc440spe_adma_set_dest(group_start, dma_dest, 0);
+ ppc4xx_desc_init_xor(group_start, src_cnt, flags);
+ ppc4xx_adma_set_dest(group_start, dma_dest, 0);
while (src_cnt--)
- ppc440spe_adma_memcpy_xor_set_src(group_start,
+ ppc4xx_adma_memcpy_xor_set_src(group_start,
dma_src[src_cnt], src_cnt);
- ppc440spe_desc_set_byte_count(group_start, ppc440spe_chan, len);
+ ppc4xx_desc_set_byte_count(group_start, ppc4xx_chan, len);
sw_desc->unmap_len = len;
sw_desc->async_tx.flags = flags;
}
- spin_unlock_bh(&ppc440spe_chan->lock);
-
- return sw_desc ? &sw_desc->async_tx : NULL;
-}
-
-static inline void
-ppc440spe_desc_set_xor_src_cnt(struct ppc440spe_adma_desc_slot *desc,
- int src_cnt);
-static void ppc440spe_init_rxor_cursor(struct ppc440spe_rxor *cursor);
-
-/**
- * ppc440spe_adma_init_dma2rxor_slot -
- */
-static void ppc440spe_adma_init_dma2rxor_slot(
- struct ppc440spe_adma_desc_slot *desc,
- dma_addr_t *src, int src_cnt)
-{
- int i;
-
- /* initialize CDB */
- for (i = 0; i < src_cnt; i++) {
- ppc440spe_adma_dma2rxor_prep_src(desc, &desc->rxor_cursor, i,
- desc->src_cnt, (u32)src[i]);
- }
-}
-
-/**
- * ppc440spe_dma01_prep_mult -
- * for Q operation where destination is also the source
- */
-static struct ppc440spe_adma_desc_slot *ppc440spe_dma01_prep_mult(
- struct ppc440spe_adma_chan *ppc440spe_chan,
- dma_addr_t *dst, int dst_cnt, dma_addr_t *src, int src_cnt,
- const unsigned char *scf, size_t len, unsigned long flags)
-{
- struct ppc440spe_adma_desc_slot *sw_desc = NULL;
- unsigned long op = 0;
- int slot_cnt;
-
- set_bit(PPC440SPE_DESC_WXOR, &op);
- slot_cnt = 2;
-
- spin_lock_bh(&ppc440spe_chan->lock);
-
- /* use WXOR, each descriptor occupies one slot */
- sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt, 1);
- if (sw_desc) {
- struct ppc440spe_adma_chan *chan;
- struct ppc440spe_adma_desc_slot *iter;
- struct dma_cdb *hw_desc;
-
- chan = to_ppc440spe_adma_chan(sw_desc->async_tx.chan);
- set_bits(op, &sw_desc->flags);
- sw_desc->src_cnt = src_cnt;
- sw_desc->dst_cnt = dst_cnt;
- /* First descriptor, zero data in the destination and copy it
- * to q page using MULTICAST transfer.
- */
- iter = list_first_entry(&sw_desc->group_list,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
- /* set 'next' pointer */
- iter->hw_next = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- clear_bit(PPC440SPE_DESC_INT, &iter->flags);
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MULTICAST;
-
- ppc440spe_desc_set_dest_addr(iter, chan,
- DMA_CUED_XOR_BASE, dst[0], 0);
- ppc440spe_desc_set_dest_addr(iter, chan, 0, dst[1], 1);
- ppc440spe_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB,
- src[0]);
- ppc440spe_desc_set_byte_count(iter, ppc440spe_chan, len);
- iter->unmap_len = len;
-
- /*
- * Second descriptor, multiply data from the q page
- * and store the result in real destination.
- */
- iter = list_first_entry(&iter->chain_node,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
- iter->hw_next = NULL;
- if (flags & DMA_PREP_INTERRUPT)
- set_bit(PPC440SPE_DESC_INT, &iter->flags);
- else
- clear_bit(PPC440SPE_DESC_INT, &iter->flags);
-
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
- ppc440spe_desc_set_src_addr(iter, chan, 0,
- DMA_CUED_XOR_HB, dst[1]);
- ppc440spe_desc_set_dest_addr(iter, chan,
- DMA_CUED_XOR_BASE, dst[0], 0);
-
- ppc440spe_desc_set_src_mult(iter, chan, DMA_CUED_MULT1_OFF,
- DMA_CDB_SG_DST1, scf[0]);
- ppc440spe_desc_set_byte_count(iter, ppc440spe_chan, len);
- iter->unmap_len = len;
- sw_desc->async_tx.flags = flags;
- }
-
- spin_unlock_bh(&ppc440spe_chan->lock);
-
- return sw_desc;
-}
-
-/**
- * ppc440spe_dma01_prep_sum_product -
- * Dx = A*(P+Pxy) + B*(Q+Qxy) operation where destination is also
- * the source.
- */
-static struct ppc440spe_adma_desc_slot *ppc440spe_dma01_prep_sum_product(
- struct ppc440spe_adma_chan *ppc440spe_chan,
- dma_addr_t *dst, dma_addr_t *src, int src_cnt,
- const unsigned char *scf, size_t len, unsigned long flags)
-{
- struct ppc440spe_adma_desc_slot *sw_desc = NULL;
- unsigned long op = 0;
- int slot_cnt;
-
- set_bit(PPC440SPE_DESC_WXOR, &op);
- slot_cnt = 3;
-
- spin_lock_bh(&ppc440spe_chan->lock);
-
- /* WXOR, each descriptor occupies one slot */
- sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt, 1);
- if (sw_desc) {
- struct ppc440spe_adma_chan *chan;
- struct ppc440spe_adma_desc_slot *iter;
- struct dma_cdb *hw_desc;
-
- chan = to_ppc440spe_adma_chan(sw_desc->async_tx.chan);
- set_bits(op, &sw_desc->flags);
- sw_desc->src_cnt = src_cnt;
- sw_desc->dst_cnt = 1;
- /* 1st descriptor, src[1] data to q page and zero destination */
- iter = list_first_entry(&sw_desc->group_list,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
- iter->hw_next = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- clear_bit(PPC440SPE_DESC_INT, &iter->flags);
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MULTICAST;
-
- ppc440spe_desc_set_dest_addr(iter, chan, DMA_CUED_XOR_BASE,
- *dst, 0);
- ppc440spe_desc_set_dest_addr(iter, chan, 0,
- ppc440spe_chan->qdest, 1);
- ppc440spe_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB,
- src[1]);
- ppc440spe_desc_set_byte_count(iter, ppc440spe_chan, len);
- iter->unmap_len = len;
-
- /* 2nd descriptor, multiply src[1] data and store the
- * result in destination */
- iter = list_first_entry(&iter->chain_node,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
- /* set 'next' pointer */
- iter->hw_next = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- if (flags & DMA_PREP_INTERRUPT)
- set_bit(PPC440SPE_DESC_INT, &iter->flags);
- else
- clear_bit(PPC440SPE_DESC_INT, &iter->flags);
-
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
- ppc440spe_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB,
- ppc440spe_chan->qdest);
- ppc440spe_desc_set_dest_addr(iter, chan, DMA_CUED_XOR_BASE,
- *dst, 0);
- ppc440spe_desc_set_src_mult(iter, chan, DMA_CUED_MULT1_OFF,
- DMA_CDB_SG_DST1, scf[1]);
- ppc440spe_desc_set_byte_count(iter, ppc440spe_chan, len);
- iter->unmap_len = len;
-
- /*
- * 3rd descriptor, multiply src[0] data and xor it
- * with destination
- */
- iter = list_first_entry(&iter->chain_node,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
- iter->hw_next = NULL;
- if (flags & DMA_PREP_INTERRUPT)
- set_bit(PPC440SPE_DESC_INT, &iter->flags);
- else
- clear_bit(PPC440SPE_DESC_INT, &iter->flags);
-
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
- ppc440spe_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB,
- src[0]);
- ppc440spe_desc_set_dest_addr(iter, chan, DMA_CUED_XOR_BASE,
- *dst, 0);
- ppc440spe_desc_set_src_mult(iter, chan, DMA_CUED_MULT1_OFF,
- DMA_CDB_SG_DST1, scf[0]);
- ppc440spe_desc_set_byte_count(iter, ppc440spe_chan, len);
- iter->unmap_len = len;
- sw_desc->async_tx.flags = flags;
- }
-
- spin_unlock_bh(&ppc440spe_chan->lock);
-
- return sw_desc;
-}
-
-static struct ppc440spe_adma_desc_slot *ppc440spe_dma01_prep_pq(
- struct ppc440spe_adma_chan *ppc440spe_chan,
- dma_addr_t *dst, int dst_cnt, dma_addr_t *src, int src_cnt,
- const unsigned char *scf, size_t len, unsigned long flags)
-{
- int slot_cnt;
- struct ppc440spe_adma_desc_slot *sw_desc = NULL, *iter;
- unsigned long op = 0;
- unsigned char mult = 1;
-
- pr_debug("%s: dst_cnt %d, src_cnt %d, len %d\n",
- __func__, dst_cnt, src_cnt, len);
- /* select operations WXOR/RXOR depending on the
- * source addresses of operators and the number
- * of destinations (RXOR support only Q-parity calculations)
- */
- set_bit(PPC440SPE_DESC_WXOR, &op);
- if (!test_and_set_bit(PPC440SPE_RXOR_RUN, &ppc440spe_rxor_state)) {
- /* no active RXOR;
- * do RXOR if:
- * - there are more than 1 source,
- * - len is aligned on 512-byte boundary,
- * - source addresses fit to one of 4 possible regions.
- */
- if (src_cnt > 1 &&
- !(len & MQ0_CF2H_RXOR_BS_MASK) &&
- (src[0] + len) == src[1]) {
- /* may do RXOR R1 R2 */
- set_bit(PPC440SPE_DESC_RXOR, &op);
- if (src_cnt != 2) {
- /* may try to enhance region of RXOR */
- if ((src[1] + len) == src[2]) {
- /* do RXOR R1 R2 R3 */
- set_bit(PPC440SPE_DESC_RXOR123,
- &op);
- } else if ((src[1] + len * 2) == src[2]) {
- /* do RXOR R1 R2 R4 */
- set_bit(PPC440SPE_DESC_RXOR124, &op);
- } else if ((src[1] + len * 3) == src[2]) {
- /* do RXOR R1 R2 R5 */
- set_bit(PPC440SPE_DESC_RXOR125,
- &op);
- } else {
- /* do RXOR R1 R2 */
- set_bit(PPC440SPE_DESC_RXOR12,
- &op);
- }
- } else {
- /* do RXOR R1 R2 */
- set_bit(PPC440SPE_DESC_RXOR12, &op);
- }
- }
-
- if (!test_bit(PPC440SPE_DESC_RXOR, &op)) {
- /* can not do this operation with RXOR */
- clear_bit(PPC440SPE_RXOR_RUN,
- &ppc440spe_rxor_state);
- } else {
- /* can do; set block size right now */
- ppc440spe_desc_set_rxor_block_size(len);
- }
- }
-
- /* Number of necessary slots depends on operation type selected */
- if (!test_bit(PPC440SPE_DESC_RXOR, &op)) {
- /* This is a WXOR only chain. Need descriptors for each
- * source to GF-XOR them with WXOR, and need descriptors
- * for each destination to zero them with WXOR
- */
- slot_cnt = src_cnt;
-
- if (flags & DMA_PREP_ZERO_P) {
- slot_cnt++;
- set_bit(PPC440SPE_ZERO_P, &op);
- }
- if (flags & DMA_PREP_ZERO_Q) {
- slot_cnt++;
- set_bit(PPC440SPE_ZERO_Q, &op);
- }
- } else {
- /* Need 1/2 descriptor for RXOR operation, and
- * need (src_cnt - (2 or 3)) for WXOR of sources
- * remained (if any)
- */
- slot_cnt = dst_cnt;
-
- if (flags & DMA_PREP_ZERO_P)
- set_bit(PPC440SPE_ZERO_P, &op);
- if (flags & DMA_PREP_ZERO_Q)
- set_bit(PPC440SPE_ZERO_Q, &op);
-
- if (test_bit(PPC440SPE_DESC_RXOR12, &op))
- slot_cnt += src_cnt - 2;
- else
- slot_cnt += src_cnt - 3;
-
- /* Thus we have either RXOR only chain or
- * mixed RXOR/WXOR
- */
- if (slot_cnt == dst_cnt)
- /* RXOR only chain */
- clear_bit(PPC440SPE_DESC_WXOR, &op);
- }
-
- spin_lock_bh(&ppc440spe_chan->lock);
- /* for both RXOR/WXOR each descriptor occupies one slot */
- sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt, 1);
- if (sw_desc) {
- ppc440spe_desc_init_dma01pq(sw_desc, dst_cnt, src_cnt,
- flags, op);
-
- /* setup dst/src/mult */
- pr_debug("%s: set dst descriptor 0, 1: 0x%016llx, 0x%016llx\n",
- __func__, dst[0], dst[1]);
- ppc440spe_adma_pq_set_dest(sw_desc, dst, flags);
- while (src_cnt--) {
- ppc440spe_adma_pq_set_src(sw_desc, src[src_cnt],
- src_cnt);
-
- /* NOTE: "Multi = 0 is equivalent to = 1" as it
- * stated in 440SPSPe_RAID6_Addendum_UM_1_17.pdf
- * doesn't work for RXOR with DMA0/1! Instead, multi=0
- * leads to zeroing source data after RXOR.
- * So, for P case set-up mult=1 explicitly.
- */
- if (!(flags & DMA_PREP_PQ_DISABLE_Q))
- mult = scf[src_cnt];
- ppc440spe_adma_pq_set_src_mult(sw_desc,
- mult, src_cnt, dst_cnt - 1);
- }
-
- /* Setup byte count foreach slot just allocated */
- sw_desc->async_tx.flags = flags;
- list_for_each_entry(iter, &sw_desc->group_list,
- chain_node) {
- ppc440spe_desc_set_byte_count(iter,
- ppc440spe_chan, len);
- iter->unmap_len = len;
- }
- }
- spin_unlock_bh(&ppc440spe_chan->lock);
-
- return sw_desc;
-}
-
-static struct ppc440spe_adma_desc_slot *ppc440spe_dma2_prep_pq(
- struct ppc440spe_adma_chan *ppc440spe_chan,
- dma_addr_t *dst, int dst_cnt, dma_addr_t *src, int src_cnt,
- const unsigned char *scf, size_t len, unsigned long flags)
-{
- int slot_cnt, descs_per_op;
- struct ppc440spe_adma_desc_slot *sw_desc = NULL, *iter;
- unsigned long op = 0;
- unsigned char mult = 1;
-
- BUG_ON(!dst_cnt);
- /*pr_debug("%s: dst_cnt %d, src_cnt %d, len %d\n",
- __func__, dst_cnt, src_cnt, len);*/
-
- spin_lock_bh(&ppc440spe_chan->lock);
- descs_per_op = ppc440spe_dma2_pq_slot_count(src, src_cnt, len);
- if (descs_per_op < 0) {
- spin_unlock_bh(&ppc440spe_chan->lock);
- return NULL;
- }
-
- /* depending on number of sources we have 1 or 2 RXOR chains */
- slot_cnt = descs_per_op * dst_cnt;
-
- sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt, 1);
- if (sw_desc) {
- op = slot_cnt;
- sw_desc->async_tx.flags = flags;
- list_for_each_entry(iter, &sw_desc->group_list, chain_node) {
- ppc440spe_desc_init_dma2pq(iter, dst_cnt, src_cnt,
- --op ? 0 : flags);
- ppc440spe_desc_set_byte_count(iter, ppc440spe_chan,
- len);
- iter->unmap_len = len;
-
- ppc440spe_init_rxor_cursor(&(iter->rxor_cursor));
- iter->rxor_cursor.len = len;
- iter->descs_per_op = descs_per_op;
- }
- op = 0;
- list_for_each_entry(iter, &sw_desc->group_list, chain_node) {
- op++;
- if (op % descs_per_op == 0)
- ppc440spe_adma_init_dma2rxor_slot(iter, src,
- src_cnt);
- if (likely(!list_is_last(&iter->chain_node,
- &sw_desc->group_list))) {
- /* set 'next' pointer */
- iter->hw_next =
- list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- ppc440spe_xor_set_link(iter, iter->hw_next);
- } else {
- /* this is the last descriptor. */
- iter->hw_next = NULL;
- }
- }
-
- /* fixup head descriptor */
- sw_desc->dst_cnt = dst_cnt;
- if (flags & DMA_PREP_ZERO_P)
- set_bit(PPC440SPE_ZERO_P, &sw_desc->flags);
- if (flags & DMA_PREP_ZERO_Q)
- set_bit(PPC440SPE_ZERO_Q, &sw_desc->flags);
-
- /* setup dst/src/mult */
- ppc440spe_adma_pq_set_dest(sw_desc, dst, flags);
-
- while (src_cnt--) {
- /* handle descriptors (if dst_cnt == 2) inside
- * the ppc440spe_adma_pq_set_srcxxx() functions
- */
- ppc440spe_adma_pq_set_src(sw_desc, src[src_cnt],
- src_cnt);
- if (!(flags & DMA_PREP_PQ_DISABLE_Q))
- mult = scf[src_cnt];
- ppc440spe_adma_pq_set_src_mult(sw_desc,
- mult, src_cnt, dst_cnt - 1);
- }
- }
- spin_unlock_bh(&ppc440spe_chan->lock);
- ppc440spe_desc_set_rxor_block_size(len);
- return sw_desc;
-}
-
-/**
- * ppc440spe_adma_prep_dma_pq - prepare CDB (group) for a GF-XOR operation
- */
-static struct dma_async_tx_descriptor *ppc440spe_adma_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 ppc440spe_adma_chan *ppc440spe_chan;
- struct ppc440spe_adma_desc_slot *sw_desc = NULL;
- int dst_cnt = 0;
-
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
-
- ADMA_LL_DBG(prep_dma_pq_dbg(ppc440spe_chan->device->id,
- dst, src, src_cnt));
- BUG_ON(!len);
- BUG_ON(unlikely(len > PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT));
- BUG_ON(!src_cnt);
-
- if (src_cnt == 1 && dst[1] == src[0]) {
- dma_addr_t dest[2];
-
- /* dst[1] is real destination (Q) */
- dest[0] = dst[1];
- /* this is the page to multicast source data to */
- dest[1] = ppc440spe_chan->qdest;
- sw_desc = ppc440spe_dma01_prep_mult(ppc440spe_chan,
- dest, 2, src, src_cnt, scf, len, flags);
- return sw_desc ? &sw_desc->async_tx : NULL;
- }
-
- if (src_cnt == 2 && dst[1] == src[1]) {
- sw_desc = ppc440spe_dma01_prep_sum_product(ppc440spe_chan,
- &dst[1], src, 2, scf, len, flags);
- return sw_desc ? &sw_desc->async_tx : NULL;
- }
-
- if (!(flags & DMA_PREP_PQ_DISABLE_P)) {
- BUG_ON(!dst[0]);
- dst_cnt++;
- flags |= DMA_PREP_ZERO_P;
- }
-
- if (!(flags & DMA_PREP_PQ_DISABLE_Q)) {
- BUG_ON(!dst[1]);
- dst_cnt++;
- flags |= DMA_PREP_ZERO_Q;
- }
-
- BUG_ON(!dst_cnt);
-
- dev_dbg(ppc440spe_chan->device->common.dev,
- "ppc440spe adma%d: %s src_cnt: %d len: %u int_en: %d\n",
- ppc440spe_chan->device->id, __func__, src_cnt, len,
- flags & DMA_PREP_INTERRUPT ? 1 : 0);
-
- switch (ppc440spe_chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- sw_desc = ppc440spe_dma01_prep_pq(ppc440spe_chan,
- dst, dst_cnt, src, src_cnt, scf,
- len, flags);
- break;
-
- case PPC440SPE_XOR_ID:
- sw_desc = ppc440spe_dma2_prep_pq(ppc440spe_chan,
- dst, dst_cnt, src, src_cnt, scf,
- len, flags);
- break;
- }
+ spin_unlock_bh(&ppc4xx_chan->lock);
return sw_desc ? &sw_desc->async_tx : NULL;
}
/**
- * 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];
-
- ADMA_LL_DBG(prep_dma_pqzero_sum_dbg(ppc440spe_chan->device->id,
- src, src_cnt, scf));
-
- /* 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);
-
- /* Setup byte count for each slot just allocated */
- sw_desc->async_tx.flags = flags;
- list_for_each_entry(iter, &sw_desc->group_list, chain_node) {
- ppc440spe_desc_set_byte_count(iter, ppc440spe_chan,
- len);
- iter->unmap_len = len;
- }
-
- if (pdest) {
- struct dma_cdb *hw_desc;
- struct ppc440spe_adma_chan *chan;
-
- iter = sw_desc->group_head;
- chan = to_ppc440spe_adma_chan(iter->async_tx.chan);
- memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
- iter->hw_next = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
- iter->src_cnt = 0;
- iter->dst_cnt = 0;
- ppc440spe_desc_set_dest_addr(iter, chan, 0,
- ppc440spe_chan->pdest, 0);
- ppc440spe_desc_set_src_addr(iter, chan, 0, 0, pdest);
- ppc440spe_desc_set_byte_count(iter, ppc440spe_chan,
- len);
- iter->unmap_len = 0;
- /* override pdest to preserve original P */
- pdest = ppc440spe_chan->pdest;
- }
- if (qdest) {
- struct dma_cdb *hw_desc;
- struct ppc440spe_adma_chan *chan;
-
- iter = list_first_entry(&sw_desc->group_list,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- chan = to_ppc440spe_adma_chan(iter->async_tx.chan);
-
- if (pdest) {
- iter = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- }
-
- memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
- iter->hw_next = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- hw_desc = iter->hw_desc;
- hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
- iter->src_cnt = 0;
- iter->dst_cnt = 0;
- ppc440spe_desc_set_dest_addr(iter, chan, 0,
- ppc440spe_chan->qdest, 0);
- ppc440spe_desc_set_src_addr(iter, chan, 0, 0, qdest);
- ppc440spe_desc_set_byte_count(iter, ppc440spe_chan,
- len);
- iter->unmap_len = 0;
- /* override qdest to preserve original Q */
- qdest = ppc440spe_chan->qdest;
- }
-
- /* Setup destinations for P/Q ops */
- ppc440spe_adma_pqzero_sum_set_dest(sw_desc, pdest, qdest);
-
- /* Setup zero QWORDs into DCHECK CDBs */
- idst = dst_cnt;
- list_for_each_entry_reverse(iter, &sw_desc->group_list,
- chain_node) {
- /*
- * The last CDB corresponds to Q-parity check,
- * the one before last CDB corresponds
- * P-parity check
- */
- if (idst == DMA_DEST_MAX_NUM) {
- if (idst == dst_cnt) {
- set_bit(PPC440SPE_DESC_QCHECK,
- &iter->flags);
- } else {
- set_bit(PPC440SPE_DESC_PCHECK,
- &iter->flags);
- }
- } else {
- if (qdest) {
- set_bit(PPC440SPE_DESC_QCHECK,
- &iter->flags);
- } else {
- set_bit(PPC440SPE_DESC_PCHECK,
- &iter->flags);
- }
- }
- iter->xor_check_result = pqres;
-
- /*
- * set it to zero, if check fail then result will
- * be updated
- */
- *iter->xor_check_result = 0;
- ppc440spe_desc_set_dcheck(iter, ppc440spe_chan,
- ppc440spe_qword);
-
- if (!(--dst_cnt))
- break;
- }
-
- /* Setup sources and mults for P/Q ops */
- list_for_each_entry_continue_reverse(iter, &sw_desc->group_list,
- chain_node) {
- struct ppc440spe_adma_chan *chan;
- u32 mult_dst;
-
- chan = to_ppc440spe_adma_chan(iter->async_tx.chan);
- ppc440spe_desc_set_src_addr(iter, chan, 0,
- DMA_CUED_XOR_HB,
- src[src_cnt - 1]);
- if (qdest) {
- mult_dst = (dst_cnt - 1) ? DMA_CDB_SG_DST2 :
- DMA_CDB_SG_DST1;
- ppc440spe_desc_set_src_mult(iter, chan,
- DMA_CUED_MULT1_OFF,
- mult_dst,
- scf[src_cnt - 1]);
- }
- if (!(--src_cnt))
- break;
- }
- }
- spin_unlock_bh(&ppc440spe_chan->lock);
- return sw_desc ? &sw_desc->async_tx : NULL;
-}
-
-/**
- * ppc440spe_adma_prep_dma_xor_zero_sum - prepare CDB group for
- * XOR ZERO_SUM operation
- */
-static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_xor_zero_sum(
- struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt,
- size_t len, enum sum_check_flags *result, unsigned long flags)
-{
- struct dma_async_tx_descriptor *tx;
- dma_addr_t pq[2];
-
- /* validate P, disable Q */
- pq[0] = src[0];
- pq[1] = 0;
- flags |= DMA_PREP_PQ_DISABLE_Q;
-
- tx = ppc440spe_adma_prep_dma_pqzero_sum(chan, pq, &src[1],
- src_cnt - 1, 0, len,
- result, flags);
- return tx;
-}
-
-/**
- * ppc440spe_adma_set_dest - set destination address into descriptor
- */
-static void ppc440spe_adma_set_dest(struct ppc440spe_adma_desc_slot *sw_desc,
- dma_addr_t addr, int index)
-{
- struct ppc440spe_adma_chan *chan;
-
- BUG_ON(index >= sw_desc->dst_cnt);
-
- chan = to_ppc440spe_adma_chan(sw_desc->async_tx.chan);
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- /* to do: support transfers lengths >
- * PPC440SPE_ADMA_DMA/XOR_MAX_BYTE_COUNT
- */
- ppc440spe_desc_set_dest_addr(sw_desc->group_head,
- chan, 0, addr, index);
- break;
- case PPC440SPE_XOR_ID:
- sw_desc = ppc440spe_get_group_entry(sw_desc, index);
- ppc440spe_desc_set_dest_addr(sw_desc,
- chan, 0, addr, index);
- break;
- }
-}
-
-static void ppc440spe_adma_pq_zero_op(struct ppc440spe_adma_desc_slot *iter,
- struct ppc440spe_adma_chan *chan, dma_addr_t addr)
-{
- /* To clear destinations update the descriptor
- * (P or Q depending on index) as follows:
- * addr is destination (0 corresponds to SG2):
- */
- ppc440spe_desc_set_dest_addr(iter, chan, DMA_CUED_XOR_BASE, addr, 0);
-
- /* ... and the addr is source: */
- ppc440spe_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB, addr);
-
- /* addr is always SG2 then the mult is always DST1 */
- ppc440spe_desc_set_src_mult(iter, chan, DMA_CUED_MULT1_OFF,
- DMA_CDB_SG_DST1, 1);
-}
-
-/**
- * ppc440spe_adma_pq_set_dest - set destination address into descriptor
- * for the PQXOR operation
- */
-static void ppc440spe_adma_pq_set_dest(struct ppc440spe_adma_desc_slot *sw_desc,
- dma_addr_t *addrs, unsigned long flags)
-{
- struct ppc440spe_adma_desc_slot *iter;
- struct ppc440spe_adma_chan *chan;
- dma_addr_t paddr, qaddr;
- dma_addr_t addr = 0, ppath, qpath;
- int index = 0, i;
-
- chan = to_ppc440spe_adma_chan(sw_desc->async_tx.chan);
-
- if (flags & DMA_PREP_PQ_DISABLE_P)
- paddr = 0;
- else
- paddr = addrs[0];
-
- if (flags & DMA_PREP_PQ_DISABLE_Q)
- qaddr = 0;
- else
- qaddr = addrs[1];
-
- if (!paddr || !qaddr)
- addr = paddr ? paddr : qaddr;
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- /* walk through the WXOR source list and set P/Q-destinations
- * for each slot:
- */
- if (!test_bit(PPC440SPE_DESC_RXOR, &sw_desc->flags)) {
- /* This is WXOR-only chain; may have 1/2 zero descs */
- if (test_bit(PPC440SPE_ZERO_P, &sw_desc->flags))
- index++;
- if (test_bit(PPC440SPE_ZERO_Q, &sw_desc->flags))
- index++;
-
- iter = ppc440spe_get_group_entry(sw_desc, index);
- if (addr) {
- /* one destination */
- list_for_each_entry_from(iter,
- &sw_desc->group_list, chain_node)
- ppc440spe_desc_set_dest_addr(iter, chan,
- DMA_CUED_XOR_BASE, addr, 0);
- } else {
- /* two destinations */
- list_for_each_entry_from(iter,
- &sw_desc->group_list, chain_node) {
- ppc440spe_desc_set_dest_addr(iter, chan,
- DMA_CUED_XOR_BASE, paddr, 0);
- ppc440spe_desc_set_dest_addr(iter, chan,
- DMA_CUED_XOR_BASE, qaddr, 1);
- }
- }
-
- if (index) {
- /* To clear destinations update the descriptor
- * (1st,2nd, or both depending on flags)
- */
- index = 0;
- if (test_bit(PPC440SPE_ZERO_P,
- &sw_desc->flags)) {
- iter = ppc440spe_get_group_entry(
- sw_desc, index++);
- ppc440spe_adma_pq_zero_op(iter, chan,
- paddr);
- }
-
- if (test_bit(PPC440SPE_ZERO_Q,
- &sw_desc->flags)) {
- iter = ppc440spe_get_group_entry(
- sw_desc, index++);
- ppc440spe_adma_pq_zero_op(iter, chan,
- qaddr);
- }
-
- return;
- }
- } else {
- /* This is RXOR-only or RXOR/WXOR mixed chain */
-
- /* If we want to include destination into calculations,
- * then make dest addresses cued with mult=1 (XOR).
- */
- ppath = test_bit(PPC440SPE_ZERO_P, &sw_desc->flags) ?
- DMA_CUED_XOR_HB :
- DMA_CUED_XOR_BASE |
- (1 << DMA_CUED_MULT1_OFF);
- qpath = test_bit(PPC440SPE_ZERO_Q, &sw_desc->flags) ?
- DMA_CUED_XOR_HB :
- DMA_CUED_XOR_BASE |
- (1 << DMA_CUED_MULT1_OFF);
-
- /* Setup destination(s) in RXOR slot(s) */
- iter = ppc440spe_get_group_entry(sw_desc, index++);
- ppc440spe_desc_set_dest_addr(iter, chan,
- paddr ? ppath : qpath,
- paddr ? paddr : qaddr, 0);
- if (!addr) {
- /* two destinations */
- iter = ppc440spe_get_group_entry(sw_desc,
- index++);
- ppc440spe_desc_set_dest_addr(iter, chan,
- qpath, qaddr, 0);
- }
-
- if (test_bit(PPC440SPE_DESC_WXOR, &sw_desc->flags)) {
- /* Setup destination(s) in remaining WXOR
- * slots
- */
- iter = ppc440spe_get_group_entry(sw_desc,
- index);
- if (addr) {
- /* one destination */
- list_for_each_entry_from(iter,
- &sw_desc->group_list,
- chain_node)
- ppc440spe_desc_set_dest_addr(
- iter, chan,
- DMA_CUED_XOR_BASE,
- addr, 0);
-
- } else {
- /* two destinations */
- list_for_each_entry_from(iter,
- &sw_desc->group_list,
- chain_node) {
- ppc440spe_desc_set_dest_addr(
- iter, chan,
- DMA_CUED_XOR_BASE,
- paddr, 0);
- ppc440spe_desc_set_dest_addr(
- iter, chan,
- DMA_CUED_XOR_BASE,
- qaddr, 1);
- }
- }
- }
-
- }
- break;
-
- case PPC440SPE_XOR_ID:
- /* DMA2 descriptors have only 1 destination, so there are
- * two chains - one for each dest.
- * If we want to include destination into calculations,
- * then make dest addresses cued with mult=1 (XOR).
- */
- ppath = test_bit(PPC440SPE_ZERO_P, &sw_desc->flags) ?
- DMA_CUED_XOR_HB :
- DMA_CUED_XOR_BASE |
- (1 << DMA_CUED_MULT1_OFF);
-
- qpath = test_bit(PPC440SPE_ZERO_Q, &sw_desc->flags) ?
- DMA_CUED_XOR_HB :
- DMA_CUED_XOR_BASE |
- (1 << DMA_CUED_MULT1_OFF);
-
- iter = ppc440spe_get_group_entry(sw_desc, 0);
- for (i = 0; i < sw_desc->descs_per_op; i++) {
- ppc440spe_desc_set_dest_addr(iter, chan,
- paddr ? ppath : qpath,
- paddr ? paddr : qaddr, 0);
- iter = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- }
-
- if (!addr) {
- /* Two destinations; setup Q here */
- iter = ppc440spe_get_group_entry(sw_desc,
- sw_desc->descs_per_op);
- for (i = 0; i < sw_desc->descs_per_op; i++) {
- ppc440spe_desc_set_dest_addr(iter,
- chan, qpath, qaddr, 0);
- iter = list_entry(iter->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- }
- }
-
- break;
- }
-}
-
-/**
- * ppc440spe_adma_pq_zero_sum_set_dest - set destination address into descriptor
- * for the PQ_ZERO_SUM operation
- */
-static void ppc440spe_adma_pqzero_sum_set_dest(
- struct ppc440spe_adma_desc_slot *sw_desc,
- dma_addr_t paddr, dma_addr_t qaddr)
-{
- struct ppc440spe_adma_desc_slot *iter, *end;
- struct ppc440spe_adma_chan *chan;
- dma_addr_t addr = 0;
- int idx;
-
- chan = to_ppc440spe_adma_chan(sw_desc->async_tx.chan);
-
- /* walk through the WXOR source list and set P/Q-destinations
- * for each slot
- */
- idx = (paddr && qaddr) ? 2 : 1;
- /* set end */
- list_for_each_entry_reverse(end, &sw_desc->group_list,
- chain_node) {
- if (!(--idx))
- break;
- }
- /* set start */
- idx = (paddr && qaddr) ? 2 : 1;
- iter = ppc440spe_get_group_entry(sw_desc, idx);
-
- if (paddr && qaddr) {
- /* two destinations */
- list_for_each_entry_from(iter, &sw_desc->group_list,
- chain_node) {
- if (unlikely(iter == end))
- break;
- ppc440spe_desc_set_dest_addr(iter, chan,
- DMA_CUED_XOR_BASE, paddr, 0);
- ppc440spe_desc_set_dest_addr(iter, chan,
- DMA_CUED_XOR_BASE, qaddr, 1);
- }
- } else {
- /* one destination */
- addr = paddr ? paddr : qaddr;
- list_for_each_entry_from(iter, &sw_desc->group_list,
- chain_node) {
- if (unlikely(iter == end))
- break;
- ppc440spe_desc_set_dest_addr(iter, chan,
- DMA_CUED_XOR_BASE, addr, 0);
- }
- }
-
- /* The remaining descriptors are DATACHECK. These have no need in
- * destination. Actually, these destinations are used there
- * as sources for check operation. So, set addr as source.
- */
- ppc440spe_desc_set_src_addr(end, chan, 0, 0, addr ? addr : paddr);
-
- if (!addr) {
- end = list_entry(end->chain_node.next,
- struct ppc440spe_adma_desc_slot, chain_node);
- ppc440spe_desc_set_src_addr(end, chan, 0, 0, qaddr);
- }
-}
-
-/**
- * ppc440spe_desc_set_xor_src_cnt - set source count into descriptor
- */
-static inline void ppc440spe_desc_set_xor_src_cnt(
- struct ppc440spe_adma_desc_slot *desc,
- int src_cnt)
-{
- struct xor_cb *hw_desc = desc->hw_desc;
-
- hw_desc->cbc &= ~XOR_CDCR_OAC_MSK;
- hw_desc->cbc |= src_cnt;
-}
-
-/**
- * ppc440spe_adma_pq_set_src - set source address into descriptor
- */
-static void ppc440spe_adma_pq_set_src(struct ppc440spe_adma_desc_slot *sw_desc,
- dma_addr_t addr, int index)
-{
- struct ppc440spe_adma_chan *chan;
- dma_addr_t haddr = 0;
- struct ppc440spe_adma_desc_slot *iter = NULL;
-
- chan = to_ppc440spe_adma_chan(sw_desc->async_tx.chan);
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- /* DMA0,1 may do: WXOR, RXOR, RXOR+WXORs chain
- */
- if (test_bit(PPC440SPE_DESC_RXOR, &sw_desc->flags)) {
- /* RXOR-only or RXOR/WXOR operation */
- int iskip = test_bit(PPC440SPE_DESC_RXOR12,
- &sw_desc->flags) ? 2 : 3;
-
- if (index == 0) {
- /* 1st slot (RXOR) */
- /* setup sources region (R1-2-3, R1-2-4,
- * or R1-2-5)
- */
- if (test_bit(PPC440SPE_DESC_RXOR12,
- &sw_desc->flags))
- haddr = DMA_RXOR12 <<
- DMA_CUED_REGION_OFF;
- else if (test_bit(PPC440SPE_DESC_RXOR123,
- &sw_desc->flags))
- haddr = DMA_RXOR123 <<
- DMA_CUED_REGION_OFF;
- else if (test_bit(PPC440SPE_DESC_RXOR124,
- &sw_desc->flags))
- haddr = DMA_RXOR124 <<
- DMA_CUED_REGION_OFF;
- else if (test_bit(PPC440SPE_DESC_RXOR125,
- &sw_desc->flags))
- haddr = DMA_RXOR125 <<
- DMA_CUED_REGION_OFF;
- else
- BUG();
- haddr |= DMA_CUED_XOR_BASE;
- iter = ppc440spe_get_group_entry(sw_desc, 0);
- } else if (index < iskip) {
- /* 1st slot (RXOR)
- * shall actually set source address only once
- * instead of first <iskip>
- */
- iter = NULL;
- } else {
- /* 2nd/3d and next slots (WXOR);
- * skip first slot with RXOR
- */
- haddr = DMA_CUED_XOR_HB;
- iter = ppc440spe_get_group_entry(sw_desc,
- index - iskip + sw_desc->dst_cnt);
- }
- } else {
- int znum = 0;
-
- /* WXOR-only operation; skip first slots with
- * zeroing destinations
- */
- if (test_bit(PPC440SPE_ZERO_P, &sw_desc->flags))
- znum++;
- if (test_bit(PPC440SPE_ZERO_Q, &sw_desc->flags))
- znum++;
-
- haddr = DMA_CUED_XOR_HB;
- iter = ppc440spe_get_group_entry(sw_desc,
- index + znum);
- }
-
- if (likely(iter)) {
- ppc440spe_desc_set_src_addr(iter, chan, 0, haddr, addr);
-
- if (!index &&
- test_bit(PPC440SPE_DESC_RXOR, &sw_desc->flags) &&
- sw_desc->dst_cnt == 2) {
- /* if we have two destinations for RXOR, then
- * setup source in the second descr too
- */
- iter = ppc440spe_get_group_entry(sw_desc, 1);
- ppc440spe_desc_set_src_addr(iter, chan, 0,
- haddr, addr);
- }
- }
- break;
-
- case PPC440SPE_XOR_ID:
- /* DMA2 may do Biskup */
- iter = sw_desc->group_head;
- if (iter->dst_cnt == 2) {
- /* both P & Q calculations required; set P src here */
- ppc440spe_adma_dma2rxor_set_src(iter, index, addr);
-
- /* this is for Q */
- iter = ppc440spe_get_group_entry(sw_desc,
- sw_desc->descs_per_op);
- }
- ppc440spe_adma_dma2rxor_set_src(iter, index, addr);
- break;
- }
-}
-
-/**
- * ppc440spe_adma_memcpy_xor_set_src - set source address into descriptor
- */
-static void ppc440spe_adma_memcpy_xor_set_src(
- struct ppc440spe_adma_desc_slot *sw_desc,
- dma_addr_t addr, int index)
-{
- struct ppc440spe_adma_chan *chan;
-
- chan = to_ppc440spe_adma_chan(sw_desc->async_tx.chan);
- sw_desc = sw_desc->group_head;
-
- if (likely(sw_desc))
- ppc440spe_desc_set_src_addr(sw_desc, chan, index, 0, addr);
-}
-
-/**
- * ppc440spe_adma_dma2rxor_inc_addr -
- */
-static void ppc440spe_adma_dma2rxor_inc_addr(
- struct ppc440spe_adma_desc_slot *desc,
- struct ppc440spe_rxor *cursor, int index, int src_cnt)
-{
- cursor->addr_count++;
- if (index == src_cnt - 1) {
- ppc440spe_desc_set_xor_src_cnt(desc, cursor->addr_count);
- } else if (cursor->addr_count == XOR_MAX_OPS) {
- ppc440spe_desc_set_xor_src_cnt(desc, cursor->addr_count);
- cursor->addr_count = 0;
- cursor->desc_count++;
- }
-}
-
-/**
- * ppc440spe_adma_dma2rxor_prep_src - setup RXOR types in DMA2 CDB
- */
-static int ppc440spe_adma_dma2rxor_prep_src(
- struct ppc440spe_adma_desc_slot *hdesc,
- struct ppc440spe_rxor *cursor, int index,
- int src_cnt, u32 addr)
-{
- int rval = 0;
- u32 sign;
- struct ppc440spe_adma_desc_slot *desc = hdesc;
- int i;
-
- for (i = 0; i < cursor->desc_count; i++) {
- desc = list_entry(hdesc->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- }
-
- switch (cursor->state) {
- case 0:
- if (addr == cursor->addrl + cursor->len) {
- /* direct RXOR */
- cursor->state = 1;
- cursor->xor_count++;
- if (index == src_cnt-1) {
- ppc440spe_rxor_set_region(desc,
- cursor->addr_count,
- DMA_RXOR12 << DMA_CUED_REGION_OFF);
- ppc440spe_adma_dma2rxor_inc_addr(
- desc, cursor, index, src_cnt);
- }
- } else if (cursor->addrl == addr + cursor->len) {
- /* reverse RXOR */
- cursor->state = 1;
- cursor->xor_count++;
- set_bit(cursor->addr_count, &desc->reverse_flags[0]);
- if (index == src_cnt-1) {
- ppc440spe_rxor_set_region(desc,
- cursor->addr_count,
- DMA_RXOR12 << DMA_CUED_REGION_OFF);
- ppc440spe_adma_dma2rxor_inc_addr(
- desc, cursor, index, src_cnt);
- }
- } else {
- printk(KERN_ERR "Cannot build "
- "DMA2 RXOR command block.\n");
- BUG();
- }
- break;
- case 1:
- sign = test_bit(cursor->addr_count,
- desc->reverse_flags)
- ? -1 : 1;
- if (index == src_cnt-2 || (sign == -1
- && addr != cursor->addrl - 2*cursor->len)) {
- cursor->state = 0;
- cursor->xor_count = 1;
- cursor->addrl = addr;
- ppc440spe_rxor_set_region(desc,
- cursor->addr_count,
- DMA_RXOR12 << DMA_CUED_REGION_OFF);
- ppc440spe_adma_dma2rxor_inc_addr(
- desc, cursor, index, src_cnt);
- } else if (addr == cursor->addrl + 2*sign*cursor->len) {
- cursor->state = 2;
- cursor->xor_count = 0;
- ppc440spe_rxor_set_region(desc,
- cursor->addr_count,
- DMA_RXOR123 << DMA_CUED_REGION_OFF);
- if (index == src_cnt-1) {
- ppc440spe_adma_dma2rxor_inc_addr(
- desc, cursor, index, src_cnt);
- }
- } else if (addr == cursor->addrl + 3*cursor->len) {
- cursor->state = 2;
- cursor->xor_count = 0;
- ppc440spe_rxor_set_region(desc,
- cursor->addr_count,
- DMA_RXOR124 << DMA_CUED_REGION_OFF);
- if (index == src_cnt-1) {
- ppc440spe_adma_dma2rxor_inc_addr(
- desc, cursor, index, src_cnt);
- }
- } else if (addr == cursor->addrl + 4*cursor->len) {
- cursor->state = 2;
- cursor->xor_count = 0;
- ppc440spe_rxor_set_region(desc,
- cursor->addr_count,
- DMA_RXOR125 << DMA_CUED_REGION_OFF);
- if (index == src_cnt-1) {
- ppc440spe_adma_dma2rxor_inc_addr(
- desc, cursor, index, src_cnt);
- }
- } else {
- cursor->state = 0;
- cursor->xor_count = 1;
- cursor->addrl = addr;
- ppc440spe_rxor_set_region(desc,
- cursor->addr_count,
- DMA_RXOR12 << DMA_CUED_REGION_OFF);
- ppc440spe_adma_dma2rxor_inc_addr(
- desc, cursor, index, src_cnt);
- }
- break;
- case 2:
- cursor->state = 0;
- cursor->addrl = addr;
- cursor->xor_count++;
- if (index) {
- ppc440spe_adma_dma2rxor_inc_addr(
- desc, cursor, index, src_cnt);
- }
- break;
- }
-
- return rval;
-}
-
-/**
- * ppc440spe_adma_dma2rxor_set_src - set RXOR source address; it's assumed that
- * ppc440spe_adma_dma2rxor_prep_src() has already done prior this call
- */
-static void ppc440spe_adma_dma2rxor_set_src(
- struct ppc440spe_adma_desc_slot *desc,
- int index, dma_addr_t addr)
-{
- struct xor_cb *xcb = desc->hw_desc;
- int k = 0, op = 0, lop = 0;
-
- /* get the RXOR operand which corresponds to index addr */
- while (op <= index) {
- lop = op;
- if (k == XOR_MAX_OPS) {
- k = 0;
- desc = list_entry(desc->chain_node.next,
- struct ppc440spe_adma_desc_slot, chain_node);
- xcb = desc->hw_desc;
-
- }
- if ((xcb->ops[k++].h & (DMA_RXOR12 << DMA_CUED_REGION_OFF)) ==
- (DMA_RXOR12 << DMA_CUED_REGION_OFF))
- op += 2;
- else
- op += 3;
- }
-
- BUG_ON(k < 1);
-
- if (test_bit(k-1, desc->reverse_flags)) {
- /* reverse operand order; put last op in RXOR group */
- if (index == op - 1)
- ppc440spe_rxor_set_src(desc, k - 1, addr);
- } else {
- /* direct operand order; put first op in RXOR group */
- if (index == lop)
- ppc440spe_rxor_set_src(desc, k - 1, addr);
- }
-}
-
-/**
- * ppc440spe_adma_dma2rxor_set_mult - set RXOR multipliers; it's assumed that
- * ppc440spe_adma_dma2rxor_prep_src() has already done prior this call
- */
-static void ppc440spe_adma_dma2rxor_set_mult(
- struct ppc440spe_adma_desc_slot *desc,
- int index, u8 mult)
-{
- struct xor_cb *xcb = desc->hw_desc;
- int k = 0, op = 0, lop = 0;
-
- /* get the RXOR operand which corresponds to index mult */
- while (op <= index) {
- lop = op;
- if (k == XOR_MAX_OPS) {
- k = 0;
- desc = list_entry(desc->chain_node.next,
- struct ppc440spe_adma_desc_slot,
- chain_node);
- xcb = desc->hw_desc;
-
- }
- if ((xcb->ops[k++].h & (DMA_RXOR12 << DMA_CUED_REGION_OFF)) ==
- (DMA_RXOR12 << DMA_CUED_REGION_OFF))
- op += 2;
- else
- op += 3;
- }
-
- BUG_ON(k < 1);
- if (test_bit(k-1, desc->reverse_flags)) {
- /* reverse order */
- ppc440spe_rxor_set_mult(desc, k - 1, op - index - 1, mult);
- } else {
- /* direct order */
- ppc440spe_rxor_set_mult(desc, k - 1, index - lop, mult);
- }
-}
-
-/**
- * ppc440spe_init_rxor_cursor -
- */
-static void ppc440spe_init_rxor_cursor(struct ppc440spe_rxor *cursor)
-{
- memset(cursor, 0, sizeof(struct ppc440spe_rxor));
- cursor->state = 2;
-}
-
-/**
- * ppc440spe_adma_pq_set_src_mult - set multiplication coefficient into
- * descriptor for the PQXOR operation
- */
-static void ppc440spe_adma_pq_set_src_mult(
- struct ppc440spe_adma_desc_slot *sw_desc,
- unsigned char mult, int index, int dst_pos)
-{
- struct ppc440spe_adma_chan *chan;
- u32 mult_idx, mult_dst;
- struct ppc440spe_adma_desc_slot *iter = NULL, *iter1 = NULL;
-
- chan = to_ppc440spe_adma_chan(sw_desc->async_tx.chan);
-
- switch (chan->device->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- if (test_bit(PPC440SPE_DESC_RXOR, &sw_desc->flags)) {
- int region = test_bit(PPC440SPE_DESC_RXOR12,
- &sw_desc->flags) ? 2 : 3;
-
- if (index < region) {
- /* RXOR multipliers */
- iter = ppc440spe_get_group_entry(sw_desc,
- sw_desc->dst_cnt - 1);
- if (sw_desc->dst_cnt == 2)
- iter1 = ppc440spe_get_group_entry(
- sw_desc, 0);
-
- mult_idx = DMA_CUED_MULT1_OFF + (index << 3);
- mult_dst = DMA_CDB_SG_SRC;
- } else {
- /* WXOR multiplier */
- iter = ppc440spe_get_group_entry(sw_desc,
- index - region +
- sw_desc->dst_cnt);
- mult_idx = DMA_CUED_MULT1_OFF;
- mult_dst = dst_pos ? DMA_CDB_SG_DST2 :
- DMA_CDB_SG_DST1;
- }
- } else {
- int znum = 0;
-
- /* WXOR-only;
- * skip first slots with destinations (if ZERO_DST has
- * place)
- */
- if (test_bit(PPC440SPE_ZERO_P, &sw_desc->flags))
- znum++;
- if (test_bit(PPC440SPE_ZERO_Q, &sw_desc->flags))
- znum++;
-
- iter = ppc440spe_get_group_entry(sw_desc, index + znum);
- mult_idx = DMA_CUED_MULT1_OFF;
- mult_dst = dst_pos ? DMA_CDB_SG_DST2 : DMA_CDB_SG_DST1;
- }
-
- if (likely(iter)) {
- ppc440spe_desc_set_src_mult(iter, chan,
- mult_idx, mult_dst, mult);
-
- if (unlikely(iter1)) {
- /* if we have two destinations for RXOR, then
- * we've just set Q mult. Set-up P now.
- */
- ppc440spe_desc_set_src_mult(iter1, chan,
- mult_idx, mult_dst, 1);
- }
-
- }
- break;
-
- case PPC440SPE_XOR_ID:
- iter = sw_desc->group_head;
- if (sw_desc->dst_cnt == 2) {
- /* both P & Q calculations required; set P mult here */
- ppc440spe_adma_dma2rxor_set_mult(iter, index, 1);
-
- /* and then set Q mult */
- iter = ppc440spe_get_group_entry(sw_desc,
- sw_desc->descs_per_op);
- }
- ppc440spe_adma_dma2rxor_set_mult(iter, index, mult);
- break;
- }
-}
-
-/**
- * ppc440spe_adma_free_chan_resources - free the resources allocated
+ * ppc4xx_adma_free_chan_resources - free the resources allocated
*/
-static void ppc440spe_adma_free_chan_resources(struct dma_chan *chan)
+static void ppc4xx_adma_free_chan_resources(struct dma_chan *chan)
{
- struct ppc440spe_adma_chan *ppc440spe_chan;
- struct ppc440spe_adma_desc_slot *iter, *_iter;
+ struct ppc4xx_adma_chan *ppc4xx_chan;
+ struct ppc4xx_adma_desc_slot *iter, *_iter;
int in_use_descs = 0;
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
- ppc440spe_adma_slot_cleanup(ppc440spe_chan);
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
+ ppc4xx_adma_slot_cleanup(ppc4xx_chan);
- spin_lock_bh(&ppc440spe_chan->lock);
- list_for_each_entry_safe(iter, _iter, &ppc440spe_chan->chain,
+ spin_lock_bh(&ppc4xx_chan->lock);
+ list_for_each_entry_safe(iter, _iter, &ppc4xx_chan->chain,
chain_node) {
in_use_descs++;
list_del(&iter->chain_node);
}
list_for_each_entry_safe_reverse(iter, _iter,
- &ppc440spe_chan->all_slots, slot_node) {
+ &ppc4xx_chan->all_slots, slot_node) {
list_del(&iter->slot_node);
kfree(iter);
- ppc440spe_chan->slots_allocated--;
+ ppc4xx_chan->slots_allocated--;
}
- ppc440spe_chan->last_used = NULL;
+ ppc4xx_chan->last_used = NULL;
- dev_dbg(ppc440spe_chan->device->common.dev,
- "ppc440spe adma%d %s slots_allocated %d\n",
- ppc440spe_chan->device->id,
- __func__, ppc440spe_chan->slots_allocated);
- spin_unlock_bh(&ppc440spe_chan->lock);
+ dev_dbg(ppc4xx_chan->device->common.dev,
+ "ppc4xx adma%d %s slots_allocated %d\n",
+ ppc4xx_chan->device->id,
+ __func__, ppc4xx_chan->slots_allocated);
+ spin_unlock_bh(&ppc4xx_chan->lock);
/* one is ok since we left it on there on purpose */
if (in_use_descs > 1)
@@ -3935,22 +856,22 @@ static void ppc440spe_adma_free_chan_resources(struct dma_chan *chan)
}
/**
- * ppc440spe_adma_tx_status - poll the status of an ADMA transaction
+ * ppc4xx_adma_tx_status - poll the status of an ADMA transaction
* @chan: ADMA channel handle
* @cookie: ADMA transaction identifier
* @txstate: a holder for the current state of the channel
*/
-static enum dma_status ppc440spe_adma_tx_status(struct dma_chan *chan,
+static enum dma_status ppc4xx_adma_tx_status(struct dma_chan *chan,
dma_cookie_t cookie, struct dma_tx_state *txstate)
{
- struct ppc440spe_adma_chan *ppc440spe_chan;
+ struct ppc4xx_adma_chan *ppc4xx_chan;
dma_cookie_t last_used;
dma_cookie_t last_complete;
enum dma_status ret;
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
last_used = chan->cookie;
- last_complete = ppc440spe_chan->completed_cookie;
+ last_complete = ppc4xx_chan->completed_cookie;
dma_set_tx_state(txstate, last_complete, last_used, 0);
@@ -3958,10 +879,10 @@ static enum dma_status ppc440spe_adma_tx_status(struct dma_chan *chan,
if (ret == DMA_SUCCESS)
return ret;
- ppc440spe_adma_slot_cleanup(ppc440spe_chan);
+ ppc4xx_adma_slot_cleanup(ppc4xx_chan);
last_used = chan->cookie;
- last_complete = ppc440spe_chan->completed_cookie;
+ last_complete = ppc4xx_chan->completed_cookie;
dma_set_tx_state(txstate, last_complete, last_used, 0);
@@ -3969,86 +890,78 @@ static enum dma_status ppc440spe_adma_tx_status(struct dma_chan *chan,
}
/**
- * ppc440spe_adma_eot_handler - end of transfer interrupt handler
+ * ppc4xx_adma_eot_handler - end of transfer interrupt handler
*/
-static irqreturn_t ppc440spe_adma_eot_handler(int irq, void *data)
+static irqreturn_t ppc4xx_adma_eot_handler(int irq, void *data)
{
- struct ppc440spe_adma_chan *chan = data;
+ struct ppc4xx_adma_chan *chan = data;
dev_dbg(chan->device->common.dev,
- "ppc440spe adma%d: %s\n", chan->device->id, __func__);
+ "ppc4xx adma%d: %s\n", chan->device->id, __func__);
tasklet_schedule(&chan->irq_tasklet);
- ppc440spe_adma_device_clear_eot_status(chan);
+ ppc4xx_adma_device_clear_eot_status(chan);
return IRQ_HANDLED;
}
/**
- * ppc440spe_adma_err_handler - DMA error interrupt handler;
+ * ppc4xx_adma_err_handler - DMA error interrupt handler;
* do the same things as a eot handler
*/
-static irqreturn_t ppc440spe_adma_err_handler(int irq, void *data)
+static irqreturn_t ppc4xx_adma_err_handler(int irq, void *data)
{
- struct ppc440spe_adma_chan *chan = data;
+ struct ppc4xx_adma_chan *chan = data;
dev_dbg(chan->device->common.dev,
- "ppc440spe adma%d: %s\n", chan->device->id, __func__);
+ "ppc4xx adma%d: %s\n", chan->device->id, __func__);
tasklet_schedule(&chan->irq_tasklet);
- ppc440spe_adma_device_clear_eot_status(chan);
+ ppc4xx_adma_device_clear_eot_status(chan);
return IRQ_HANDLED;
}
/**
- * ppc440spe_test_callback - called when test operation has been done
+ * ppc4xx_adma_issue_pending - flush all pending descriptors to h/w
*/
-static void ppc440spe_test_callback(void *unused)
+static void ppc4xx_adma_issue_pending(struct dma_chan *chan)
{
- complete(&ppc440spe_r6_test_comp);
-}
+ struct ppc4xx_adma_chan *ppc4xx_chan;
-/**
- * ppc440spe_adma_issue_pending - flush all pending descriptors to h/w
- */
-static void ppc440spe_adma_issue_pending(struct dma_chan *chan)
-{
- struct ppc440spe_adma_chan *ppc440spe_chan;
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
+ dev_dbg(ppc4xx_chan->device->common.dev,
+ "ppc4xx adma%d: %s %d \n", ppc4xx_chan->device->id,
+ __func__, ppc4xx_chan->pending);
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
- dev_dbg(ppc440spe_chan->device->common.dev,
- "ppc440spe adma%d: %s %d \n", ppc440spe_chan->device->id,
- __func__, ppc440spe_chan->pending);
-
- if (ppc440spe_chan->pending) {
- ppc440spe_chan->pending = 0;
- ppc440spe_chan_append(ppc440spe_chan);
+ if (ppc4xx_chan->pending) {
+ ppc4xx_chan->pending = 0;
+ ppc4xx_chan_append(ppc4xx_chan);
}
}
/**
- * ppc440spe_chan_start_null_xor - initiate the first XOR operation (DMA engines
+ * ppc4xx_chan_start_null_xor - initiate the first XOR operation (DMA engines
* use FIFOs (as opposite to chains used in XOR) so this is a XOR
* specific operation)
*/
-static void ppc440spe_chan_start_null_xor(struct ppc440spe_adma_chan *chan)
+static void ppc4xx_chan_start_null_xor(struct ppc4xx_adma_chan *chan)
{
- struct ppc440spe_adma_desc_slot *sw_desc, *group_start;
+ struct ppc4xx_adma_desc_slot *sw_desc, *group_start;
dma_cookie_t cookie;
int slot_cnt, slots_per_op;
dev_dbg(chan->device->common.dev,
- "ppc440spe adma%d: %s\n", chan->device->id, __func__);
+ "ppc4xx adma%d: %s\n", chan->device->id, __func__);
spin_lock_bh(&chan->lock);
- slot_cnt = ppc440spe_chan_xor_slot_count(0, 2, &slots_per_op);
- sw_desc = ppc440spe_adma_alloc_slots(chan, slot_cnt, slots_per_op);
+ slot_cnt = ppc4xx_chan_xor_slot_count(0, 2, &slots_per_op);
+ sw_desc = ppc4xx_adma_alloc_slots(chan, slot_cnt, slots_per_op);
if (sw_desc) {
group_start = sw_desc->group_head;
list_splice_init(&sw_desc->group_list, &chan->chain);
async_tx_ack(&sw_desc->async_tx);
- ppc440spe_desc_init_null_xor(group_start);
+ ppc4xx_desc_init_null_xor(group_start);
cookie = chan->common.cookie;
cookie++;
@@ -4062,384 +975,98 @@ static void ppc440spe_chan_start_null_xor(struct ppc440spe_adma_chan *chan)
chan->common.cookie = sw_desc->async_tx.cookie = cookie;
/* channel should not be busy */
- BUG_ON(ppc440spe_chan_is_busy(chan));
+ BUG_ON(ppc4xx_chan_is_busy(chan));
/* set the descriptor address */
- ppc440spe_chan_set_first_xor_descriptor(chan, sw_desc);
+ ppc4xx_chan_set_first_xor_descriptor(chan, sw_desc);
/* run the descriptor */
- ppc440spe_chan_run(chan);
+ ppc4xx_chan_run(chan);
} else
- printk(KERN_ERR "ppc440spe adma%d"
+ printk(KERN_ERR "ppc4xx adma%d"
" failed to allocate null descriptor\n",
chan->device->id);
spin_unlock_bh(&chan->lock);
}
/**
- * ppc440spe_test_raid6 - test are RAID-6 capabilities enabled successfully.
+ * ppc4xx_test_raid6 - test are RAID-6 capabilities enabled successfully.
* For this we just perform one WXOR operation with the same source
* and destination addresses, the GF-multiplier is 1; so if RAID-6
* capabilities are enabled then we'll get src/dst filled with zero.
*/
-static int ppc440spe_test_raid6(struct ppc440spe_adma_chan *chan)
+static int ppc4xx_test_raid6(struct ppc4xx_adma_chan *chan)
{
- struct ppc440spe_adma_desc_slot *sw_desc, *iter;
- struct page *pg;
- char *a;
- dma_addr_t dma_addr, addrs[2];
- unsigned long op = 0;
- int rval = 0;
-
- set_bit(PPC440SPE_DESC_WXOR, &op);
-
- pg = alloc_page(GFP_KERNEL);
- if (!pg)
- return -ENOMEM;
-
- spin_lock_bh(&chan->lock);
- sw_desc = ppc440spe_adma_alloc_slots(chan, 1, 1);
- if (sw_desc) {
- /* 1 src, 1 dsr, int_ena, WXOR */
- ppc440spe_desc_init_dma01pq(sw_desc, 1, 1, 1, op);
- list_for_each_entry(iter, &sw_desc->group_list, chain_node) {
- ppc440spe_desc_set_byte_count(iter, chan, PAGE_SIZE);
- iter->unmap_len = PAGE_SIZE;
- }
- } else {
- rval = -EFAULT;
- spin_unlock_bh(&chan->lock);
- goto exit;
- }
- spin_unlock_bh(&chan->lock);
-
- /* Fill the test page with ones */
- memset(page_address(pg), 0xFF, PAGE_SIZE);
- dma_addr = dma_map_page(chan->device->dev, pg, 0,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
-
- /* Setup addresses */
- ppc440spe_adma_pq_set_src(sw_desc, dma_addr, 0);
- ppc440spe_adma_pq_set_src_mult(sw_desc, 1, 0, 0);
- addrs[0] = dma_addr;
- addrs[1] = 0;
- ppc440spe_adma_pq_set_dest(sw_desc, addrs, DMA_PREP_PQ_DISABLE_Q);
-
- async_tx_ack(&sw_desc->async_tx);
- sw_desc->async_tx.callback = ppc440spe_test_callback;
- sw_desc->async_tx.callback_param = NULL;
-
- init_completion(&ppc440spe_r6_test_comp);
-
- ppc440spe_adma_tx_submit(&sw_desc->async_tx);
- ppc440spe_adma_issue_pending(&chan->common);
-
- wait_for_completion(&ppc440spe_r6_test_comp);
-
- /* Now check if the test page is zeroed */
- a = page_address(pg);
- if ((*(u32 *)a) == 0 && memcmp(a, a+4, PAGE_SIZE-4) == 0) {
- /* page is zero - RAID-6 enabled */
- rval = 0;
- } else {
- /* RAID-6 was not enabled */
- rval = -EINVAL;
- }
-exit:
- __free_page(pg);
- return rval;
+ return ppc4xx_test_raid6(chan);
}
-static void ppc440spe_adma_init_capabilities(struct ppc440spe_adma_device *adev)
+static void ppc4xx_adma_init_capabilities(struct ppc4xx_adma_device *adev)
{
- switch (adev->id) {
- case PPC440SPE_DMA0_ID:
- case PPC440SPE_DMA1_ID:
- dma_cap_set(DMA_MEMCPY, adev->common.cap_mask);
- dma_cap_set(DMA_INTERRUPT, adev->common.cap_mask);
- dma_cap_set(DMA_MEMSET, adev->common.cap_mask);
- dma_cap_set(DMA_PQ, adev->common.cap_mask);
- dma_cap_set(DMA_PQ_VAL, adev->common.cap_mask);
- dma_cap_set(DMA_XOR_VAL, adev->common.cap_mask);
- break;
- case PPC440SPE_XOR_ID:
- dma_cap_set(DMA_XOR, adev->common.cap_mask);
- dma_cap_set(DMA_PQ, adev->common.cap_mask);
- dma_cap_set(DMA_INTERRUPT, adev->common.cap_mask);
- adev->common.cap_mask = adev->common.cap_mask;
- break;
- }
-
/* Set base routines */
adev->common.device_alloc_chan_resources =
- ppc440spe_adma_alloc_chan_resources;
+ ppc4xx_adma_alloc_chan_resources;
adev->common.device_free_chan_resources =
- ppc440spe_adma_free_chan_resources;
- adev->common.device_tx_status = ppc440spe_adma_tx_status;
- adev->common.device_issue_pending = ppc440spe_adma_issue_pending;
+ ppc4xx_adma_free_chan_resources;
+ adev->common.device_tx_status = ppc4xx_adma_tx_status;
+ adev->common.device_issue_pending = ppc4xx_adma_issue_pending;
/* Set prep routines based on capability */
if (dma_has_cap(DMA_MEMCPY, adev->common.cap_mask)) {
adev->common.device_prep_dma_memcpy =
- ppc440spe_adma_prep_dma_memcpy;
+ ppc4xx_adma_prep_dma_memcpy;
}
if (dma_has_cap(DMA_MEMSET, adev->common.cap_mask)) {
adev->common.device_prep_dma_memset =
- ppc440spe_adma_prep_dma_memset;
+ ppc4xx_adma_prep_dma_memset;
}
if (dma_has_cap(DMA_XOR, adev->common.cap_mask)) {
adev->common.max_xor = XOR_MAX_OPS;
adev->common.device_prep_dma_xor =
- ppc440spe_adma_prep_dma_xor;
+ ppc4xx_adma_prep_dma_xor;
}
if (dma_has_cap(DMA_PQ, adev->common.cap_mask)) {
- switch (adev->id) {
- case PPC440SPE_DMA0_ID:
- dma_set_maxpq(&adev->common,
- DMA0_FIFO_SIZE / sizeof(struct dma_cdb), 0);
- break;
- case PPC440SPE_DMA1_ID:
- dma_set_maxpq(&adev->common,
- DMA1_FIFO_SIZE / sizeof(struct dma_cdb), 0);
- 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;
+ ppc4xx_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(struct dma_cdb);
- break;
- case PPC440SPE_DMA1_ID:
- adev->common.max_pq = DMA1_FIFO_SIZE /
- sizeof(struct dma_cdb);
- break;
- }
adev->common.device_prep_dma_pq_val =
- ppc440spe_adma_prep_dma_pqzero_sum;
+ ppc4xx_adma_prep_dma_pqzero_sum;
}
if (dma_has_cap(DMA_XOR_VAL, adev->common.cap_mask)) {
- switch (adev->id) {
- case PPC440SPE_DMA0_ID:
- adev->common.max_xor = DMA0_FIFO_SIZE /
- sizeof(struct dma_cdb);
- break;
- case PPC440SPE_DMA1_ID:
- adev->common.max_xor = DMA1_FIFO_SIZE /
- sizeof(struct dma_cdb);
- break;
- }
adev->common.device_prep_dma_xor_val =
- ppc440spe_adma_prep_dma_xor_zero_sum;
+ ppc4xx_adma_prep_dma_xor_zero_sum;
}
if (dma_has_cap(DMA_INTERRUPT, adev->common.cap_mask)) {
adev->common.device_prep_dma_interrupt =
- ppc440spe_adma_prep_dma_interrupt;
+ ppc4xx_adma_prep_dma_interrupt;
}
- pr_info("%s: AMCC(R) PPC440SP(E) ADMA Engine: "
- "( %s%s%s%s%s%s%s)\n",
- dev_name(adev->dev),
- dma_has_cap(DMA_PQ, adev->common.cap_mask) ? "pq " : "",
- dma_has_cap(DMA_PQ_VAL, adev->common.cap_mask) ? "pq_val " : "",
- dma_has_cap(DMA_XOR, adev->common.cap_mask) ? "xor " : "",
- dma_has_cap(DMA_XOR_VAL, adev->common.cap_mask) ? "xor_val " : "",
- dma_has_cap(DMA_MEMCPY, adev->common.cap_mask) ? "memcpy " : "",
- dma_has_cap(DMA_MEMSET, adev->common.cap_mask) ? "memset " : "",
- dma_has_cap(DMA_INTERRUPT, adev->common.cap_mask) ? "intr " : "");
}
-
-static int ppc440spe_adma_setup_irqs(struct ppc440spe_adma_device *adev,
- struct ppc440spe_adma_chan *chan,
- int *initcode)
-{
- struct platform_device *ofdev;
- struct device_node *np;
- int ret;
-
- ofdev = container_of(adev->dev, struct platform_device, dev);
- np = ofdev->dev.of_node;
- if (adev->id != PPC440SPE_XOR_ID) {
- adev->err_irq = irq_of_parse_and_map(np, 1);
- if (adev->err_irq == NO_IRQ) {
- dev_warn(adev->dev, "no err irq resource?\n");
- *initcode = PPC_ADMA_INIT_IRQ2;
- adev->err_irq = -ENXIO;
- } else
- atomic_inc(&ppc440spe_adma_err_irq_ref);
- } else {
- adev->err_irq = -ENXIO;
- }
-
- adev->irq = irq_of_parse_and_map(np, 0);
- if (adev->irq == NO_IRQ) {
- dev_err(adev->dev, "no irq resource\n");
- *initcode = PPC_ADMA_INIT_IRQ1;
- ret = -ENXIO;
- goto err_irq_map;
- }
- dev_dbg(adev->dev, "irq %d, err irq %d\n",
- adev->irq, adev->err_irq);
-
- ret = request_irq(adev->irq, ppc440spe_adma_eot_handler,
- 0, dev_driver_string(adev->dev), chan);
- if (ret) {
- dev_err(adev->dev, "can't request irq %d\n",
- adev->irq);
- *initcode = PPC_ADMA_INIT_IRQ1;
- ret = -EIO;
- goto err_req1;
- }
-
- /* only DMA engines have a separate error IRQ
- * so it's Ok if err_irq < 0 in XOR engine case.
- */
- if (adev->err_irq > 0) {
- /* both DMA engines share common error IRQ */
- ret = request_irq(adev->err_irq,
- ppc440spe_adma_err_handler,
- IRQF_SHARED,
- dev_driver_string(adev->dev),
- chan);
- if (ret) {
- dev_err(adev->dev, "can't request irq %d\n",
- adev->err_irq);
- *initcode = PPC_ADMA_INIT_IRQ2;
- ret = -EIO;
- goto err_req2;
- }
- }
-
- if (adev->id == PPC440SPE_XOR_ID) {
- /* enable XOR engine interrupts */
- iowrite32be(XOR_IE_CBCIE_BIT | XOR_IE_ICBIE_BIT |
- XOR_IE_ICIE_BIT | XOR_IE_RPTIE_BIT,
- &adev->xor_reg->ier);
- } else {
- u32 mask, enable;
-
- np = of_find_compatible_node(NULL, NULL, "ibm,i2o-440spe");
- if (!np) {
- pr_err("%s: can't find I2O device tree node\n",
- __func__);
- ret = -ENODEV;
- goto err_req2;
- }
- adev->i2o_reg = of_iomap(np, 0);
- if (!adev->i2o_reg) {
- pr_err("%s: failed to map I2O registers\n", __func__);
- of_node_put(np);
- ret = -EINVAL;
- goto err_req2;
- }
- of_node_put(np);
- /* Unmask 'CS FIFO Attention' interrupts and
- * enable generating interrupts on errors
- */
- enable = (adev->id == PPC440SPE_DMA0_ID) ?
- ~(I2O_IOPIM_P0SNE | I2O_IOPIM_P0EM) :
- ~(I2O_IOPIM_P1SNE | I2O_IOPIM_P1EM);
- mask = ioread32(&adev->i2o_reg->iopim) & enable;
- iowrite32(mask, &adev->i2o_reg->iopim);
- }
- return 0;
-
-err_req2:
- free_irq(adev->irq, chan);
-err_req1:
- irq_dispose_mapping(adev->irq);
-err_irq_map:
- if (adev->err_irq > 0) {
- if (atomic_dec_and_test(&ppc440spe_adma_err_irq_ref))
- irq_dispose_mapping(adev->err_irq);
- }
- return ret;
-}
-
-static void ppc440spe_adma_release_irqs(struct ppc440spe_adma_device *adev,
- struct ppc440spe_adma_chan *chan)
-{
- u32 mask, disable;
-
- if (adev->id == PPC440SPE_XOR_ID) {
- /* disable XOR engine interrupts */
- mask = ioread32be(&adev->xor_reg->ier);
- mask &= ~(XOR_IE_CBCIE_BIT | XOR_IE_ICBIE_BIT |
- XOR_IE_ICIE_BIT | XOR_IE_RPTIE_BIT);
- iowrite32be(mask, &adev->xor_reg->ier);
- } else {
- /* disable DMAx engine interrupts */
- disable = (adev->id == PPC440SPE_DMA0_ID) ?
- (I2O_IOPIM_P0SNE | I2O_IOPIM_P0EM) :
- (I2O_IOPIM_P1SNE | I2O_IOPIM_P1EM);
- mask = ioread32(&adev->i2o_reg->iopim) | disable;
- iowrite32(mask, &adev->i2o_reg->iopim);
- }
- free_irq(adev->irq, chan);
- irq_dispose_mapping(adev->irq);
- if (adev->err_irq > 0) {
- free_irq(adev->err_irq, chan);
- if (atomic_dec_and_test(&ppc440spe_adma_err_irq_ref)) {
- irq_dispose_mapping(adev->err_irq);
- iounmap(adev->i2o_reg);
- }
- }
-}
-
/**
- * ppc440spe_adma_probe - probe the asynch device
+ * ppc4xx_adma_probe - probe the asynch device
*/
-static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev,
+static int __devinit ppc4xx_adma_probe(struct platform_device *ofdev,
const struct of_device_id *match)
{
struct device_node *np = ofdev->dev.of_node;
struct resource res;
- struct ppc440spe_adma_device *adev;
- struct ppc440spe_adma_chan *chan;
+ struct ppc4xx_adma_device *adev;
+ struct ppc4xx_adma_chan *chan;
struct ppc_dma_chan_ref *ref, *_ref;
int ret = 0, initcode = PPC_ADMA_INIT_OK;
- const u32 *idx;
- int len;
void *regs;
u32 id, pool_size;
- if (of_device_is_compatible(np, "amcc,xor-accelerator")) {
- id = PPC440SPE_XOR_ID;
- /* As far as the XOR engine is concerned, it does not
- * use FIFOs but uses linked list. So there is no dependency
- * between pool size to allocate and the engine configuration.
- */
- pool_size = PAGE_SIZE << 1;
- } else {
- /* it is DMA0 or DMA1 */
- idx = of_get_property(np, "cell-index", &len);
- if (!idx || (len != sizeof(u32))) {
- dev_err(&ofdev->dev, "Device node %s has missing "
- "or invalid cell-index property\n",
- np->full_name);
- return -EINVAL;
- }
- id = *idx;
- /* DMA0,1 engines use FIFO to maintain CDBs, so we
- * should allocate the pool accordingly to size of this
- * FIFO. Thus, the pool size depends on the FIFO depth:
- * how much CDBs pointers the FIFO may contain then so
- * much CDBs we should provide in the pool.
- * That is
- * CDB size = 32B;
- * CDBs number = (DMA0_FIFO_SIZE >> 3);
- * Pool size = CDBs number * CDB size =
- * = (DMA0_FIFO_SIZE >> 3) << 5 = DMA0_FIFO_SIZE << 2.
- */
- pool_size = (id == PPC440SPE_DMA0_ID) ?
- DMA0_FIFO_SIZE : DMA1_FIFO_SIZE;
- pool_size <<= 2;
- }
-
+ /*
+ * get device ID
+ */
+ adev->id = ppc4xx_adma_get_devid(ofdev, np);
+ /*
+ * Get DMA pool size
+ */
+ pool_size = ppc4xx_adma_get_pool_size(np, adev->id);
+ /*
+ * Get resource info
+ */
if (of_address_to_resource(np, 0, &res)) {
dev_err(&ofdev->dev, "failed to get memory resource\n");
initcode = PPC_ADMA_INIT_MEMRES;
@@ -4489,28 +1116,10 @@ static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev,
goto err_regs_alloc;
}
- if (adev->id == PPC440SPE_XOR_ID) {
- adev->xor_reg = regs;
- /* Reset XOR */
- iowrite32be(XOR_CRSR_XASR_BIT, &adev->xor_reg->crsr);
- iowrite32be(XOR_CRSR_64BA_BIT, &adev->xor_reg->crrr);
- } else {
- size_t fifo_size = (adev->id == PPC440SPE_DMA0_ID) ?
- DMA0_FIFO_SIZE : DMA1_FIFO_SIZE;
- adev->dma_reg = regs;
- /* DMAx_FIFO_SIZE is defined in bytes,
- * <fsiz> - is defined in number of CDB pointers (8byte).
- * DMA FIFO Length = CSlength + CPlength, where
- * CSlength = CPlength = (fsiz + 1) * 8.
- */
- iowrite32(DMA_FIFO_ENABLE | ((fifo_size >> 3) - 2),
- &adev->dma_reg->fsiz);
- /* Configure DMA engine */
- iowrite32(DMA_CFG_DXEPR_HP | DMA_CFG_DFMPP_HP | DMA_CFG_FALGN,
- &adev->dma_reg->cfg);
- /* Clear Status */
- iowrite32(~0, &adev->dma_reg->dsts);
- }
+ /*
+ * reset DMA and config FIFO
+ */
+ ppc4xx_adma_init_hw(adev, regs);
adev->dev = &ofdev->dev;
adev->common.dev = &ofdev->dev;
@@ -4532,46 +1141,32 @@ static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev,
chan->device = adev;
chan->common.device = &adev->common;
list_add_tail(&chan->common.device_node, &adev->common.channels);
- tasklet_init(&chan->irq_tasklet, ppc440spe_adma_tasklet,
+ tasklet_init(&chan->irq_tasklet, ppc4xx_adma_tasklet,
(unsigned long)chan);
- /* allocate and map helper pages for async validation or
- * async_mult/async_sum_product operations on DMA0/1.
+ /*
+ * Create helper pages
*/
- if (adev->id != PPC440SPE_XOR_ID) {
- chan->pdest_page = alloc_page(GFP_KERNEL);
- chan->qdest_page = alloc_page(GFP_KERNEL);
- if (!chan->pdest_page ||
- !chan->qdest_page) {
- if (chan->pdest_page)
- __free_page(chan->pdest_page);
- if (chan->qdest_page)
- __free_page(chan->qdest_page);
- ret = -ENOMEM;
+ if (ppc4xx_create_helper_pages(adev, ofdev, chan))
goto err_page_alloc;
- }
- chan->pdest = dma_map_page(&ofdev->dev, chan->pdest_page, 0,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- chan->qdest = dma_map_page(&ofdev->dev, chan->qdest_page, 0,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- }
ref = kmalloc(sizeof(*ref), GFP_KERNEL);
if (ref) {
ref->chan = &chan->common;
INIT_LIST_HEAD(&ref->node);
- list_add_tail(&ref->node, &ppc440spe_adma_chan_list);
+ list_add_tail(&ref->node, &ppc4xx_adma_chan_list);
} else {
dev_err(&ofdev->dev, "failed to allocate channel reference!\n");
ret = -ENOMEM;
goto err_ref_alloc;
}
- ret = ppc440spe_adma_setup_irqs(adev, chan, &initcode);
+ ret = ppc4xx_adma_setup_irqs(adev, chan, &initcode);
if (ret)
goto err_irq;
- ppc440spe_adma_init_capabilities(adev);
+ ppc4xx_adma_set_capabilities(adev);
+ ppc4xx_adma_init_capabilities(adev);
ret = dma_async_device_register(&adev->common);
if (ret) {
@@ -4583,30 +1178,20 @@ static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev,
goto out;
err_dev_reg:
- ppc440spe_adma_release_irqs(adev, chan);
+ ppc4xx_adma_release_irqs(adev, chan);
err_irq:
- list_for_each_entry_safe(ref, _ref, &ppc440spe_adma_chan_list, node) {
- if (chan == to_ppc440spe_adma_chan(ref->chan)) {
+ list_for_each_entry_safe(ref, _ref, &ppc4xx_adma_chan_list, node) {
+ if (chan == to_ppc4xx_adma_chan(ref->chan)) {
list_del(&ref->node);
kfree(ref);
}
}
err_ref_alloc:
- if (adev->id != PPC440SPE_XOR_ID) {
- dma_unmap_page(&ofdev->dev, chan->pdest,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- dma_unmap_page(&ofdev->dev, chan->qdest,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- __free_page(chan->pdest_page);
- __free_page(chan->qdest_page);
- }
+ ppc4xx_free_ref(adev, ofdev, chan);
err_page_alloc:
kfree(chan);
err_chan_alloc:
- if (adev->id == PPC440SPE_XOR_ID)
- iounmap(adev->xor_reg);
- else
- iounmap(adev->dma_reg);
+ ppc4xx_free_reg(adev);
err_regs_alloc:
dma_free_coherent(adev->dev, adev->pool_size,
adev->dma_desc_pool_virt,
@@ -4616,410 +1201,25 @@ err_dma_alloc:
err_adev_alloc:
release_mem_region(res.start, resource_size(&res));
out:
- if (id < PPC440SPE_ADMA_ENGINES_NUM)
- ppc440spe_adma_devices[id] = initcode;
+ if (id < PPC4XX_ADMA_ENGINES_NUM)
+ ppc4xx_adma_devices[id] = initcode;
return ret;
}
-/**
- * ppc440spe_adma_remove - remove the asynch device
- */
-static int __devexit ppc440spe_adma_remove(struct platform_device *ofdev)
-{
- struct ppc440spe_adma_device *adev = dev_get_drvdata(&ofdev->dev);
- struct device_node *np = ofdev->dev.of_node;
- struct resource res;
- struct dma_chan *chan, *_chan;
- struct ppc_dma_chan_ref *ref, *_ref;
- struct ppc440spe_adma_chan *ppc440spe_chan;
-
- dev_set_drvdata(&ofdev->dev, NULL);
- if (adev->id < PPC440SPE_ADMA_ENGINES_NUM)
- ppc440spe_adma_devices[adev->id] = -1;
-
- dma_async_device_unregister(&adev->common);
-
- list_for_each_entry_safe(chan, _chan, &adev->common.channels,
- device_node) {
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
- ppc440spe_adma_release_irqs(adev, ppc440spe_chan);
- tasklet_kill(&ppc440spe_chan->irq_tasklet);
- if (adev->id != PPC440SPE_XOR_ID) {
- dma_unmap_page(&ofdev->dev, ppc440spe_chan->pdest,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- dma_unmap_page(&ofdev->dev, ppc440spe_chan->qdest,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- __free_page(ppc440spe_chan->pdest_page);
- __free_page(ppc440spe_chan->qdest_page);
- }
- list_for_each_entry_safe(ref, _ref, &ppc440spe_adma_chan_list,
- node) {
- if (ppc440spe_chan ==
- to_ppc440spe_adma_chan(ref->chan)) {
- list_del(&ref->node);
- kfree(ref);
- }
- }
- list_del(&chan->device_node);
- kfree(ppc440spe_chan);
- }
-
- dma_free_coherent(adev->dev, adev->pool_size,
- adev->dma_desc_pool_virt, adev->dma_desc_pool);
- if (adev->id == PPC440SPE_XOR_ID)
- iounmap(adev->xor_reg);
- else
- iounmap(adev->dma_reg);
- of_address_to_resource(np, 0, &res);
- release_mem_region(res.start, resource_size(&res));
- kfree(adev);
- return 0;
-}
-
-/*
- * /sys driver interface to enable h/w RAID-6 capabilities
- * Files created in e.g. /sys/devices/plb.0/400100100.dma0/driver/
- * directory are "devices", "enable" and "poly".
- * "devices" shows available engines.
- * "enable" is used to enable RAID-6 capabilities or to check
- * whether these has been activated.
- * "poly" allows setting/checking used polynomial (for PPC440SPe only).
- */
-
-static ssize_t show_ppc440spe_devices(struct device_driver *dev, char *buf)
-{
- ssize_t size = 0;
- int i;
-
- for (i = 0; i < PPC440SPE_ADMA_ENGINES_NUM; i++) {
- if (ppc440spe_adma_devices[i] == -1)
- continue;
- size += snprintf(buf + size, PAGE_SIZE - size,
- "PPC440SP(E)-ADMA.%d: %s\n", i,
- ppc_adma_errors[ppc440spe_adma_devices[i]]);
- }
- return size;
-}
-
-static ssize_t show_ppc440spe_r6enable(struct device_driver *dev, char *buf)
-{
- return snprintf(buf, PAGE_SIZE,
- "PPC440SP(e) RAID-6 capabilities are %sABLED.\n",
- ppc440spe_r6_enabled ? "EN" : "DIS");
-}
-
-static ssize_t store_ppc440spe_r6enable(struct device_driver *dev,
- const char *buf, size_t count)
-{
- unsigned long val;
-
- if (!count || count > 11)
- return -EINVAL;
-
- if (!ppc440spe_r6_tchan)
- return -EFAULT;
-
- /* Write a key */
- sscanf(buf, "%lx", &val);
- dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_XORBA, val);
- isync();
-
- /* Verify whether it really works now */
- if (ppc440spe_test_raid6(ppc440spe_r6_tchan) == 0) {
- pr_info("PPC440SP(e) RAID-6 has been activated "
- "successfully\n");
- ppc440spe_r6_enabled = 1;
- } else {
- pr_info("PPC440SP(e) RAID-6 hasn't been activated!"
- " Error key ?\n");
- ppc440spe_r6_enabled = 0;
- }
- return count;
-}
-
-static ssize_t show_ppc440spe_r6poly(struct device_driver *dev, char *buf)
-{
- ssize_t size = 0;
- u32 reg;
-
-#ifdef CONFIG_440SP
- /* 440SP has fixed polynomial */
- reg = 0x4d;
-#else
- reg = dcr_read(ppc440spe_mq_dcr_host, DCRN_MQ0_CFBHL);
- reg >>= MQ0_CFBHL_POLY;
- reg &= 0xFF;
-#endif
-
- size = snprintf(buf, PAGE_SIZE, "PPC440SP(e) RAID-6 driver "
- "uses 0x1%02x polynomial.\n", reg);
- return size;
-}
-
-static ssize_t store_ppc440spe_r6poly(struct device_driver *dev,
- const char *buf, size_t count)
-{
- unsigned long reg, val;
-
-#ifdef CONFIG_440SP
- /* 440SP uses default 0x14D polynomial only */
- return -EINVAL;
-#endif
-
- if (!count || count > 6)
- return -EINVAL;
-
- /* e.g., 0x14D or 0x11D */
- sscanf(buf, "%lx", &val);
-
- if (val & ~0x1FF)
- return -EINVAL;
-
- val &= 0xFF;
- reg = dcr_read(ppc440spe_mq_dcr_host, DCRN_MQ0_CFBHL);
- reg &= ~(0xFF << MQ0_CFBHL_POLY);
- reg |= val << MQ0_CFBHL_POLY;
- dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_CFBHL, reg);
-
- return count;
-}
-
-static DRIVER_ATTR(devices, S_IRUGO, show_ppc440spe_devices, NULL);
-static DRIVER_ATTR(enable, S_IRUGO | S_IWUSR, show_ppc440spe_r6enable,
- store_ppc440spe_r6enable);
-static DRIVER_ATTR(poly, S_IRUGO | S_IWUSR, show_ppc440spe_r6poly,
- store_ppc440spe_r6poly);
-
-/*
- * Common initialisation for RAID engines; allocate memory for
- * DMAx FIFOs, perform configuration common for all DMA engines.
- * Further DMA engine specific configuration is done at probe time.
- */
-static int ppc440spe_configure_raid_devices(void)
-{
- struct device_node *np;
- struct resource i2o_res;
- struct i2o_regs __iomem *i2o_reg;
- dcr_host_t i2o_dcr_host;
- unsigned int dcr_base, dcr_len;
- int i, ret;
-
- np = of_find_compatible_node(NULL, NULL, "ibm,i2o-440spe");
- if (!np) {
- pr_err("%s: can't find I2O device tree node\n",
- __func__);
- return -ENODEV;
- }
-
- if (of_address_to_resource(np, 0, &i2o_res)) {
- of_node_put(np);
- return -EINVAL;
- }
-
- i2o_reg = of_iomap(np, 0);
- if (!i2o_reg) {
- pr_err("%s: failed to map I2O registers\n", __func__);
- of_node_put(np);
- return -EINVAL;
- }
-
- /* Get I2O DCRs base */
- dcr_base = dcr_resource_start(np, 0);
- dcr_len = dcr_resource_len(np, 0);
- if (!dcr_base && !dcr_len) {
- pr_err("%s: can't get DCR registers base/len!\n",
- np->full_name);
- of_node_put(np);
- iounmap(i2o_reg);
- return -ENODEV;
- }
-
- i2o_dcr_host = dcr_map(np, dcr_base, dcr_len);
- if (!DCR_MAP_OK(i2o_dcr_host)) {
- pr_err("%s: failed to map DCRs!\n", np->full_name);
- of_node_put(np);
- iounmap(i2o_reg);
- return -ENODEV;
- }
- of_node_put(np);
-
- /* Provide memory regions for DMA's FIFOs: I2O, DMA0 and DMA1 share
- * the base address of FIFO memory space.
- * Actually we need twice more physical memory than programmed in the
- * <fsiz> register (because there are two FIFOs for each DMA: CP and CS)
- */
- ppc440spe_dma_fifo_buf = kmalloc((DMA0_FIFO_SIZE + DMA1_FIFO_SIZE) << 1,
- GFP_KERNEL);
- if (!ppc440spe_dma_fifo_buf) {
- pr_err("%s: DMA FIFO buffer allocation failed.\n", __func__);
- iounmap(i2o_reg);
- dcr_unmap(i2o_dcr_host, dcr_len);
- return -ENOMEM;
- }
-
- /*
- * Configure h/w
- */
- /* Reset I2O/DMA */
- mtdcri(SDR0, DCRN_SDR0_SRST, DCRN_SDR0_SRST_I2ODMA);
- mtdcri(SDR0, DCRN_SDR0_SRST, 0);
-
- /* Setup the base address of mmaped registers */
- dcr_write(i2o_dcr_host, DCRN_I2O0_IBAH, (u32)(i2o_res.start >> 32));
- dcr_write(i2o_dcr_host, DCRN_I2O0_IBAL, (u32)(i2o_res.start) |
- I2O_REG_ENABLE);
- dcr_unmap(i2o_dcr_host, dcr_len);
-
- /* Setup FIFO memory space base address */
- iowrite32(0, &i2o_reg->ifbah);
- iowrite32(((u32)__pa(ppc440spe_dma_fifo_buf)), &i2o_reg->ifbal);
-
- /* set zero FIFO size for I2O, so the whole
- * ppc440spe_dma_fifo_buf is used by DMAs.
- * DMAx_FIFOs will be configured while probe.
- */
- iowrite32(0, &i2o_reg->ifsiz);
- iounmap(i2o_reg);
-
- /* To prepare WXOR/RXOR functionality we need access to
- * Memory Queue Module DCRs (finally it will be enabled
- * via /sys interface of the ppc440spe ADMA driver).
- */
- np = of_find_compatible_node(NULL, NULL, "ibm,mq-440spe");
- if (!np) {
- pr_err("%s: can't find MQ device tree node\n",
- __func__);
- ret = -ENODEV;
- goto out_free;
- }
-
- /* Get MQ DCRs base */
- dcr_base = dcr_resource_start(np, 0);
- dcr_len = dcr_resource_len(np, 0);
- if (!dcr_base && !dcr_len) {
- pr_err("%s: can't get DCR registers base/len!\n",
- np->full_name);
- ret = -ENODEV;
- goto out_mq;
- }
-
- ppc440spe_mq_dcr_host = dcr_map(np, dcr_base, dcr_len);
- if (!DCR_MAP_OK(ppc440spe_mq_dcr_host)) {
- pr_err("%s: failed to map DCRs!\n", np->full_name);
- ret = -ENODEV;
- goto out_mq;
- }
- of_node_put(np);
- ppc440spe_mq_dcr_len = dcr_len;
-
- /* Set HB alias */
- dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_BAUH, DMA_CUED_XOR_HB);
-
- /* Set:
- * - LL transaction passing limit to 1;
- * - Memory controller cycle limit to 1;
- * - Galois Polynomial to 0x14d (default)
- */
- dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_CFBHL,
- (1 << MQ0_CFBHL_TPLM) | (1 << MQ0_CFBHL_HBCL) |
- (PPC440SPE_DEFAULT_POLY << MQ0_CFBHL_POLY));
-
- atomic_set(&ppc440spe_adma_err_irq_ref, 0);
- for (i = 0; i < PPC440SPE_ADMA_ENGINES_NUM; i++)
- ppc440spe_adma_devices[i] = -1;
-
- return 0;
-
-out_mq:
- of_node_put(np);
-out_free:
- kfree(ppc440spe_dma_fifo_buf);
- return ret;
-}
-
-static const struct of_device_id ppc440spe_adma_of_match[] __devinitconst = {
- { .compatible = "ibm,dma-440spe", },
- { .compatible = "amcc,xor-accelerator", },
- {},
-};
-MODULE_DEVICE_TABLE(of, ppc440spe_adma_of_match);
-
-static struct of_platform_driver ppc440spe_adma_driver = {
- .probe = ppc440spe_adma_probe,
- .remove = __devexit_p(ppc440spe_adma_remove),
+static struct of_platform_driver ppc4xx_adma_driver = {
+ .probe = ppc4xx_adma_probe,
+ .remove = __devexit_p(ppc4xx_adma_remove),
.driver = {
- .name = "PPC440SP(E)-ADMA",
- .owner = THIS_MODULE,
- .of_match_table = ppc440spe_adma_of_match,
- },
+ .name = "PPC4XX-ADMA",
+ .owner = THIS_MODULE,
+ .of_match_table = ppc4xx_adma_of_match,
+ },
};
-static __init int ppc440spe_adma_init(void)
-{
- int ret;
-
- ret = ppc440spe_configure_raid_devices();
- if (ret)
- return ret;
-
- ret = of_register_platform_driver(&ppc440spe_adma_driver);
- if (ret) {
- pr_err("%s: failed to register platform driver\n",
- __func__);
- goto out_reg;
- }
-
- /* Initialization status */
- ret = driver_create_file(&ppc440spe_adma_driver.driver,
- &driver_attr_devices);
- if (ret)
- goto out_dev;
-
- /* RAID-6 h/w enable entry */
- ret = driver_create_file(&ppc440spe_adma_driver.driver,
- &driver_attr_enable);
- if (ret)
- goto out_en;
-
- /* GF polynomial to use */
- ret = driver_create_file(&ppc440spe_adma_driver.driver,
- &driver_attr_poly);
- if (!ret)
- return ret;
-
- driver_remove_file(&ppc440spe_adma_driver.driver,
- &driver_attr_enable);
-out_en:
- driver_remove_file(&ppc440spe_adma_driver.driver,
- &driver_attr_devices);
-out_dev:
- /* User will not be able to enable h/w RAID-6 */
- pr_err("%s: failed to create RAID-6 driver interface\n",
- __func__);
- of_unregister_platform_driver(&ppc440spe_adma_driver);
-out_reg:
- dcr_unmap(ppc440spe_mq_dcr_host, ppc440spe_mq_dcr_len);
- kfree(ppc440spe_dma_fifo_buf);
- return ret;
-}
-
-static void __exit ppc440spe_adma_exit(void)
-{
- driver_remove_file(&ppc440spe_adma_driver.driver,
- &driver_attr_poly);
- driver_remove_file(&ppc440spe_adma_driver.driver,
- &driver_attr_enable);
- driver_remove_file(&ppc440spe_adma_driver.driver,
- &driver_attr_devices);
- of_unregister_platform_driver(&ppc440spe_adma_driver);
- dcr_unmap(ppc440spe_mq_dcr_host, ppc440spe_mq_dcr_len);
- kfree(ppc440spe_dma_fifo_buf);
-}
-
-arch_initcall(ppc440spe_adma_init);
-module_exit(ppc440spe_adma_exit);
+arch_initcall(ppc4xx_adma_init);
+module_exit(ppc4xx_adma_exit);
MODULE_AUTHOR("Yuri Tikhonov <yur@emcraft.com>");
-MODULE_DESCRIPTION("PPC440SPE ADMA Engine Driver");
+MODULE_DESCRIPTION("PPC4XX ADMA Engine Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/dma/ppc4xx/adma.h b/drivers/dma/ppc4xx/adma.h
index 8ada5a8..10d7198 100644
--- a/drivers/dma/ppc4xx/adma.h
+++ b/drivers/dma/ppc4xx/adma.h
@@ -8,45 +8,52 @@
* any kind, whether express or implied.
*/
-#ifndef _PPC440SPE_ADMA_H
-#define _PPC440SPE_ADMA_H
+#ifndef _PPC4XX_ADMA_H
+#define _PPC4XX_ADMA_H
#include <linux/types.h>
-#include "dma.h"
-#include "xor.h"
-#define to_ppc440spe_adma_chan(chan) \
- container_of(chan, struct ppc440spe_adma_chan, common)
-#define to_ppc440spe_adma_device(dev) \
- container_of(dev, struct ppc440spe_adma_device, common)
-#define tx_to_ppc440spe_adma_slot(tx) \
- container_of(tx, struct ppc440spe_adma_desc_slot, async_tx)
-
-/* Default polynomial (for 440SP is only available) */
-#define PPC440SPE_DEFAULT_POLY 0x4d
-
-#define PPC440SPE_ADMA_ENGINES_NUM (XOR_ENGINES_NUM + DMA_ENGINES_NUM)
-
-#define PPC440SPE_ADMA_WATCHDOG_MSEC 3
-#define PPC440SPE_ADMA_THRESHOLD 1
-
-#define PPC440SPE_DMA0_ID 0
-#define PPC440SPE_DMA1_ID 1
-#define PPC440SPE_XOR_ID 2
-
-#define PPC440SPE_ADMA_DMA_MAX_BYTE_COUNT 0xFFFFFFUL
-/* this is the XOR_CBBCR width */
-#define PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT (1 << 31)
-#define PPC440SPE_ADMA_ZERO_SUM_MAX_BYTE_COUNT PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT
-
-#define PPC440SPE_RXOR_RUN 0
+#define to_ppc4xx_adma_chan(chan) \
+ container_of(chan, struct ppc4xx_adma_chan, common)
+#define to_ppc4xx_adma_device(dev) \
+ container_of(dev, struct ppc4xx_adma_device, common)
+#define tx_to_ppc4xx_adma_slot(tx) \
+ container_of(tx, struct ppc4xx_adma_desc_slot, async_tx)
+
+enum ppc_adma_init_code {
+ PPC_ADMA_INIT_OK = 0,
+ PPC_ADMA_INIT_MEMRES,
+ PPC_ADMA_INIT_MEMREG,
+ PPC_ADMA_INIT_ALLOC,
+ PPC_ADMA_INIT_COHERENT,
+ PPC_ADMA_INIT_CHANNEL,
+ PPC_ADMA_INIT_IRQ1,
+ PPC_ADMA_INIT_IRQ2,
+ PPC_ADMA_INIT_REGISTER
+};
-#define MQ0_CF2H_RXOR_BS_MASK 0x1FF
+static char *ppc_adma_errors[] = {
+ [PPC_ADMA_INIT_OK] = "ok",
+ [PPC_ADMA_INIT_MEMRES] = "failed to get memory resource",
+ [PPC_ADMA_INIT_MEMREG] = "failed to request memory region",
+ [PPC_ADMA_INIT_ALLOC] = "failed to allocate memory for adev "
+ "structure",
+ [PPC_ADMA_INIT_COHERENT] = "failed to allocate coherent memory for "
+ "hardware descriptors",
+ [PPC_ADMA_INIT_CHANNEL] = "failed to allocate memory for channel",
+ [PPC_ADMA_INIT_IRQ1] = "failed to request first irq",
+ [PPC_ADMA_INIT_IRQ2] = "failed to request second irq",
+ [PPC_ADMA_INIT_REGISTER] = "failed to register dma async device",
+};
+struct ppc_dma_chan_ref {
+ struct dma_chan *chan;
+ struct list_head node;
+};
#undef ADMA_LL_DEBUG
/**
- * struct ppc440spe_adma_device - internal representation of an ADMA device
+ * struct ppc4xx_adma_device - internal representation of an ADMA device
* @dev: device
* @dma_reg: base for DMAx register access
* @xor_reg: base for XOR register access
@@ -59,7 +66,7 @@
* @err_irq: DMAx error irq number
* @common: embedded struct dma_device
*/
-struct ppc440spe_adma_device {
+struct ppc4xx_adma_device {
struct device *dev;
struct dma_regs __iomem *dma_reg;
struct xor_regs __iomem *xor_reg;
@@ -74,7 +81,7 @@ struct ppc440spe_adma_device {
};
/**
- * struct ppc440spe_adma_chan - internal representation of an ADMA channel
+ * struct ppc4xx_adma_chan - internal representation of an ADMA channel
* @lock: serializes enqueue/dequeue operations to the slot pool
* @device: parent device
* @chain: device chain view of the descriptors
@@ -84,20 +91,20 @@ struct ppc440spe_adma_device {
* @completed_cookie: identifier for the most recently completed operation
* @slots_allocated: records the actual size of the descriptor slot pool
* @hw_chain_inited: h/w descriptor chain initialization flag
- * @irq_tasklet: bottom half where ppc440spe_adma_slot_cleanup runs
+ * @irq_tasklet: bottom half where ppc4xx_adma_slot_cleanup runs
* @needs_unmap: if buffers should not be unmapped upon final processing
* @pdest_page: P destination page for async validate operation
* @qdest_page: Q destination page for async validate operation
* @pdest: P dma addr for async validate operation
* @qdest: Q dma addr for async validate operation
*/
-struct ppc440spe_adma_chan {
+struct ppc4xx_adma_chan {
spinlock_t lock;
- struct ppc440spe_adma_device *device;
+ struct ppc4xx_adma_device *device;
struct list_head chain;
struct dma_chan common;
struct list_head all_slots;
- struct ppc440spe_adma_desc_slot *last_used;
+ struct ppc4xx_adma_desc_slot *last_used;
int pending;
dma_cookie_t completed_cookie;
int slots_allocated;
@@ -110,7 +117,7 @@ struct ppc440spe_adma_chan {
dma_addr_t qdest;
};
-struct ppc440spe_rxor {
+struct ppc4xx_rxor {
u32 addrl;
u32 addrh;
int len;
@@ -121,7 +128,7 @@ struct ppc440spe_rxor {
};
/**
- * struct ppc440spe_adma_desc_slot - PPC440SPE-ADMA software descriptor
+ * struct ppc4xx_adma_desc_slot - PPC4XX-ADMA software descriptor
* @phys: hardware address of the hardware descriptor chain
* @group_head: first operation in a transaction
* @hw_next: pointer to the next descriptor in chain
@@ -139,16 +146,16 @@ struct ppc440spe_rxor {
* @dst_cnt: number of destinations set in the descriptor
* @slots_per_op: number of slots per operation
* @descs_per_op: number of slot per P/Q operation see comment
- * for ppc440spe_prep_dma_pqxor function
+ * for ppc4xx_prep_dma_pqxor function
* @flags: desc state/type
* @reverse_flags: 1 if a corresponding rxor address uses reversed address order
* @xor_check_result: result of zero sum
* @crc32_result: result crc calculation
*/
-struct ppc440spe_adma_desc_slot {
+struct ppc4xx_adma_desc_slot {
dma_addr_t phys;
- struct ppc440spe_adma_desc_slot *group_head;
- struct ppc440spe_adma_desc_slot *hw_next;
+ struct ppc4xx_adma_desc_slot *group_head;
+ struct ppc4xx_adma_desc_slot *hw_next;
struct dma_async_tx_descriptor async_tx;
struct list_head slot_node;
struct list_head chain_node; /* node in channel ops list */
@@ -165,26 +172,7 @@ struct ppc440spe_adma_desc_slot {
unsigned long flags;
unsigned long reverse_flags[8];
-#define PPC440SPE_DESC_INT 0 /* generate interrupt on complete */
-#define PPC440SPE_ZERO_P 1 /* clear P destionaion */
-#define PPC440SPE_ZERO_Q 2 /* clear Q destination */
-#define PPC440SPE_COHERENT 3 /* src/dst are coherent */
-
-#define PPC440SPE_DESC_WXOR 4 /* WXORs are in chain */
-#define PPC440SPE_DESC_RXOR 5 /* RXOR is in chain */
-
-#define PPC440SPE_DESC_RXOR123 8 /* CDB for RXOR123 operation */
-#define PPC440SPE_DESC_RXOR124 9 /* CDB for RXOR124 operation */
-#define PPC440SPE_DESC_RXOR125 10 /* CDB for RXOR125 operation */
-#define PPC440SPE_DESC_RXOR12 11 /* CDB for RXOR12 operation */
-#define PPC440SPE_DESC_RXOR_REV 12 /* CDB has srcs in reversed order */
-
-#define PPC440SPE_DESC_PCHECK 13
-#define PPC440SPE_DESC_QCHECK 14
-
-#define PPC440SPE_DESC_RXOR_MSK 0x3
-
- struct ppc440spe_rxor rxor_cursor;
+ struct ppc4xx_rxor rxor_cursor;
union {
u32 *xor_check_result;
@@ -192,4 +180,4 @@ struct ppc440spe_adma_desc_slot {
};
};
-#endif /* _PPC440SPE_ADMA_H */
+#endif /* _PPC4XX_ADMA_H */
diff --git a/drivers/dma/ppc4xx/ppc4xx-adma.h b/drivers/dma/ppc4xx/ppc4xx-adma.h
new file mode 100644
index 0000000..7457237
--- /dev/null
+++ b/drivers/dma/ppc4xx/ppc4xx-adma.h
@@ -0,0 +1,4020 @@
+/*
+ * Copyright (C) 2006-2009 DENX Software Engineering.
+ *
+ * Author: Yuri Tikhonov <yur@emcraft.com>
+ *
+ * Further porting to arch/powerpc by
+ * Anatolij Gustschin <agust@denx.de>
+ * Tirumala R Marri <tmarri@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
+/*
+ * This driver supports the asynchrounous DMA copy and RAID engines available
+ * on the AMCC PPC440SPe Processors.
+ * Based on the Intel Xscale(R) family of I/O Processors (IOP 32x, 33x, 134x)
+ * ADMA driver written by D.Williams.
+ */
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+#include "adma.h"
+#include "ppc440spe-dma.h"
+
+/* Default polynomial (for 440SP is only available) */
+#define PPC4XX_DEFAULT_POLY 0x4d
+
+#define PPC4XX_ADMA_ENGINES_NUM (XOR_ENGINES_NUM + DMA_ENGINES_NUM)
+
+#define PPC4XX_ADMA_WATCHDOG_MSEC 3
+#define PPC4XX_ADMA_THRESHOLD 1
+
+#define PPC4XX_DMA0_ID 0
+#define PPC4XX_DMA1_ID 1
+#define PPC4XX_XOR_ID 2
+
+#define PPC4XX_ADMA_DMA_MAX_BYTE_COUNT 0xFFFFFFUL
+/* this is the XOR_CBBCR width */
+#define PPC4XX_ADMA_XOR_MAX_BYTE_COUNT (1 << 31)
+#define PPC4XX_ADMA_ZERO_SUM_MAX_BYTE_COUNT PPC4XX_ADMA_XOR_MAX_BYTE_COUNT
+
+#define PPC4XX_RXOR_RUN 0
+
+#define MQ0_CF2H_RXOR_BS_MASK 0x1FF
+
+#define PPC4XX_DESC_INT 0 /* generate interrupt on complete */
+#define PPC4XX_ZERO_P 1 /* clear P destionaion */
+#define PPC4XX_ZERO_Q 2 /* clear Q destination */
+#define PPC4XX_COHERENT 3 /* src/dst are coherent */
+
+#define PPC4XX_DESC_WXOR 4 /* WXORs are in chain */
+#define PPC4XX_DESC_RXOR 5 /* RXOR is in chain */
+
+#define PPC4XX_DESC_RXOR123 8 /* CDB for RXOR123 operation */
+#define PPC4XX_DESC_RXOR124 9 /* CDB for RXOR124 operation */
+#define PPC4XX_DESC_RXOR125 10 /* CDB for RXOR125 operation */
+#define PPC4XX_DESC_RXOR12 11 /* CDB for RXOR12 operation */
+#define PPC4XX_DESC_RXOR_REV 12 /* CDB has srcs in reversed order */
+
+#define PPC4XX_DESC_PCHECK 13
+#define PPC4XX_DESC_QCHECK 14
+
+#define PPC4XX_DESC_RXOR_MSK 0x3
+
+/* The list of channels exported by ppc440spe ADMA */
+struct list_head
+ ppc4xx_adma_chan_list = LIST_HEAD_INIT(ppc4xx_adma_chan_list);
+
+/* This flag is set when want to refetch the xor chain in the interrupt
+ * handler
+ */
+static u32 do_xor_refetch;
+
+/* Pointer to DMA0, DMA1 CP/CS FIFO */
+static void *ppc440spe_dma_fifo_buf;
+
+/* Pointers to last submitted to DMA0, DMA1 CDBs */
+static struct ppc4xx_adma_desc_slot *chan_last_sub[3];
+static struct ppc4xx_adma_desc_slot *chan_first_cdb[3];
+
+/* Pointer to last linked and submitted xor CB */
+static struct ppc4xx_adma_desc_slot *xor_last_linked;
+static struct ppc4xx_adma_desc_slot *xor_last_submit;
+
+/* This array is used in data-check operations for storing a pattern */
+static char ppc440spe_qword[16];
+
+static atomic_t ppc4xx_adma_err_irq_ref;
+static dcr_host_t ppc440spe_mq_dcr_host;
+static unsigned int ppc440spe_mq_dcr_len;
+
+static int ppc4xx_adma_devices[PPC4XX_ADMA_ENGINES_NUM];
+/* Since RXOR operations use the common register (MQ0_CF2H) for setting-up
+ * the block size in transactions, then we do not allow to activate more than
+ * only one RXOR transactions simultaneously. So use this var to store
+ * the information about is RXOR currently active (PPC4XX_RXOR_RUN bit is
+ * set) or not (PPC4XX_RXOR_RUN is clear).
+ */
+static unsigned long ppc440spe_rxor_state;
+
+static struct page *ppc440spe_rxor_srcs[32];
+
+static struct of_platform_driver ppc4xx_adma_driver;
+/* These are used in enable & check routines
+ */
+static u32 ppc440spe_r6_enabled;
+static struct ppc4xx_adma_chan *ppc440spe_r6_tchan;
+static struct completion ppc440spe_r6_test_comp;
+
+static int ppc4xx_adma_dma2rxor_prep_src(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_rxor *cursor,
+ int index, int src_cnt, u32 addr);
+static void ppc4xx_adma_dma2rxor_set_src(struct ppc4xx_adma_desc_slot *desc,
+ int index, dma_addr_t addr);
+static void ppc4xx_adma_dma2rxor_set_mult(struct ppc4xx_adma_desc_slot *desc,
+ int index, u8 mult);
+static void ppc440spe_init_rxor_cursor(struct ppc4xx_rxor *cursor);
+static irqreturn_t ppc4xx_adma_eot_handler(int irq, void *data);
+static irqreturn_t ppc4xx_adma_err_handler(int irq, void *data);
+
+static void ppc4xx_adma_issue_pending(struct dma_chan *chan);
+static void ppc4xx_adma_init_dma2rxor_slot(struct ppc4xx_adma_desc_slot
+ *desc, dma_addr_t * src,
+ int src_cnt);
+static struct ppc4xx_adma_desc_slot *ppc4xx_adma_alloc_slots(struct
+ ppc4xx_adma_chan
+ *chan,
+ int num_slots,
+ int slots_per_op);
+static void ppc4xx_adma_free_slots(struct ppc4xx_adma_desc_slot *slot,
+ struct ppc4xx_adma_chan *chan);
+static struct ppc4xx_adma_desc_slot *ppc4xx_get_group_entry(struct
+ ppc4xx_adma_desc_slot
+ *tdesc,
+ u32 entry_idx);
+static dma_cookie_t ppc4xx_adma_tx_submit(struct dma_async_tx_descriptor *tx);
+static void ppc4xx_chan_start_null_xor(struct ppc4xx_adma_chan *chan);
+static void prep_dma_pqzero_sum_dbg(int id, dma_addr_t * src,
+ unsigned int src_cnt,
+ const unsigned char *scf);
+static void print_cb_list(struct ppc4xx_adma_chan *chan,
+ struct ppc4xx_adma_desc_slot *iter);
+static void prep_dma_pq_dbg(int id, dma_addr_t * dst, dma_addr_t * src,
+ unsigned int src_cnt);
+
+#ifdef ADMA_LL_DEBUG
+#define ADMA_LL_DBG(x) ({ if (1) x; 0; })
+#else
+#define ADMA_LL_DBG(x) ({ if (0) x; 0; })
+#endif
+static void print_cb(struct ppc4xx_adma_chan *chan, void *block)
+{
+ struct dma_cdb *cdb;
+ struct xor_cb *cb;
+ int i;
+
+ switch (chan->device->id) {
+ case 0:
+ case 1:
+ cdb = block;
+
+ pr_debug("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)
+ );
+ break;
+ case 2:
+ cb = block;
+
+ pr_debug("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;
+ pr_debug("\t ops[%2d]: h 0x%08x l 0x%08x\n",
+ i, cb->ops[i].h, cb->ops[i].l);
+ }
+ break;
+ }
+}
+
+/**
+ * ppc440spe_can_rxor - check if the operands may be processed with RXOR
+ */
+static int ppc440spe_can_rxor(struct page **srcs, int src_cnt, size_t len)
+{
+ int i, order = 0, state = 0;
+ int idx = 0;
+
+ if (unlikely(!(src_cnt > 1)))
+ return 0;
+
+ BUG_ON(src_cnt > ARRAY_SIZE(ppc440spe_rxor_srcs));
+
+ /* Skip holes in the source list before checking */
+ for (i = 0; i < src_cnt; i++) {
+ if (!srcs[i])
+ continue;
+ ppc440spe_rxor_srcs[idx++] = srcs[i];
+ }
+ src_cnt = idx;
+
+ for (i = 1; i < src_cnt; i++) {
+ char *cur_addr = page_address(ppc440spe_rxor_srcs[i]);
+ char *old_addr = page_address(ppc440spe_rxor_srcs[i - 1]);
+
+ switch (state) {
+ case 0:
+ if (cur_addr == old_addr + len) {
+ /* direct RXOR */
+ order = 1;
+ state = 1;
+ } else if (old_addr == cur_addr + len) {
+ /* reverse RXOR */
+ order = -1;
+ state = 1;
+ } else
+ goto out;
+ break;
+ case 1:
+ if ((i == src_cnt - 2) ||
+ (order == -1 && cur_addr != old_addr - len)) {
+ order = 0;
+ state = 0;
+ } else if ((cur_addr == old_addr + len * order) ||
+ (cur_addr == old_addr + 2 * len) ||
+ (cur_addr == old_addr + 3 * len)) {
+ state = 2;
+ } else {
+ order = 0;
+ state = 0;
+ }
+ break;
+ case 2:
+ order = 0;
+ state = 0;
+ break;
+ }
+ }
+
+ out:
+ if (state == 1 || state == 2)
+ return 1;
+
+ return 0;
+}
+
+/******************************************************************************
+ * Command (Descriptor) Blocks low-level routines
+ ******************************************************************************/
+/**
+ * ppc4xx_desc_init_interrupt - initialize the descriptor for INTERRUPT
+ * pseudo operation
+ */
+static void ppc4xx_desc_init_interrupt(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan)
+{
+ struct xor_cb *p;
+
+ switch (chan->device->id) {
+ case PPC4XX_XOR_ID:
+ p = desc->hw_desc;
+ memset(desc->hw_desc, 0, sizeof(struct xor_cb));
+ /* NOP with Command Block Complete Enable */
+ p->cbc = XOR_CBCR_CBCE_BIT;
+ break;
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ memset(desc->hw_desc, 0, sizeof(struct dma_cdb));
+ /* NOP with interrupt */
+ set_bit(PPC4XX_DESC_INT, &desc->flags);
+ break;
+ default:
+ printk(KERN_ERR "Unsupported id %d in %s\n", chan->device->id,
+ __func__);
+ break;
+ }
+}
+
+/**
+ * ppc4xx_desc_init_null_xor - initialize the descriptor for NULL XOR
+ * pseudo operation
+ */
+static void ppc4xx_desc_init_null_xor(struct ppc4xx_adma_desc_slot *desc)
+{
+ memset(desc->hw_desc, 0, sizeof(struct xor_cb));
+ desc->hw_next = NULL;
+ desc->src_cnt = 0;
+ desc->dst_cnt = 1;
+}
+
+/**
+ * ppc4xx_desc_init_xor - initialize the descriptor for XOR operation
+ */
+static void ppc4xx_desc_init_xor(struct ppc4xx_adma_desc_slot *desc,
+ int src_cnt, unsigned long flags)
+{
+ struct xor_cb *hw_desc = desc->hw_desc;
+
+ memset(desc->hw_desc, 0, sizeof(struct xor_cb));
+ desc->hw_next = NULL;
+ desc->src_cnt = src_cnt;
+ desc->dst_cnt = 1;
+
+ hw_desc->cbc = XOR_CBCR_TGT_BIT | src_cnt;
+ if (flags & DMA_PREP_INTERRUPT)
+ /* Enable interrupt on completion */
+ hw_desc->cbc |= XOR_CBCR_CBCE_BIT;
+}
+
+/**
+ * ppc4xx_desc_init_dma2pq - initialize the descriptor for PQ
+ * operation in DMA2 controller
+ */
+static void ppc4xx_desc_init_dma2pq(struct ppc4xx_adma_desc_slot *desc,
+ int dst_cnt, int src_cnt,
+ unsigned long flags)
+{
+ struct xor_cb *hw_desc = desc->hw_desc;
+
+ memset(desc->hw_desc, 0, sizeof(struct xor_cb));
+ desc->hw_next = NULL;
+ desc->src_cnt = src_cnt;
+ desc->dst_cnt = dst_cnt;
+ memset(desc->reverse_flags, 0, sizeof(desc->reverse_flags));
+ desc->descs_per_op = 0;
+
+ hw_desc->cbc = XOR_CBCR_TGT_BIT;
+ if (flags & DMA_PREP_INTERRUPT)
+ /* Enable interrupt on completion */
+ hw_desc->cbc |= XOR_CBCR_CBCE_BIT;
+}
+
+#define DMA_CTRL_FLAGS_LAST DMA_PREP_FENCE
+#define DMA_PREP_ZERO_P (DMA_CTRL_FLAGS_LAST << 1)
+#define DMA_PREP_ZERO_Q (DMA_PREP_ZERO_P << 1)
+
+/**
+ * ppc4xx_desc_init_dma01pq - initialize the descriptors for PQ operation
+ * with DMA0/1
+ */
+static void ppc4xx_desc_init_dma01pq(struct ppc4xx_adma_desc_slot *desc,
+ int dst_cnt, int src_cnt,
+ unsigned long flags, unsigned long op)
+{
+ struct dma_cdb *hw_desc;
+ struct ppc4xx_adma_desc_slot *iter;
+ u8 dopc;
+
+ /* Common initialization of a PQ descriptors chain */
+ set_bits(op, &desc->flags);
+ desc->src_cnt = src_cnt;
+ desc->dst_cnt = dst_cnt;
+
+ /* WXOR MULTICAST if both P and Q are being computed
+ * MV_SG1_SG2 if Q only
+ */
+ dopc = (desc->dst_cnt == DMA_DEST_MAX_NUM) ?
+ DMA_CDB_OPC_MULTICAST : DMA_CDB_OPC_MV_SG1_SG2;
+
+ list_for_each_entry(iter, &desc->group_list, chain_node) {
+ hw_desc = iter->hw_desc;
+ memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
+
+ if (likely(!list_is_last(&iter->chain_node, &desc->group_list))) {
+ /* set 'next' pointer */
+ iter->hw_next = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ clear_bit(PPC4XX_DESC_INT, &iter->flags);
+ } else {
+ /* this is the last descriptor.
+ * this slot will be pasted from ADMA level
+ * each time it wants to configure parameters
+ * of the transaction (src, dst, ...)
+ */
+ iter->hw_next = NULL;
+ if (flags & DMA_PREP_INTERRUPT)
+ set_bit(PPC4XX_DESC_INT, &iter->flags);
+ else
+ clear_bit(PPC4XX_DESC_INT, &iter->flags);
+ }
+ }
+
+ /* Set OPS depending on WXOR/RXOR type of operation */
+ if (!test_bit(PPC4XX_DESC_RXOR, &desc->flags)) {
+ /* This is a WXOR only chain:
+ * - first descriptors are for zeroing destinations
+ * if PPC4XX_ZERO_P/Q set;
+ * - descriptors remained are for GF-XOR operations.
+ */
+ iter = list_first_entry(&desc->group_list,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+
+ if (test_bit(PPC4XX_ZERO_P, &desc->flags)) {
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+ iter = list_first_entry(&iter->chain_node,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ }
+
+ if (test_bit(PPC4XX_ZERO_Q, &desc->flags)) {
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+ iter = list_first_entry(&iter->chain_node,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ }
+
+ list_for_each_entry_from(iter, &desc->group_list, chain_node) {
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = dopc;
+ }
+ } else {
+ /* This is either RXOR-only or mixed RXOR/WXOR */
+
+ /* The first 1 or 2 slots in chain are always RXOR,
+ * if need to calculate P & Q, then there are two
+ * RXOR slots; if only P or only Q, then there is one
+ */
+ iter = list_first_entry(&desc->group_list,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+
+ if (desc->dst_cnt == DMA_DEST_MAX_NUM) {
+ iter = list_first_entry(&iter->chain_node,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+ }
+
+ /* The remaining descs (if any) are WXORs */
+ if (test_bit(PPC4XX_DESC_WXOR, &desc->flags)) {
+ iter = list_first_entry(&iter->chain_node,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ list_for_each_entry_from(iter, &desc->group_list,
+ chain_node) {
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = dopc;
+ }
+ }
+ }
+}
+
+/**
+ * ppc4xx_desc_init_dma01pqzero_sum - initialize the descriptor
+ * for PQ_ZERO_SUM operation
+ */
+static void ppc4xx_desc_init_dma01pqzero_sum(struct ppc4xx_adma_desc_slot
+ *desc, int dst_cnt, int src_cnt)
+{
+ struct dma_cdb *hw_desc;
+ struct ppc4xx_adma_desc_slot *iter;
+ int i = 0;
+ u8 dopc = (dst_cnt == 2) ? DMA_CDB_OPC_MULTICAST :
+ DMA_CDB_OPC_MV_SG1_SG2;
+ /*
+ * Initialize starting from 2nd or 3rd descriptor dependent
+ * on dst_cnt. First one or two slots are for cloning P
+ * and/or Q to chan->pdest and/or chan->qdest as we have
+ * to preserve original P/Q.
+ */
+ iter = list_first_entry(&desc->group_list,
+ struct ppc4xx_adma_desc_slot, chain_node);
+ iter = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot, chain_node);
+
+ if (dst_cnt > 1) {
+ iter = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot, chain_node);
+ }
+ /* initialize each source descriptor in chain */
+ list_for_each_entry_from(iter, &desc->group_list, chain_node) {
+ hw_desc = iter->hw_desc;
+ memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
+ iter->src_cnt = 0;
+ iter->dst_cnt = 0;
+
+ /* This is a ZERO_SUM operation:
+ * - <src_cnt> descriptors starting from 2nd or 3rd
+ * descriptor are for GF-XOR operations;
+ * - remaining <dst_cnt> descriptors are for checking the result
+ */
+ if (i++ < src_cnt)
+ /* MV_SG1_SG2 if only Q is being verified
+ * MULTICAST if both P and Q are being verified
+ */
+ hw_desc->opc = dopc;
+ else
+ /* DMA_CDB_OPC_DCHECK128 operation */
+ hw_desc->opc = DMA_CDB_OPC_DCHECK128;
+
+ if (likely(!list_is_last(&iter->chain_node, &desc->group_list))) {
+ /* set 'next' pointer */
+ iter->hw_next = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ } else {
+ /* this is the last descriptor.
+ * this slot will be pasted from ADMA level
+ * each time it wants to configure parameters
+ * of the transaction (src, dst, ...)
+ */
+ iter->hw_next = NULL;
+ /* always enable interrupt generation since we get
+ * the status of pqzero from the handler
+ */
+ set_bit(PPC4XX_DESC_INT, &iter->flags);
+ }
+ }
+ desc->src_cnt = src_cnt;
+ desc->dst_cnt = dst_cnt;
+}
+
+/**
+ * ppc4xx_desc_init_memcpy - initialize the descriptor for MEMCPY operation
+ */
+static void ppc4xx_desc_init_memcpy(struct ppc4xx_adma_desc_slot *desc,
+ unsigned long flags)
+{
+ struct dma_cdb *hw_desc = desc->hw_desc;
+
+ memset(desc->hw_desc, 0, sizeof(struct dma_cdb));
+ desc->hw_next = NULL;
+ desc->src_cnt = 1;
+ desc->dst_cnt = 1;
+
+ if (flags & DMA_PREP_INTERRUPT)
+ set_bit(PPC4XX_DESC_INT, &desc->flags);
+ else
+ clear_bit(PPC4XX_DESC_INT, &desc->flags);
+
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+}
+
+/**
+ * ppc4xx_desc_init_memset - initialize the descriptor for MEMSET operation
+ */
+static void ppc4xx_desc_init_memset(struct ppc4xx_adma_desc_slot *desc,
+ int value, unsigned long flags)
+{
+ struct dma_cdb *hw_desc = desc->hw_desc;
+
+ memset(desc->hw_desc, 0, sizeof(struct dma_cdb));
+ desc->hw_next = NULL;
+ desc->src_cnt = 1;
+ desc->dst_cnt = 1;
+
+ if (flags & DMA_PREP_INTERRUPT)
+ set_bit(PPC4XX_DESC_INT, &desc->flags);
+ else
+ clear_bit(PPC4XX_DESC_INT, &desc->flags);
+
+ hw_desc->sg1u = hw_desc->sg1l = cpu_to_le32((u32) value);
+ hw_desc->sg3u = hw_desc->sg3l = cpu_to_le32((u32) value);
+ hw_desc->opc = DMA_CDB_OPC_DFILL128;
+}
+
+/**
+ * ppc4xx_desc_set_src_addr - set source address into the descriptor
+ */
+static void ppc4xx_desc_set_src_addr(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan,
+ int src_idx, dma_addr_t addrh,
+ dma_addr_t addrl)
+{
+ struct dma_cdb *dma_hw_desc;
+ struct xor_cb *xor_hw_desc;
+ phys_addr_t addr64, tmplow, tmphi;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ if (!addrh) {
+ addr64 = addrl;
+ tmphi = (addr64 >> 32);
+ tmplow = (addr64 & 0xFFFFFFFF);
+ } else {
+ tmphi = addrh;
+ tmplow = addrl;
+ }
+ dma_hw_desc = desc->hw_desc;
+ dma_hw_desc->sg1l = cpu_to_le32((u32) tmplow);
+ dma_hw_desc->sg1u |= cpu_to_le32((u32) tmphi);
+ break;
+ case PPC4XX_XOR_ID:
+ xor_hw_desc = desc->hw_desc;
+ xor_hw_desc->ops[src_idx].l = addrl;
+ xor_hw_desc->ops[src_idx].h |= addrh;
+ break;
+ }
+}
+
+/**
+ * ppc4xx_desc_set_src_mult - set source address mult into the descriptor
+ */
+static void ppc4xx_desc_set_src_mult(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan,
+ u32 mult_index, int sg_index,
+ unsigned char mult_value)
+{
+ struct dma_cdb *dma_hw_desc;
+ struct xor_cb *xor_hw_desc;
+ u32 *psgu;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ dma_hw_desc = desc->hw_desc;
+
+ switch (sg_index) {
+ /* for RXOR operations set multiplier
+ * into source cued address
+ */
+ case DMA_CDB_SG_SRC:
+ psgu = &dma_hw_desc->sg1u;
+ break;
+ /* for WXOR operations set multiplier
+ * into destination cued address(es)
+ */
+ case DMA_CDB_SG_DST1:
+ psgu = &dma_hw_desc->sg2u;
+ break;
+ case DMA_CDB_SG_DST2:
+ psgu = &dma_hw_desc->sg3u;
+ break;
+ default:
+ BUG();
+ }
+
+ *psgu |= cpu_to_le32(mult_value << mult_index);
+ break;
+ case PPC4XX_XOR_ID:
+ xor_hw_desc = desc->hw_desc;
+ break;
+ default:
+ BUG();
+ }
+}
+
+/**
+ * ppc4xx_desc_set_dest_addr - set destination address into the descriptor
+ */
+static void ppc4xx_desc_set_dest_addr(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan,
+ dma_addr_t addrh, dma_addr_t addrl,
+ u32 dst_idx)
+{
+ struct dma_cdb *dma_hw_desc;
+ struct xor_cb *xor_hw_desc;
+ phys_addr_t addr64, tmphi, tmplow;
+ u32 *psgu, *psgl;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ if (!addrh) {
+ addr64 = addrl;
+ tmphi = (addr64 >> 32);
+ tmplow = (addr64 & 0xFFFFFFFF);
+ } else {
+ tmphi = addrh;
+ tmplow = addrl;
+ }
+ dma_hw_desc = desc->hw_desc;
+
+ psgu = dst_idx ? &dma_hw_desc->sg3u : &dma_hw_desc->sg2u;
+ psgl = dst_idx ? &dma_hw_desc->sg3l : &dma_hw_desc->sg2l;
+
+ *psgl = cpu_to_le32((u32) tmplow);
+ *psgu |= cpu_to_le32((u32) tmphi);
+ break;
+ case PPC4XX_XOR_ID:
+ xor_hw_desc = desc->hw_desc;
+ xor_hw_desc->cbtal = addrl;
+ xor_hw_desc->cbtah |= addrh;
+ break;
+ }
+}
+
+/**
+ * ppc4xx_desc_set_byte_count - set number of data bytes involved
+ * into the operation
+ */
+static void ppc4xx_desc_set_byte_count(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan,
+ u32 byte_count)
+{
+ struct dma_cdb *dma_hw_desc;
+ struct xor_cb *xor_hw_desc;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ dma_hw_desc = desc->hw_desc;
+ dma_hw_desc->cnt = cpu_to_le32(byte_count);
+ break;
+ case PPC4XX_XOR_ID:
+ xor_hw_desc = desc->hw_desc;
+ xor_hw_desc->cbbc = byte_count;
+ break;
+ }
+}
+
+/**
+ * ppc4xx_desc_set_rxor_block_size - set RXOR block size
+ */
+static inline void ppc4xx_desc_set_rxor_block_size(u32 byte_count)
+{
+ /* assume that byte_count is aligned on the 512-boundary;
+ * thus write it directly to the register (bits 23:31 are
+ * reserved there).
+ */
+ dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_CF2H, byte_count);
+}
+
+/**
+ * ppc4xx_desc_set_dcheck - set CHECK pattern
+ */
+static void ppc4xx_desc_set_dcheck(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan, u8 * qword)
+{
+ struct dma_cdb *dma_hw_desc;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ dma_hw_desc = desc->hw_desc;
+ iowrite32(qword[0], &dma_hw_desc->sg3l);
+ iowrite32(qword[4], &dma_hw_desc->sg3u);
+ iowrite32(qword[8], &dma_hw_desc->sg2l);
+ iowrite32(qword[12], &dma_hw_desc->sg2u);
+ break;
+ default:
+ BUG();
+ }
+}
+
+/**
+ * ppc440spe_xor_set_link - set link address in xor CB
+ */
+static void ppc440spe_xor_set_link(struct ppc4xx_adma_desc_slot *prev_desc,
+ struct ppc4xx_adma_desc_slot *next_desc)
+{
+ struct xor_cb *xor_hw_desc = prev_desc->hw_desc;
+
+ if (unlikely(!next_desc || !(next_desc->phys))) {
+ printk(KERN_ERR "%s: next_desc=0x%p; next_desc->phys=0x%llx\n",
+ __func__, next_desc, next_desc ? next_desc->phys : 0);
+ BUG();
+ }
+
+ xor_hw_desc->cbs = 0;
+ xor_hw_desc->cblal = next_desc->phys;
+ xor_hw_desc->cblah = 0;
+ xor_hw_desc->cbc |= XOR_CBCR_LNK_BIT;
+}
+
+/**
+ * ppc4xx_desc_set_link - set the address of descriptor following this
+ * descriptor in chain
+ */
+static void ppc4xx_desc_set_link(struct ppc4xx_adma_chan *chan,
+ struct ppc4xx_adma_desc_slot *prev_desc,
+ struct ppc4xx_adma_desc_slot *next_desc)
+{
+ unsigned long flags;
+ struct ppc4xx_adma_desc_slot *tail = next_desc;
+
+ if (unlikely(!prev_desc || !next_desc ||
+ (prev_desc->hw_next && prev_desc->hw_next != next_desc))) {
+ /* If previous next is overwritten something is wrong.
+ * though we may refetch from append to initiate list
+ * processing; in this case - it's ok.
+ */
+ printk(KERN_ERR "%s: prev_desc=0x%p; next_desc=0x%p; "
+ "prev->hw_next=0x%p\n", __func__, prev_desc,
+ next_desc, prev_desc ? prev_desc->hw_next : 0);
+ BUG();
+ }
+
+ local_irq_save(flags);
+
+ /* do s/w chaining both for DMA and XOR descriptors */
+ prev_desc->hw_next = next_desc;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ break;
+ case PPC4XX_XOR_ID:
+ /* bind descriptor to the chain */
+ while (tail->hw_next)
+ tail = tail->hw_next;
+ xor_last_linked = tail;
+
+ if (prev_desc == xor_last_submit)
+ /* do not link to the last submitted CB */
+ break;
+ ppc440spe_xor_set_link(prev_desc, next_desc);
+ break;
+ }
+
+ local_irq_restore(flags);
+}
+
+/**
+ * ppc4xx_desc_get_src_addr - extract the source address from the descriptor
+ */
+static u32 ppc4xx_desc_get_src_addr(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan,
+ int src_idx)
+{
+ struct dma_cdb *dma_hw_desc;
+ struct xor_cb *xor_hw_desc;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ dma_hw_desc = desc->hw_desc;
+ /* May have 0, 1, 2, or 3 sources */
+ switch (dma_hw_desc->opc) {
+ case DMA_CDB_OPC_NO_OP:
+ case DMA_CDB_OPC_DFILL128:
+ return 0;
+ case DMA_CDB_OPC_DCHECK128:
+ if (unlikely(src_idx)) {
+ printk(KERN_ERR "%s: try to get %d source for"
+ " DCHECK128\n", __func__, src_idx);
+ BUG();
+ }
+ return le32_to_cpu(dma_hw_desc->sg1l);
+ case DMA_CDB_OPC_MULTICAST:
+ case DMA_CDB_OPC_MV_SG1_SG2:
+ if (unlikely(src_idx > 2)) {
+ printk(KERN_ERR "%s: try to get %d source from"
+ " DMA descr\n", __func__, src_idx);
+ BUG();
+ }
+ if (src_idx) {
+ if (le32_to_cpu(dma_hw_desc->sg1u) &
+ DMA_CUED_XOR_WIN_MSK) {
+ u8 region;
+
+ if (src_idx == 1)
+ return le32_to_cpu(dma_hw_desc->
+ sg1l) +
+ desc->unmap_len;
+
+ region =
+ (le32_to_cpu(dma_hw_desc->sg1u)) >>
+ DMA_CUED_REGION_OFF;
+
+ region &= DMA_CUED_REGION_MSK;
+ switch (region) {
+ case DMA_RXOR123:
+ return le32_to_cpu(dma_hw_desc->
+ sg1l) +
+ (desc->unmap_len << 1);
+ case DMA_RXOR124:
+ return le32_to_cpu(dma_hw_desc->
+ sg1l) +
+ (desc->unmap_len * 3);
+ case DMA_RXOR125:
+ return le32_to_cpu(dma_hw_desc->
+ sg1l) +
+ (desc->unmap_len << 2);
+ default:
+ printk(KERN_ERR
+ "%s: try to"
+ " get src3 for region %02x"
+ "PPC4XX_DESC_RXOR12?\n",
+ __func__, region);
+ BUG();
+ }
+ } else {
+ printk(KERN_ERR
+ "%s: try to get %d"
+ " source for non-cued descr\n",
+ __func__, src_idx);
+ BUG();
+ }
+ }
+ return le32_to_cpu(dma_hw_desc->sg1l);
+ default:
+ printk(KERN_ERR "%s: unknown OPC 0x%02x\n",
+ __func__, dma_hw_desc->opc);
+ BUG();
+ }
+ return le32_to_cpu(dma_hw_desc->sg1l);
+ case PPC4XX_XOR_ID:
+ /* May have up to 16 sources */
+ xor_hw_desc = desc->hw_desc;
+ return xor_hw_desc->ops[src_idx].l;
+ }
+ return 0;
+}
+
+/**
+ * ppc4xx_desc_get_dest_addr - extract the destination address from the
+ * descriptor
+ */
+static u32 ppc4xx_desc_get_dest_addr(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan, int idx)
+{
+ struct dma_cdb *dma_hw_desc;
+ struct xor_cb *xor_hw_desc;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ dma_hw_desc = desc->hw_desc;
+
+ if (likely(!idx))
+ return le32_to_cpu(dma_hw_desc->sg2l);
+ return le32_to_cpu(dma_hw_desc->sg3l);
+ case PPC4XX_XOR_ID:
+ xor_hw_desc = desc->hw_desc;
+ return xor_hw_desc->cbtal;
+ }
+ return 0;
+}
+
+/**
+ * ppc4xx_desc_get_src_num - extract the number of source addresses from
+ * the descriptor
+ */
+static u32 ppc4xx_desc_get_src_num(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan)
+{
+ struct dma_cdb *dma_hw_desc;
+ struct xor_cb *xor_hw_desc;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ dma_hw_desc = desc->hw_desc;
+
+ switch (dma_hw_desc->opc) {
+ case DMA_CDB_OPC_NO_OP:
+ case DMA_CDB_OPC_DFILL128:
+ return 0;
+ case DMA_CDB_OPC_DCHECK128:
+ return 1;
+ case DMA_CDB_OPC_MV_SG1_SG2:
+ case DMA_CDB_OPC_MULTICAST:
+ /*
+ * Only for RXOR operations we have more than
+ * one source
+ */
+ if (le32_to_cpu(dma_hw_desc->sg1u) &
+ DMA_CUED_XOR_WIN_MSK) {
+ /* RXOR op, there are 2 or 3 sources */
+ if (((le32_to_cpu(dma_hw_desc->sg1u) >>
+ DMA_CUED_REGION_OFF) &
+ DMA_CUED_REGION_MSK) == DMA_RXOR12) {
+ /* RXOR 1-2 */
+ return 2;
+ } else {
+ /* RXOR 1-2-3/1-2-4/1-2-5 */
+ return 3;
+ }
+ }
+ return 1;
+ default:
+ printk(KERN_ERR "%s: unknown OPC 0x%02x\n",
+ __func__, dma_hw_desc->opc);
+ BUG();
+ }
+ case PPC4XX_XOR_ID:
+ /* up to 16 sources */
+ xor_hw_desc = desc->hw_desc;
+ return xor_hw_desc->cbc & XOR_CDCR_OAC_MSK;
+ default:
+ BUG();
+ }
+ return 0;
+}
+
+/**
+ * ppc4xx_desc_get_dst_num - get the number of destination addresses in
+ * this descriptor
+ */
+static u32 ppc4xx_desc_get_dst_num(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan)
+{
+ struct dma_cdb *dma_hw_desc;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ /* May be 1 or 2 destinations */
+ dma_hw_desc = desc->hw_desc;
+ switch (dma_hw_desc->opc) {
+ case DMA_CDB_OPC_NO_OP:
+ case DMA_CDB_OPC_DCHECK128:
+ return 0;
+ case DMA_CDB_OPC_MV_SG1_SG2:
+ case DMA_CDB_OPC_DFILL128:
+ return 1;
+ case DMA_CDB_OPC_MULTICAST:
+ if (desc->dst_cnt == 2)
+ return 2;
+ else
+ return 1;
+ default:
+ printk(KERN_ERR "%s: unknown OPC 0x%02x\n",
+ __func__, dma_hw_desc->opc);
+ BUG();
+ }
+ case PPC4XX_XOR_ID:
+ /* Always only 1 destination */
+ return 1;
+ default:
+ BUG();
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * ADMA channel low-level routines
+ ******************************************************************************/
+
+static u32 ppc4xx_chan_get_current_descriptor(struct ppc4xx_adma_chan *chan);
+static void ppc4xx_chan_append(struct ppc4xx_adma_chan *chan);
+
+/**
+ * ppc4xx_adma_device_clear_eot_status - interrupt ack to XOR or DMA engine
+ */
+static void ppc4xx_adma_device_clear_eot_status(struct ppc4xx_adma_chan *chan)
+{
+ struct dma_regs *dma_reg;
+ struct xor_regs *xor_reg;
+ u8 *p = chan->device->dma_desc_pool_virt;
+ struct dma_cdb *cdb;
+ u32 rv, i;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ /* read FIFO to ack */
+ dma_reg = chan->device->dma_reg;
+ while ((rv = ioread32(&dma_reg->csfpl))) {
+ i = rv & DMA_CDB_ADDR_MSK;
+ cdb = (struct dma_cdb *)&p[i -
+ (u32) chan->device->
+ dma_desc_pool];
+
+ /* Clear opcode to ack. This is necessary for
+ * ZeroSum operations only
+ */
+ cdb->opc = 0;
+
+ if (test_bit(PPC4XX_RXOR_RUN, &ppc440spe_rxor_state)) {
+ /* probably this is a completed RXOR op,
+ * get pointer to CDB using the fact that
+ * physical and virtual addresses of CDB
+ * in pools have the same offsets
+ */
+ if (le32_to_cpu(cdb->sg1u) & DMA_CUED_XOR_BASE) {
+ /* this is a RXOR */
+ clear_bit(PPC4XX_RXOR_RUN,
+ &ppc440spe_rxor_state);
+ }
+ }
+
+ if (rv & DMA_CDB_STATUS_MSK) {
+ /* ZeroSum check failed
+ */
+ struct ppc4xx_adma_desc_slot *iter;
+ dma_addr_t phys = rv & ~DMA_CDB_MSK;
+
+ /*
+ * Update the status of corresponding
+ * descriptor.
+ */
+ list_for_each_entry(iter, &chan->chain,
+ chain_node) {
+ if (iter->phys == phys)
+ break;
+ }
+ /*
+ * if cannot find the corresponding
+ * slot it's a bug
+ */
+ BUG_ON(&iter->chain_node == &chan->chain);
+
+ if (iter->xor_check_result) {
+ if (test_bit(PPC4XX_DESC_PCHECK,
+ &iter->flags)) {
+ *iter->xor_check_result |=
+ SUM_CHECK_P_RESULT;
+ } else
+ if (test_bit(PPC4XX_DESC_QCHECK,
+ &iter->flags)) {
+ *iter->xor_check_result |=
+ SUM_CHECK_Q_RESULT;
+ } else
+ BUG();
+ }
+ }
+ }
+
+ rv = ioread32(&dma_reg->dsts);
+ if (rv) {
+ pr_err("DMA%d err status: 0x%x\n",
+ chan->device->id, rv);
+ /* write back to clear */
+ iowrite32(rv, &dma_reg->dsts);
+ }
+ break;
+ case PPC4XX_XOR_ID:
+ /* reset status bits to ack */
+ xor_reg = chan->device->xor_reg;
+ rv = ioread32be(&xor_reg->sr);
+ iowrite32be(rv, &xor_reg->sr);
+
+ if (rv &
+ (XOR_IE_ICBIE_BIT | XOR_IE_ICIE_BIT | XOR_IE_RPTIE_BIT)) {
+ if (rv & XOR_IE_RPTIE_BIT) {
+ /* Read PLB Timeout Error.
+ * Try to resubmit the CB
+ */
+ u32 val = ioread32be(&xor_reg->ccbalr);
+
+ iowrite32be(val, &xor_reg->cblalr);
+
+ val = ioread32be(&xor_reg->crsr);
+ iowrite32be(val | XOR_CRSR_XAE_BIT,
+ &xor_reg->crsr);
+ } else
+ pr_err("XOR ERR 0x%x status\n", rv);
+ break;
+ }
+
+ /* if the XORcore is idle, but there are unprocessed CBs
+ * then refetch the s/w chain here
+ */
+ if (!(ioread32be(&xor_reg->sr) & XOR_SR_XCP_BIT) &&
+ do_xor_refetch)
+ ppc4xx_chan_append(chan);
+ break;
+ }
+}
+
+/**
+ * ppc4xx_chan_is_busy - get the channel status
+ */
+static int ppc4xx_chan_is_busy(struct ppc4xx_adma_chan *chan)
+{
+ struct dma_regs *dma_reg;
+ struct xor_regs *xor_reg;
+ int busy = 0;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ dma_reg = chan->device->dma_reg;
+ /* if command FIFO's head and tail pointers are equal and
+ * status tail is the same as command, then channel is free
+ */
+ if (ioread16(&dma_reg->cpfhp) != ioread16(&dma_reg->cpftp) ||
+ ioread16(&dma_reg->cpftp) != ioread16(&dma_reg->csftp))
+ busy = 1;
+ break;
+ case PPC4XX_XOR_ID:
+ /* use the special status bit for the XORcore
+ */
+ xor_reg = chan->device->xor_reg;
+ busy = (ioread32be(&xor_reg->sr) & XOR_SR_XCP_BIT) ? 1 : 0;
+ break;
+ }
+
+ return busy;
+}
+
+/**
+ * ppc4xx_chan_set_first_xor_descriptor - init XORcore chain
+ */
+static void ppc4xx_chan_set_first_xor_descriptor(struct ppc4xx_adma_chan *chan,
+ struct ppc4xx_adma_desc_slot
+ *next_desc)
+{
+ struct xor_regs *xor_reg = chan->device->xor_reg;
+
+ if (ioread32be(&xor_reg->sr) & XOR_SR_XCP_BIT)
+ printk(KERN_INFO "%s: Warn: XORcore is running "
+ "when try to set the first CDB!\n", __func__);
+
+ xor_last_submit = xor_last_linked = next_desc;
+
+ iowrite32be(XOR_CRSR_64BA_BIT, &xor_reg->crsr);
+
+ iowrite32be(next_desc->phys, &xor_reg->cblalr);
+ iowrite32be(0, &xor_reg->cblahr);
+ iowrite32be(ioread32be(&xor_reg->cbcr) | XOR_CBCR_LNK_BIT,
+ &xor_reg->cbcr);
+
+ chan->hw_chain_inited = 1;
+}
+
+/**
+ * ppc440spe_dma_put_desc - put DMA0,1 descriptor to FIFO.
+ * called with irqs disabled
+ */
+static void ppc440spe_dma_put_desc(struct ppc4xx_adma_chan *chan,
+ struct ppc4xx_adma_desc_slot *desc)
+{
+ u32 pcdb;
+ struct dma_regs *dma_reg = chan->device->dma_reg;
+
+ pcdb = desc->phys;
+ if (!test_bit(PPC4XX_DESC_INT, &desc->flags))
+ pcdb |= DMA_CDB_NO_INT;
+
+ chan_last_sub[chan->device->id] = desc;
+
+ ADMA_LL_DBG(print_cb(chan, desc->hw_desc));
+
+ iowrite32(pcdb, &dma_reg->cpfpl);
+}
+
+/**
+ * ppc4xx_chan_append - update the h/w chain in the channel
+ */
+static void ppc4xx_chan_append(struct ppc4xx_adma_chan *chan)
+{
+ struct xor_regs *xor_reg;
+ struct ppc4xx_adma_desc_slot *iter;
+ struct xor_cb *xcb;
+ u32 cur_desc;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ cur_desc = ppc4xx_chan_get_current_descriptor(chan);
+
+ if (likely(cur_desc)) {
+ iter = chan_last_sub[chan->device->id];
+ BUG_ON(!iter);
+ } else {
+ /* first peer */
+ iter = chan_first_cdb[chan->device->id];
+ BUG_ON(!iter);
+ ppc440spe_dma_put_desc(chan, iter);
+ chan->hw_chain_inited = 1;
+ }
+
+ /* is there something new to append */
+ if (!iter->hw_next)
+ break;
+
+ /* flush descriptors from the s/w queue to fifo */
+ list_for_each_entry_continue(iter, &chan->chain, chain_node) {
+ ppc440spe_dma_put_desc(chan, iter);
+ if (!iter->hw_next)
+ break;
+ }
+ break;
+ case PPC4XX_XOR_ID:
+ /* update h/w links and refetch */
+ if (!xor_last_submit->hw_next)
+ break;
+
+ xor_reg = chan->device->xor_reg;
+ /* the last linked CDB has to generate an interrupt
+ * that we'd be able to append the next lists to h/w
+ * regardless of the XOR engine state at the moment of
+ * appending of these next lists
+ */
+ xcb = xor_last_linked->hw_desc;
+ xcb->cbc |= XOR_CBCR_CBCE_BIT;
+
+ if (!(ioread32be(&xor_reg->sr) & XOR_SR_XCP_BIT)) {
+ /* XORcore is idle. Refetch now */
+ do_xor_refetch = 0;
+ ppc440spe_xor_set_link(xor_last_submit,
+ xor_last_submit->hw_next);
+
+ ADMA_LL_DBG(print_cb_list(chan,
+ xor_last_submit->hw_next));
+
+ xor_last_submit = xor_last_linked;
+ iowrite32be(ioread32be(&xor_reg->crsr) |
+ XOR_CRSR_RCBE_BIT | XOR_CRSR_64BA_BIT,
+ &xor_reg->crsr);
+ } else {
+ /* XORcore is running. Refetch later in the handler */
+ do_xor_refetch = 1;
+ }
+
+ break;
+ }
+
+ local_irq_restore(flags);
+}
+
+/**
+ * ppc4xx_chan_get_current_descriptor - get the currently executed descriptor
+ */
+static u32 ppc4xx_chan_get_current_descriptor(struct ppc4xx_adma_chan *chan)
+{
+ struct dma_regs *dma_reg;
+ struct xor_regs *xor_reg;
+
+ if (unlikely(!chan->hw_chain_inited))
+ /* h/w descriptor chain is not initialized yet */
+ return 0;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ dma_reg = chan->device->dma_reg;
+ return ioread32(&dma_reg->acpl) & (~DMA_CDB_MSK);
+ case PPC4XX_XOR_ID:
+ xor_reg = chan->device->xor_reg;
+ return ioread32be(&xor_reg->ccbalr);
+ }
+ return 0;
+}
+
+/**
+ * ppc4xx_chan_run - enable the channel
+ */
+static void ppc4xx_chan_run(struct ppc4xx_adma_chan *chan)
+{
+ struct xor_regs *xor_reg;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ /* DMAs are always enabled, do nothing */
+ break;
+ case PPC4XX_XOR_ID:
+ /* drain write buffer */
+ xor_reg = chan->device->xor_reg;
+
+ /* fetch descriptor pointed to in <link> */
+ iowrite32be(XOR_CRSR_64BA_BIT | XOR_CRSR_XAE_BIT,
+ &xor_reg->crsr);
+ break;
+ }
+}
+
+/**
+ * ppc4xx_adma_device_estimate - estimate the efficiency of processing
+ * the operation given on this channel. It's assumed that 'chan' is
+ * capable to process 'cap' type of operation.
+ * @chan: channel to use
+ * @cap: type of transaction
+ * @dst_lst: array of destination pointers
+ * @dst_cnt: number of destination operands
+ * @src_lst: array of source pointers
+ * @src_cnt: number of source operands
+ * @src_sz: size of each source operand
+ */
+static int ppc4xx_adma_estimate(struct dma_chan *chan,
+ enum dma_transaction_type cap,
+ struct page **dst_lst, int dst_cnt,
+ struct page **src_lst, int src_cnt,
+ size_t src_sz)
+{
+ int ef = 1;
+
+ if (cap == DMA_PQ || cap == DMA_PQ_VAL) {
+ /* If RAID-6 capabilities were not activated don't try
+ * to use them
+ */
+ if (unlikely(!ppc440spe_r6_enabled))
+ return -1;
+ }
+ /* In the current implementation of ppc440spe ADMA driver it
+ * makes sense to pick out only pq case, because it may be
+ * processed:
+ * (1) either using Biskup method on DMA2;
+ * (2) or on DMA0/1.
+ * Thus we give a favour to (1) if the sources are suitable;
+ * else let it be processed on one of the DMA0/1 engines.
+ * In the sum_product case where destination is also the
+ * source process it on DMA0/1 only.
+ */
+ if (cap == DMA_PQ && chan->chan_id == PPC4XX_XOR_ID) {
+
+ if (dst_cnt == 1 && src_cnt == 2 && dst_lst[0] == src_lst[1])
+ ef = 0; /* sum_product case, process on DMA0/1 */
+ else if (ppc440spe_can_rxor(src_lst, src_cnt, src_sz))
+ ef = 3; /* override (DMA0/1 + idle) */
+ else
+ ef = 0; /* can't process on DMA2 if !rxor */
+ }
+
+ /* channel idleness increases the priority */
+ if (likely(ef) && !ppc4xx_chan_is_busy(to_ppc4xx_adma_chan(chan)))
+ ef++;
+
+ return ef;
+}
+
+struct dma_chan *ppc440spe_async_tx_find_best_channel(enum dma_transaction_type
+ cap,
+ struct page **dst_lst,
+ int dst_cnt,
+ struct page **src_lst,
+ int src_cnt,
+ size_t src_sz)
+{
+ struct dma_chan *best_chan = NULL;
+ struct ppc_dma_chan_ref *ref;
+ int best_rank = -1;
+
+ if (unlikely(!src_sz))
+ return NULL;
+ if (src_sz > PAGE_SIZE) {
+ /*
+ * should a user of the api ever pass > PAGE_SIZE requests
+ * we sort out cases where temporary page-sized buffers
+ * are used.
+ */
+ switch (cap) {
+ case DMA_PQ:
+ if (src_cnt == 1 && dst_lst[1] == src_lst[0])
+ return NULL;
+ if (src_cnt == 2 && dst_lst[1] == src_lst[1])
+ return NULL;
+ break;
+ case DMA_PQ_VAL:
+ case DMA_XOR_VAL:
+ return NULL;
+ default:
+ break;
+ }
+ }
+
+ list_for_each_entry(ref, &ppc4xx_adma_chan_list, node) {
+ if (dma_has_cap(cap, ref->chan->device->cap_mask)) {
+ int rank;
+
+ rank = ppc4xx_adma_estimate(ref->chan, cap, dst_lst,
+ dst_cnt, src_lst,
+ src_cnt, src_sz);
+ if (rank > best_rank) {
+ best_rank = rank;
+ best_chan = ref->chan;
+ }
+ }
+ }
+
+ return best_chan;
+}
+
+EXPORT_SYMBOL_GPL(ppc440spe_async_tx_find_best_channel);
+/**
+ * ppc4xx_adma_clean_slot - clean up CDB slot (if ack is set)
+ */
+static int ppc4xx_adma_clean_slot(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_adma_chan *chan)
+{
+ /* the client is allowed to attach dependent operations
+ * until 'ack' is set
+ */
+ if (!async_tx_test_ack(&desc->async_tx))
+ return 0;
+
+ /* leave the last descriptor in the chain
+ * so we can append to it
+ */
+ if (list_is_last(&desc->chain_node, &chan->chain) ||
+ desc->phys == ppc4xx_chan_get_current_descriptor(chan))
+ return 1;
+
+ if (chan->device->id != PPC4XX_XOR_ID) {
+ /* our DMA interrupt handler clears opc field of
+ * each processed descriptor. For all types of
+ * operations except for ZeroSum we do not actually
+ * need ack from the interrupt handler. ZeroSum is a
+ * special case since the result of this operation
+ * is available from the handler only, so if we see
+ * such type of descriptor (which is unprocessed yet)
+ * then leave it in chain.
+ */
+ struct dma_cdb *cdb = desc->hw_desc;
+ if (cdb->opc == DMA_CDB_OPC_DCHECK128)
+ return 1;
+ }
+
+ dev_dbg(chan->device->common.dev, "\tfree slot %llx: %d stride: %d\n",
+ desc->phys, desc->idx, desc->slots_per_op);
+
+ list_del(&desc->chain_node);
+ ppc4xx_adma_free_slots(desc, chan);
+ return 0;
+}
+
+/**
+ * ppc440spe_rxor_set_region_data -
+ */
+static void ppc440spe_rxor_set_region(struct ppc4xx_adma_desc_slot *desc,
+ u8 xor_arg_no, u32 mask)
+{
+ struct xor_cb *xcb = desc->hw_desc;
+
+ xcb->ops[xor_arg_no].h |= mask;
+}
+
+/**
+ * ppc440spe_rxor_set_src -
+ */
+static void ppc440spe_rxor_set_src(struct ppc4xx_adma_desc_slot *desc,
+ u8 xor_arg_no, dma_addr_t addr)
+{
+ struct xor_cb *xcb = desc->hw_desc;
+
+ xcb->ops[xor_arg_no].h |= DMA_CUED_XOR_BASE;
+ xcb->ops[xor_arg_no].l = addr;
+}
+
+/**
+ * ppc440spe_rxor_set_mult -
+ */
+static void ppc440spe_rxor_set_mult(struct ppc4xx_adma_desc_slot *desc,
+ u8 xor_arg_no, u8 idx, u8 mult)
+{
+ struct xor_cb *xcb = desc->hw_desc;
+
+ xcb->ops[xor_arg_no].h |= mult << (DMA_CUED_MULT1_OFF + idx * 8);
+}
+
+/**
+ * ppc4xx_adma_pq_set_src - set source address into descriptor
+ */
+static void ppc4xx_adma_pq_set_src(struct ppc4xx_adma_desc_slot *sw_desc,
+ dma_addr_t addr, int index)
+{
+ struct ppc4xx_adma_chan *chan;
+ dma_addr_t haddr = 0;
+ struct ppc4xx_adma_desc_slot *iter = NULL;
+
+ chan = to_ppc4xx_adma_chan(sw_desc->async_tx.chan);
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ /* DMA0,1 may do: WXOR, RXOR, RXOR+WXORs chain
+ */
+ if (test_bit(PPC4XX_DESC_RXOR, &sw_desc->flags)) {
+ /* RXOR-only or RXOR/WXOR operation */
+ int iskip = test_bit(PPC4XX_DESC_RXOR12,
+ &sw_desc->flags) ? 2 : 3;
+
+ if (index == 0) {
+ /* 1st slot (RXOR) */
+ /* setup sources region (R1-2-3, R1-2-4,
+ * or R1-2-5)
+ */
+ if (test_bit(PPC4XX_DESC_RXOR12,
+ &sw_desc->flags))
+ haddr = DMA_RXOR12 <<
+ DMA_CUED_REGION_OFF;
+ else if (test_bit(PPC4XX_DESC_RXOR123,
+ &sw_desc->flags))
+ haddr = DMA_RXOR123 <<
+ DMA_CUED_REGION_OFF;
+ else if (test_bit(PPC4XX_DESC_RXOR124,
+ &sw_desc->flags))
+ haddr = DMA_RXOR124 <<
+ DMA_CUED_REGION_OFF;
+ else if (test_bit(PPC4XX_DESC_RXOR125,
+ &sw_desc->flags))
+ haddr = DMA_RXOR125 <<
+ DMA_CUED_REGION_OFF;
+ else
+ BUG();
+ haddr |= DMA_CUED_XOR_BASE;
+ iter = ppc4xx_get_group_entry(sw_desc, 0);
+ } else if (index < iskip) {
+ /* 1st slot (RXOR)
+ * shall actually set source address only once
+ * instead of first <iskip>
+ */
+ iter = NULL;
+ } else {
+ /* 2nd/3d and next slots (WXOR);
+ * skip first slot with RXOR
+ */
+ haddr = DMA_CUED_XOR_HB;
+ iter = ppc4xx_get_group_entry(sw_desc,
+ index - iskip +
+ sw_desc->
+ dst_cnt);
+ }
+ } else {
+ int znum = 0;
+
+ /* WXOR-only operation; skip first slots with
+ * zeroing destinations
+ */
+ if (test_bit(PPC4XX_ZERO_P, &sw_desc->flags))
+ znum++;
+ if (test_bit(PPC4XX_ZERO_Q, &sw_desc->flags))
+ znum++;
+
+ haddr = DMA_CUED_XOR_HB;
+ iter = ppc4xx_get_group_entry(sw_desc, index + znum);
+ }
+
+ if (likely(iter)) {
+ ppc4xx_desc_set_src_addr(iter, chan, 0, haddr, addr);
+
+ if (!index &&
+ test_bit(PPC4XX_DESC_RXOR, &sw_desc->flags) &&
+ sw_desc->dst_cnt == 2) {
+ /* if we have two destinations for RXOR, then
+ * setup source in the second descr too
+ */
+ iter = ppc4xx_get_group_entry(sw_desc, 1);
+ ppc4xx_desc_set_src_addr(iter, chan, 0,
+ haddr, addr);
+ }
+ }
+ break;
+
+ case PPC4XX_XOR_ID:
+ /* DMA2 may do Biskup */
+ iter = sw_desc->group_head;
+ if (iter->dst_cnt == 2) {
+ /* both P & Q calculations required; set P src here */
+ ppc4xx_adma_dma2rxor_set_src(iter, index, addr);
+
+ /* this is for Q */
+ iter = ppc4xx_get_group_entry(sw_desc,
+ sw_desc->descs_per_op);
+ }
+ ppc4xx_adma_dma2rxor_set_src(iter, index, addr);
+ break;
+ }
+}
+
+/**
+ * ppc4xx_adma_pq_set_src_mult - set multiplication coefficient into
+ * descriptor for the PQXOR operation
+ */
+static void ppc4xx_adma_pq_set_src_mult(struct ppc4xx_adma_desc_slot
+ *sw_desc, unsigned char mult,
+ int index, int dst_pos)
+{
+ struct ppc4xx_adma_chan *chan;
+ u32 mult_idx, mult_dst;
+ struct ppc4xx_adma_desc_slot *iter = NULL, *iter1 = NULL;
+
+ chan = to_ppc4xx_adma_chan(sw_desc->async_tx.chan);
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ if (test_bit(PPC4XX_DESC_RXOR, &sw_desc->flags)) {
+ int region = test_bit(PPC4XX_DESC_RXOR12,
+ &sw_desc->flags) ? 2 : 3;
+
+ if (index < region) {
+ /* RXOR multipliers */
+ iter = ppc4xx_get_group_entry(sw_desc,
+ sw_desc->
+ dst_cnt - 1);
+ if (sw_desc->dst_cnt == 2)
+ iter1 =
+ ppc4xx_get_group_entry(sw_desc,
+ 0);
+
+ mult_idx = DMA_CUED_MULT1_OFF + (index << 3);
+ mult_dst = DMA_CDB_SG_SRC;
+ } else {
+ /* WXOR multiplier */
+ iter = ppc4xx_get_group_entry(sw_desc,
+ index -
+ region +
+ sw_desc->
+ dst_cnt);
+ mult_idx = DMA_CUED_MULT1_OFF;
+ mult_dst = dst_pos ? DMA_CDB_SG_DST2 :
+ DMA_CDB_SG_DST1;
+ }
+ } else {
+ int znum = 0;
+
+ /* WXOR-only;
+ * skip first slots with destinations (if ZERO_DST has
+ * place)
+ */
+ if (test_bit(PPC4XX_ZERO_P, &sw_desc->flags))
+ znum++;
+ if (test_bit(PPC4XX_ZERO_Q, &sw_desc->flags))
+ znum++;
+
+ iter = ppc4xx_get_group_entry(sw_desc, index + znum);
+ mult_idx = DMA_CUED_MULT1_OFF;
+ mult_dst = dst_pos ? DMA_CDB_SG_DST2 : DMA_CDB_SG_DST1;
+ }
+
+ if (likely(iter)) {
+ ppc4xx_desc_set_src_mult(iter, chan,
+ mult_idx, mult_dst, mult);
+
+ if (unlikely(iter1)) {
+ /* if we have two destinations for RXOR, then
+ * we've just set Q mult. Set-up P now.
+ */
+ ppc4xx_desc_set_src_mult(iter1, chan,
+ mult_idx, mult_dst,
+ 1);
+ }
+
+ }
+ break;
+
+ case PPC4XX_XOR_ID:
+ iter = sw_desc->group_head;
+ if (sw_desc->dst_cnt == 2) {
+ /* both P & Q calculations required; set P mult here */
+ ppc4xx_adma_dma2rxor_set_mult(iter, index, 1);
+
+ /* and then set Q mult */
+ iter = ppc4xx_get_group_entry(sw_desc,
+ sw_desc->descs_per_op);
+ }
+ ppc4xx_adma_dma2rxor_set_mult(iter, index, mult);
+ break;
+ }
+}
+
+/**
+ * ppc4xx_adma_pq_zero_sum_set_dest - set destination address into descriptor
+ * for the PQ_ZERO_SUM operation
+ */
+static void ppc4xx_adma_pqzero_sum_set_dest(struct ppc4xx_adma_desc_slot
+ *sw_desc, dma_addr_t paddr,
+ dma_addr_t qaddr)
+{
+ struct ppc4xx_adma_desc_slot *iter, *end;
+ struct ppc4xx_adma_chan *chan;
+ dma_addr_t addr = 0;
+ int idx;
+
+ chan = to_ppc4xx_adma_chan(sw_desc->async_tx.chan);
+
+ /* walk through the WXOR source list and set P/Q-destinations
+ * for each slot
+ */
+ idx = (paddr && qaddr) ? 2 : 1;
+ /* set end */
+ list_for_each_entry_reverse(end, &sw_desc->group_list, chain_node) {
+ if (!(--idx))
+ break;
+ }
+ /* set start */
+ idx = (paddr && qaddr) ? 2 : 1;
+ iter = ppc4xx_get_group_entry(sw_desc, idx);
+
+ if (paddr && qaddr) {
+ /* two destinations */
+ list_for_each_entry_from(iter, &sw_desc->group_list, chain_node) {
+ if (unlikely(iter == end))
+ break;
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ DMA_CUED_XOR_BASE, paddr,
+ 0);
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ DMA_CUED_XOR_BASE, qaddr,
+ 1);
+ }
+ } else {
+ /* one destination */
+ addr = paddr ? paddr : qaddr;
+ list_for_each_entry_from(iter, &sw_desc->group_list, chain_node) {
+ if (unlikely(iter == end))
+ break;
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ DMA_CUED_XOR_BASE, addr,
+ 0);
+ }
+ }
+
+ /* The remaining descriptors are DATACHECK. These have no need in
+ * destination. Actually, these destinations are used there
+ * as sources for check operation. So, set addr as source.
+ */
+ ppc4xx_desc_set_src_addr(end, chan, 0, 0, addr ? addr : paddr);
+
+ if (!addr) {
+ end = list_entry(end->chain_node.next,
+ struct ppc4xx_adma_desc_slot, chain_node);
+ ppc4xx_desc_set_src_addr(end, chan, 0, 0, qaddr);
+ }
+}
+
+static void ppc4xx_adma_pq_zero_op(struct ppc4xx_adma_desc_slot *iter,
+ struct ppc4xx_adma_chan *chan,
+ dma_addr_t addr)
+{
+ /* To clear destinations update the descriptor
+ * (P or Q depending on index) as follows:
+ * addr is destination (0 corresponds to SG2):
+ */
+ ppc4xx_desc_set_dest_addr(iter, chan, DMA_CUED_XOR_BASE, addr, 0);
+
+ /* ... and the addr is source: */
+ ppc4xx_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB, addr);
+
+ /* addr is always SG2 then the mult is always DST1 */
+ ppc4xx_desc_set_src_mult(iter, chan, DMA_CUED_MULT1_OFF,
+ DMA_CDB_SG_DST1, 1);
+}
+
+/**
+ * ppc4xx_adma_pq_set_dest - set destination address into descriptor
+ * for the PQXOR operation
+ */
+static void ppc4xx_adma_pq_set_dest(struct ppc4xx_adma_desc_slot *sw_desc,
+ dma_addr_t * addrs, unsigned long flags)
+{
+ struct ppc4xx_adma_desc_slot *iter;
+ struct ppc4xx_adma_chan *chan;
+ dma_addr_t paddr, qaddr;
+ dma_addr_t addr = 0, ppath, qpath;
+ int index = 0, i;
+
+ chan = to_ppc4xx_adma_chan(sw_desc->async_tx.chan);
+
+ if (flags & DMA_PREP_PQ_DISABLE_P)
+ paddr = 0;
+ else
+ paddr = addrs[0];
+
+ if (flags & DMA_PREP_PQ_DISABLE_Q)
+ qaddr = 0;
+ else
+ qaddr = addrs[1];
+
+ if (!paddr || !qaddr)
+ addr = paddr ? paddr : qaddr;
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ /* walk through the WXOR source list and set P/Q-destinations
+ * for each slot:
+ */
+ if (!test_bit(PPC4XX_DESC_RXOR, &sw_desc->flags)) {
+ /* This is WXOR-only chain; may have 1/2 zero descs */
+ if (test_bit(PPC4XX_ZERO_P, &sw_desc->flags))
+ index++;
+ if (test_bit(PPC4XX_ZERO_Q, &sw_desc->flags))
+ index++;
+
+ iter = ppc4xx_get_group_entry(sw_desc, index);
+ if (addr) {
+ /* one destination */
+ list_for_each_entry_from(iter,
+ &sw_desc->group_list,
+ chain_node)
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ DMA_CUED_XOR_BASE,
+ addr, 0);
+ } else {
+ /* two destinations */
+ list_for_each_entry_from(iter,
+ &sw_desc->group_list,
+ chain_node) {
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ DMA_CUED_XOR_BASE,
+ paddr, 0);
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ DMA_CUED_XOR_BASE,
+ qaddr, 1);
+ }
+ }
+
+ if (index) {
+ /* To clear destinations update the descriptor
+ * (1st,2nd, or both depending on flags)
+ */
+ index = 0;
+ if (test_bit(PPC4XX_ZERO_P, &sw_desc->flags)) {
+ iter =
+ ppc4xx_get_group_entry(sw_desc,
+ index++);
+ ppc4xx_adma_pq_zero_op(iter, chan,
+ paddr);
+ }
+
+ if (test_bit(PPC4XX_ZERO_Q, &sw_desc->flags)) {
+ iter =
+ ppc4xx_get_group_entry(sw_desc,
+ index++);
+ ppc4xx_adma_pq_zero_op(iter, chan,
+ qaddr);
+ }
+
+ return;
+ }
+ } else {
+ /* This is RXOR-only or RXOR/WXOR mixed chain */
+
+ /* If we want to include destination into calculations,
+ * then make dest addresses cued with mult=1 (XOR).
+ */
+ ppath = test_bit(PPC4XX_ZERO_P, &sw_desc->flags) ?
+ DMA_CUED_XOR_HB :
+ DMA_CUED_XOR_BASE | (1 << DMA_CUED_MULT1_OFF);
+ qpath = test_bit(PPC4XX_ZERO_Q, &sw_desc->flags) ?
+ DMA_CUED_XOR_HB :
+ DMA_CUED_XOR_BASE | (1 << DMA_CUED_MULT1_OFF);
+
+ /* Setup destination(s) in RXOR slot(s) */
+ iter = ppc4xx_get_group_entry(sw_desc, index++);
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ paddr ? ppath : qpath,
+ paddr ? paddr : qaddr, 0);
+ if (!addr) {
+ /* two destinations */
+ iter = ppc4xx_get_group_entry(sw_desc,
+ index++);
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ qpath, qaddr, 0);
+ }
+
+ if (test_bit(PPC4XX_DESC_WXOR, &sw_desc->flags)) {
+ /* Setup destination(s) in remaining WXOR
+ * slots
+ */
+ iter = ppc4xx_get_group_entry(sw_desc,
+ index);
+ if (addr) {
+ /* one destination */
+ list_for_each_entry_from(iter,
+ &sw_desc->
+ group_list,
+ chain_node)
+ ppc4xx_desc_set_dest_addr(iter,
+ chan,
+ DMA_CUED_XOR_BASE,
+ addr,
+ 0);
+
+ } else {
+ /* two destinations */
+ list_for_each_entry_from(iter,
+ &sw_desc->
+ group_list,
+ chain_node) {
+ ppc4xx_desc_set_dest_addr
+ (iter, chan,
+ DMA_CUED_XOR_BASE, paddr,
+ 0);
+ ppc4xx_desc_set_dest_addr
+ (iter, chan,
+ DMA_CUED_XOR_BASE, qaddr,
+ 1);
+ }
+ }
+ }
+
+ }
+ break;
+
+ case PPC4XX_XOR_ID:
+ /* DMA2 descriptors have only 1 destination, so there are
+ * two chains - one for each dest.
+ * If we want to include destination into calculations,
+ * then make dest addresses cued with mult=1 (XOR).
+ */
+ ppath = test_bit(PPC4XX_ZERO_P, &sw_desc->flags) ?
+ DMA_CUED_XOR_HB :
+ DMA_CUED_XOR_BASE | (1 << DMA_CUED_MULT1_OFF);
+
+ qpath = test_bit(PPC4XX_ZERO_Q, &sw_desc->flags) ?
+ DMA_CUED_XOR_HB :
+ DMA_CUED_XOR_BASE | (1 << DMA_CUED_MULT1_OFF);
+
+ iter = ppc4xx_get_group_entry(sw_desc, 0);
+ for (i = 0; i < sw_desc->descs_per_op; i++) {
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ paddr ? ppath : qpath,
+ paddr ? paddr : qaddr, 0);
+ iter = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ }
+
+ if (!addr) {
+ /* Two destinations; setup Q here */
+ iter = ppc4xx_get_group_entry(sw_desc,
+ sw_desc->descs_per_op);
+ for (i = 0; i < sw_desc->descs_per_op; i++) {
+ ppc4xx_desc_set_dest_addr(iter,
+ chan, qpath, qaddr,
+ 0);
+ iter =
+ list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ }
+ }
+
+ break;
+ }
+}
+
+/**
+ * ppc440spe_dma01_prep_mult -
+ * for Q operation where destination is also the source
+ */
+static struct ppc4xx_adma_desc_slot *ppc440spe_dma01_prep_mult(struct
+ ppc4xx_adma_chan
+ *ppc4xx_chan,
+ dma_addr_t * dst,
+ int dst_cnt,
+ dma_addr_t * src,
+ int src_cnt,
+ const unsigned
+ char *scf,
+ size_t len,
+ unsigned long
+ flags)
+{
+ struct ppc4xx_adma_desc_slot *sw_desc = NULL;
+ unsigned long op = 0;
+ int slot_cnt;
+
+ set_bit(PPC4XX_DESC_WXOR, &op);
+ slot_cnt = 2;
+
+ spin_lock_bh(&ppc4xx_chan->lock);
+
+ /* use WXOR, each descriptor occupies one slot */
+ sw_desc = ppc4xx_adma_alloc_slots(ppc4xx_chan, slot_cnt, 1);
+ if (sw_desc) {
+ struct ppc4xx_adma_chan *chan;
+ struct ppc4xx_adma_desc_slot *iter;
+ struct dma_cdb *hw_desc;
+
+ chan = to_ppc4xx_adma_chan(sw_desc->async_tx.chan);
+ set_bits(op, &sw_desc->flags);
+ sw_desc->src_cnt = src_cnt;
+ sw_desc->dst_cnt = dst_cnt;
+ /* First descriptor, zero data in the destination and copy it
+ * to q page using MULTICAST transfer.
+ */
+ iter = list_first_entry(&sw_desc->group_list,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
+ /* set 'next' pointer */
+ iter->hw_next = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ clear_bit(PPC4XX_DESC_INT, &iter->flags);
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MULTICAST;
+
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ DMA_CUED_XOR_BASE, dst[0], 0);
+ ppc4xx_desc_set_dest_addr(iter, chan, 0, dst[1], 1);
+ ppc4xx_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB,
+ src[0]);
+ ppc4xx_desc_set_byte_count(iter, ppc4xx_chan, len);
+ iter->unmap_len = len;
+
+ /*
+ * Second descriptor, multiply data from the q page
+ * and store the result in real destination.
+ */
+ iter = list_first_entry(&iter->chain_node,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
+ iter->hw_next = NULL;
+ if (flags & DMA_PREP_INTERRUPT)
+ set_bit(PPC4XX_DESC_INT, &iter->flags);
+ else
+ clear_bit(PPC4XX_DESC_INT, &iter->flags);
+
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+ ppc4xx_desc_set_src_addr(iter, chan, 0,
+ DMA_CUED_XOR_HB, dst[1]);
+ ppc4xx_desc_set_dest_addr(iter, chan,
+ DMA_CUED_XOR_BASE, dst[0], 0);
+
+ ppc4xx_desc_set_src_mult(iter, chan, DMA_CUED_MULT1_OFF,
+ DMA_CDB_SG_DST1, scf[0]);
+ ppc4xx_desc_set_byte_count(iter, ppc4xx_chan, len);
+ iter->unmap_len = len;
+ sw_desc->async_tx.flags = flags;
+ }
+
+ spin_unlock_bh(&ppc4xx_chan->lock);
+
+ return sw_desc;
+}
+
+/**
+ * ppc440spe_dma01_prep_sum_product -
+ * Dx = A*(P+Pxy) + B*(Q+Qxy) operation where destination is also
+ * the source.
+ */
+static struct ppc4xx_adma_desc_slot *ppc440spe_dma01_prep_sum_product(struct
+ ppc4xx_adma_chan
+ *ppc4xx_chan,
+ dma_addr_t
+ * dst,
+ dma_addr_t
+ * src,
+ int
+ src_cnt,
+ const
+ unsigned
+ char *scf,
+ size_t
+ len,
+ unsigned
+ long
+ flags)
+{
+ struct ppc4xx_adma_desc_slot *sw_desc = NULL;
+ unsigned long op = 0;
+ int slot_cnt;
+
+ set_bit(PPC4XX_DESC_WXOR, &op);
+ slot_cnt = 3;
+
+ spin_lock_bh(&ppc4xx_chan->lock);
+
+ /* WXOR, each descriptor occupies one slot */
+ sw_desc = ppc4xx_adma_alloc_slots(ppc4xx_chan, slot_cnt, 1);
+ if (sw_desc) {
+ struct ppc4xx_adma_chan *chan;
+ struct ppc4xx_adma_desc_slot *iter;
+ struct dma_cdb *hw_desc;
+
+ chan = to_ppc4xx_adma_chan(sw_desc->async_tx.chan);
+ set_bits(op, &sw_desc->flags);
+ sw_desc->src_cnt = src_cnt;
+ sw_desc->dst_cnt = 1;
+ /* 1st descriptor, src[1] data to q page and zero destination */
+ iter = list_first_entry(&sw_desc->group_list,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
+ iter->hw_next = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ clear_bit(PPC4XX_DESC_INT, &iter->flags);
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MULTICAST;
+
+ ppc4xx_desc_set_dest_addr(iter, chan, DMA_CUED_XOR_BASE,
+ *dst, 0);
+ ppc4xx_desc_set_dest_addr(iter, chan, 0,
+ ppc4xx_chan->qdest, 1);
+ ppc4xx_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB,
+ src[1]);
+ ppc4xx_desc_set_byte_count(iter, ppc4xx_chan, len);
+ iter->unmap_len = len;
+
+ /* 2nd descriptor, multiply src[1] data and store the
+ * result in destination */
+ iter = list_first_entry(&iter->chain_node,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
+ /* set 'next' pointer */
+ iter->hw_next = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ if (flags & DMA_PREP_INTERRUPT)
+ set_bit(PPC4XX_DESC_INT, &iter->flags);
+ else
+ clear_bit(PPC4XX_DESC_INT, &iter->flags);
+
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+ ppc4xx_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB,
+ ppc4xx_chan->qdest);
+ ppc4xx_desc_set_dest_addr(iter, chan, DMA_CUED_XOR_BASE,
+ *dst, 0);
+ ppc4xx_desc_set_src_mult(iter, chan, DMA_CUED_MULT1_OFF,
+ DMA_CDB_SG_DST1, scf[1]);
+ ppc4xx_desc_set_byte_count(iter, ppc4xx_chan, len);
+ iter->unmap_len = len;
+
+ /*
+ * 3rd descriptor, multiply src[0] data and xor it
+ * with destination
+ */
+ iter = list_first_entry(&iter->chain_node,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
+ iter->hw_next = NULL;
+ if (flags & DMA_PREP_INTERRUPT)
+ set_bit(PPC4XX_DESC_INT, &iter->flags);
+ else
+ clear_bit(PPC4XX_DESC_INT, &iter->flags);
+
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+ ppc4xx_desc_set_src_addr(iter, chan, 0, DMA_CUED_XOR_HB,
+ src[0]);
+ ppc4xx_desc_set_dest_addr(iter, chan, DMA_CUED_XOR_BASE,
+ *dst, 0);
+ ppc4xx_desc_set_src_mult(iter, chan, DMA_CUED_MULT1_OFF,
+ DMA_CDB_SG_DST1, scf[0]);
+ ppc4xx_desc_set_byte_count(iter, ppc4xx_chan, len);
+ iter->unmap_len = len;
+ sw_desc->async_tx.flags = flags;
+ }
+
+ spin_unlock_bh(&ppc4xx_chan->lock);
+
+ return sw_desc;
+}
+
+static struct ppc4xx_adma_desc_slot *ppc440spe_dma01_prep_pq(struct
+ ppc4xx_adma_chan
+ *ppc4xx_chan,
+ dma_addr_t * dst,
+ int dst_cnt,
+ dma_addr_t * src,
+ int src_cnt,
+ const unsigned char
+ *scf, size_t len,
+ unsigned long
+ flags)
+{
+ int slot_cnt;
+ struct ppc4xx_adma_desc_slot *sw_desc = NULL, *iter;
+ unsigned long op = 0;
+ unsigned char mult = 1;
+
+ pr_debug("%s: dst_cnt %d, src_cnt %d, len %d\n",
+ __func__, dst_cnt, src_cnt, len);
+ /* select operations WXOR/RXOR depending on the
+ * source addresses of operators and the number
+ * of destinations (RXOR support only Q-parity calculations)
+ */
+ set_bit(PPC4XX_DESC_WXOR, &op);
+ if (!test_and_set_bit(PPC4XX_RXOR_RUN, &ppc440spe_rxor_state)) {
+ /* no active RXOR;
+ * do RXOR if:
+ * - there are more than 1 source,
+ * - len is aligned on 512-byte boundary,
+ * - source addresses fit to one of 4 possible regions.
+ */
+ if (src_cnt > 1 &&
+ !(len & MQ0_CF2H_RXOR_BS_MASK) &&
+ (src[0] + len) == src[1]) {
+ /* may do RXOR R1 R2 */
+ set_bit(PPC4XX_DESC_RXOR, &op);
+ if (src_cnt != 2) {
+ /* may try to enhance region of RXOR */
+ if ((src[1] + len) == src[2]) {
+ /* do RXOR R1 R2 R3 */
+ set_bit(PPC4XX_DESC_RXOR123, &op);
+ } else if ((src[1] + len * 2) == src[2]) {
+ /* do RXOR R1 R2 R4 */
+ set_bit(PPC4XX_DESC_RXOR124, &op);
+ } else if ((src[1] + len * 3) == src[2]) {
+ /* do RXOR R1 R2 R5 */
+ set_bit(PPC4XX_DESC_RXOR125, &op);
+ } else {
+ /* do RXOR R1 R2 */
+ set_bit(PPC4XX_DESC_RXOR12, &op);
+ }
+ } else {
+ /* do RXOR R1 R2 */
+ set_bit(PPC4XX_DESC_RXOR12, &op);
+ }
+ }
+
+ if (!test_bit(PPC4XX_DESC_RXOR, &op)) {
+ /* can not do this operation with RXOR */
+ clear_bit(PPC4XX_RXOR_RUN, &ppc440spe_rxor_state);
+ } else {
+ /* can do; set block size right now */
+ ppc4xx_desc_set_rxor_block_size(len);
+ }
+ }
+
+ /* Number of necessary slots depends on operation type selected */
+ if (!test_bit(PPC4XX_DESC_RXOR, &op)) {
+ /* This is a WXOR only chain. Need descriptors for each
+ * source to GF-XOR them with WXOR, and need descriptors
+ * for each destination to zero them with WXOR
+ */
+ slot_cnt = src_cnt;
+
+ if (flags & DMA_PREP_ZERO_P) {
+ slot_cnt++;
+ set_bit(PPC4XX_ZERO_P, &op);
+ }
+ if (flags & DMA_PREP_ZERO_Q) {
+ slot_cnt++;
+ set_bit(PPC4XX_ZERO_Q, &op);
+ }
+ } else {
+ /* Need 1/2 descriptor for RXOR operation, and
+ * need (src_cnt - (2 or 3)) for WXOR of sources
+ * remained (if any)
+ */
+ slot_cnt = dst_cnt;
+
+ if (flags & DMA_PREP_ZERO_P)
+ set_bit(PPC4XX_ZERO_P, &op);
+ if (flags & DMA_PREP_ZERO_Q)
+ set_bit(PPC4XX_ZERO_Q, &op);
+
+ if (test_bit(PPC4XX_DESC_RXOR12, &op))
+ slot_cnt += src_cnt - 2;
+ else
+ slot_cnt += src_cnt - 3;
+
+ /* Thus we have either RXOR only chain or
+ * mixed RXOR/WXOR
+ */
+ if (slot_cnt == dst_cnt)
+ /* RXOR only chain */
+ clear_bit(PPC4XX_DESC_WXOR, &op);
+ }
+
+ spin_lock_bh(&ppc4xx_chan->lock);
+ /* for both RXOR/WXOR each descriptor occupies one slot */
+ sw_desc = ppc4xx_adma_alloc_slots(ppc4xx_chan, slot_cnt, 1);
+ if (sw_desc) {
+ ppc4xx_desc_init_dma01pq(sw_desc, dst_cnt, src_cnt,
+ flags, op);
+
+ /* setup dst/src/mult */
+ pr_debug("%s: set dst descriptor 0, 1: 0x%016llx, 0x%016llx\n",
+ __func__, dst[0], dst[1]);
+ ppc4xx_adma_pq_set_dest(sw_desc, dst, flags);
+ while (src_cnt--) {
+ ppc4xx_adma_pq_set_src(sw_desc, src[src_cnt],
+ src_cnt);
+
+ /* NOTE: "Multi = 0 is equivalent to = 1" as it
+ * stated in 440SPSPe_RAID6_Addendum_UM_1_17.pdf
+ * doesn't work for RXOR with DMA0/1! Instead, multi=0
+ * leads to zeroing source data after RXOR.
+ * So, for P case set-up mult=1 explicitly.
+ */
+ if (!(flags & DMA_PREP_PQ_DISABLE_Q))
+ mult = scf[src_cnt];
+ ppc4xx_adma_pq_set_src_mult(sw_desc,
+ mult, src_cnt,
+ dst_cnt - 1);
+ }
+
+ /* Setup byte count foreach slot just allocated */
+ sw_desc->async_tx.flags = flags;
+ list_for_each_entry(iter, &sw_desc->group_list, chain_node) {
+ ppc4xx_desc_set_byte_count(iter,
+ ppc4xx_chan, len);
+ iter->unmap_len = len;
+ }
+ }
+ spin_unlock_bh(&ppc4xx_chan->lock);
+
+ return sw_desc;
+}
+
+/**
+ * ppc4xx_dma2_pq_slot_count - get the number of slots necessary for
+ * DMA2 PQ operation
+ */
+static int ppc4xx_dma2_pq_slot_count(dma_addr_t * srcs, int src_cnt, size_t len)
+{
+ signed long long order = 0;
+ int state = 0;
+ int addr_count = 0;
+ int i;
+ for (i = 1; i < src_cnt; i++) {
+ dma_addr_t cur_addr = srcs[i];
+ dma_addr_t old_addr = srcs[i - 1];
+ switch (state) {
+ case 0:
+ if (cur_addr == old_addr + len) {
+ /* direct RXOR */
+ order = 1;
+ state = 1;
+ if (i == src_cnt - 1)
+ addr_count++;
+ } else if (old_addr == cur_addr + len) {
+ /* reverse RXOR */
+ order = -1;
+ state = 1;
+ if (i == src_cnt - 1)
+ addr_count++;
+ } else {
+ state = 3;
+ }
+ break;
+ case 1:
+ if (i == src_cnt - 2 || (order == -1
+ && cur_addr !=
+ old_addr - len)) {
+ order = 0;
+ state = 0;
+ addr_count++;
+ } else if (cur_addr == old_addr + len * order) {
+ state = 2;
+ if (i == src_cnt - 1)
+ addr_count++;
+ } else if (cur_addr == old_addr + 2 * len) {
+ state = 2;
+ if (i == src_cnt - 1)
+ addr_count++;
+ } else if (cur_addr == old_addr + 3 * len) {
+ state = 2;
+ if (i == src_cnt - 1)
+ addr_count++;
+ } else {
+ order = 0;
+ state = 0;
+ addr_count++;
+ }
+ break;
+ case 2:
+ order = 0;
+ state = 0;
+ addr_count++;
+ break;
+ }
+ if (state == 3)
+ break;
+ }
+ if (src_cnt <= 1 || (state != 1 && state != 2)) {
+ pr_err("%s: src_cnt=%d, state=%d, addr_count=%d, order=%lld\n",
+ __func__, src_cnt, state, addr_count, order);
+ for (i = 0; i < src_cnt; i++)
+ pr_err("\t[%d] 0x%llx \n", i, srcs[i]);
+ BUG();
+ }
+
+ return (addr_count + XOR_MAX_OPS - 1) / XOR_MAX_OPS;
+}
+
+static struct ppc4xx_adma_desc_slot *ppc440spe_dma2_prep_pq(struct
+ ppc4xx_adma_chan
+ *ppc4xx_chan,
+ dma_addr_t * dst,
+ int dst_cnt,
+ dma_addr_t * src,
+ int src_cnt,
+ const unsigned char
+ *scf, size_t len,
+ unsigned long flags)
+{
+ int slot_cnt, descs_per_op;
+ struct ppc4xx_adma_desc_slot *sw_desc = NULL, *iter;
+ unsigned long op = 0;
+ unsigned char mult = 1;
+
+ BUG_ON(!dst_cnt);
+ /*pr_debug("%s: dst_cnt %d, src_cnt %d, len %d\n",
+ __func__, dst_cnt, src_cnt, len); */
+
+ spin_lock_bh(&ppc4xx_chan->lock);
+ descs_per_op = ppc4xx_dma2_pq_slot_count(src, src_cnt, len);
+ if (descs_per_op < 0) {
+ spin_unlock_bh(&ppc4xx_chan->lock);
+ return NULL;
+ }
+
+ /* depending on number of sources we have 1 or 2 RXOR chains */
+ slot_cnt = descs_per_op * dst_cnt;
+
+ sw_desc = ppc4xx_adma_alloc_slots(ppc4xx_chan, slot_cnt, 1);
+ if (sw_desc) {
+ op = slot_cnt;
+ sw_desc->async_tx.flags = flags;
+ list_for_each_entry(iter, &sw_desc->group_list, chain_node) {
+ ppc4xx_desc_init_dma2pq(iter, dst_cnt, src_cnt,
+ --op ? 0 : flags);
+ ppc4xx_desc_set_byte_count(iter, ppc4xx_chan,
+ len);
+ iter->unmap_len = len;
+
+ ppc440spe_init_rxor_cursor(&(iter->rxor_cursor));
+ iter->rxor_cursor.len = len;
+ iter->descs_per_op = descs_per_op;
+ }
+ op = 0;
+ list_for_each_entry(iter, &sw_desc->group_list, chain_node) {
+ op++;
+ if (op % descs_per_op == 0)
+ ppc4xx_adma_init_dma2rxor_slot(iter, src,
+ src_cnt);
+ if (likely(!list_is_last(&iter->chain_node,
+ &sw_desc->group_list))) {
+ /* set 'next' pointer */
+ iter->hw_next =
+ list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ ppc440spe_xor_set_link(iter, iter->hw_next);
+ } else {
+ /* this is the last descriptor. */
+ iter->hw_next = NULL;
+ }
+ }
+
+ /* fixup head descriptor */
+ sw_desc->dst_cnt = dst_cnt;
+ if (flags & DMA_PREP_ZERO_P)
+ set_bit(PPC4XX_ZERO_P, &sw_desc->flags);
+ if (flags & DMA_PREP_ZERO_Q)
+ set_bit(PPC4XX_ZERO_Q, &sw_desc->flags);
+
+ /* setup dst/src/mult */
+ ppc4xx_adma_pq_set_dest(sw_desc, dst, flags);
+
+ while (src_cnt--) {
+ /* handle descriptors (if dst_cnt == 2) inside
+ * the ppc4xx_adma_pq_set_srcxxx() functions
+ */
+ ppc4xx_adma_pq_set_src(sw_desc, src[src_cnt],
+ src_cnt);
+ if (!(flags & DMA_PREP_PQ_DISABLE_Q))
+ mult = scf[src_cnt];
+ ppc4xx_adma_pq_set_src_mult(sw_desc,
+ mult, src_cnt,
+ dst_cnt - 1);
+ }
+ }
+ spin_unlock_bh(&ppc4xx_chan->lock);
+ ppc4xx_desc_set_rxor_block_size(len);
+ return sw_desc;
+}
+
+/**
+ * ppc4xx_adma_prep_dma_pq - prepare CDB (group) for a GF-XOR operation
+ */
+static struct dma_async_tx_descriptor *ppc4xx_adma_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 ppc4xx_adma_chan *ppc4xx_chan;
+ struct ppc4xx_adma_desc_slot *sw_desc = NULL;
+ int dst_cnt = 0;
+
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
+
+ ADMA_LL_DBG(prep_dma_pq_dbg(ppc4xx_chan->device->id,
+ dst, src, src_cnt));
+ BUG_ON(!len);
+ BUG_ON(unlikely(len > PPC4XX_ADMA_XOR_MAX_BYTE_COUNT));
+ BUG_ON(!src_cnt);
+
+ if (src_cnt == 1 && dst[1] == src[0]) {
+ dma_addr_t dest[2];
+
+ /* dst[1] is real destination (Q) */
+ dest[0] = dst[1];
+ /* this is the page to multicast source data to */
+ dest[1] = ppc4xx_chan->qdest;
+ sw_desc = ppc440spe_dma01_prep_mult(ppc4xx_chan,
+ dest, 2, src, src_cnt, scf,
+ len, flags);
+ return sw_desc ? &sw_desc->async_tx : NULL;
+ }
+
+ if (src_cnt == 2 && dst[1] == src[1]) {
+ sw_desc = ppc440spe_dma01_prep_sum_product(ppc4xx_chan,
+ &dst[1], src, 2, scf,
+ len, flags);
+ return sw_desc ? &sw_desc->async_tx : NULL;
+ }
+
+ if (!(flags & DMA_PREP_PQ_DISABLE_P)) {
+ BUG_ON(!dst[0]);
+ dst_cnt++;
+ flags |= DMA_PREP_ZERO_P;
+ }
+
+ if (!(flags & DMA_PREP_PQ_DISABLE_Q)) {
+ BUG_ON(!dst[1]);
+ dst_cnt++;
+ flags |= DMA_PREP_ZERO_Q;
+ }
+
+ BUG_ON(!dst_cnt);
+
+ dev_dbg(ppc4xx_chan->device->common.dev,
+ "ppc440spe adma%d: %s src_cnt: %d len: %u int_en: %d\n",
+ ppc4xx_chan->device->id, __func__, src_cnt, len,
+ flags & DMA_PREP_INTERRUPT ? 1 : 0);
+
+ switch (ppc4xx_chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ sw_desc = ppc440spe_dma01_prep_pq(ppc4xx_chan,
+ dst, dst_cnt, src, src_cnt,
+ scf, len, flags);
+ break;
+
+ case PPC4XX_XOR_ID:
+ sw_desc = ppc440spe_dma2_prep_pq(ppc4xx_chan,
+ dst, dst_cnt, src, src_cnt,
+ scf, len, flags);
+ break;
+ }
+
+ return sw_desc ? &sw_desc->async_tx : NULL;
+}
+
+/**
+ * ppc4xx_adma_prep_dma_pqzero_sum - prepare CDB group for
+ * a PQ_ZERO_SUM operation
+ */
+static struct dma_async_tx_descriptor *ppc4xx_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 ppc4xx_adma_chan *ppc4xx_chan;
+ struct ppc4xx_adma_desc_slot *sw_desc, *iter;
+ dma_addr_t pdest, qdest;
+ int slot_cnt, slots_per_op, idst, dst_cnt;
+
+ ppc4xx_chan = to_ppc4xx_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];
+
+ ADMA_LL_DBG(prep_dma_pqzero_sum_dbg(ppc4xx_chan->device->id,
+ src, src_cnt, scf));
+
+ /* 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(&ppc4xx_chan->lock);
+ sw_desc = ppc4xx_adma_alloc_slots(ppc4xx_chan, slot_cnt,
+ slots_per_op);
+ if (sw_desc) {
+ ppc4xx_desc_init_dma01pqzero_sum(sw_desc, dst_cnt, src_cnt);
+
+ /* Setup byte count for each slot just allocated */
+ sw_desc->async_tx.flags = flags;
+ list_for_each_entry(iter, &sw_desc->group_list, chain_node) {
+ ppc4xx_desc_set_byte_count(iter, ppc4xx_chan,
+ len);
+ iter->unmap_len = len;
+ }
+
+ if (pdest) {
+ struct dma_cdb *hw_desc;
+ struct ppc4xx_adma_chan *chan;
+
+ iter = sw_desc->group_head;
+ chan = to_ppc4xx_adma_chan(iter->async_tx.chan);
+ memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
+ iter->hw_next = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+ iter->src_cnt = 0;
+ iter->dst_cnt = 0;
+ ppc4xx_desc_set_dest_addr(iter, chan, 0,
+ ppc4xx_chan->pdest, 0);
+ ppc4xx_desc_set_src_addr(iter, chan, 0, 0, pdest);
+ ppc4xx_desc_set_byte_count(iter, ppc4xx_chan,
+ len);
+ iter->unmap_len = 0;
+ /* override pdest to preserve original P */
+ pdest = ppc4xx_chan->pdest;
+ }
+ if (qdest) {
+ struct dma_cdb *hw_desc;
+ struct ppc4xx_adma_chan *chan;
+
+ iter = list_first_entry(&sw_desc->group_list,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ chan = to_ppc4xx_adma_chan(iter->async_tx.chan);
+
+ if (pdest) {
+ iter = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ }
+
+ memset(iter->hw_desc, 0, sizeof(struct dma_cdb));
+ iter->hw_next = list_entry(iter->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ hw_desc = iter->hw_desc;
+ hw_desc->opc = DMA_CDB_OPC_MV_SG1_SG2;
+ iter->src_cnt = 0;
+ iter->dst_cnt = 0;
+ ppc4xx_desc_set_dest_addr(iter, chan, 0,
+ ppc4xx_chan->qdest, 0);
+ ppc4xx_desc_set_src_addr(iter, chan, 0, 0, qdest);
+ ppc4xx_desc_set_byte_count(iter, ppc4xx_chan,
+ len);
+ iter->unmap_len = 0;
+ /* override qdest to preserve original Q */
+ qdest = ppc4xx_chan->qdest;
+ }
+
+ /* Setup destinations for P/Q ops */
+ ppc4xx_adma_pqzero_sum_set_dest(sw_desc, pdest, qdest);
+
+ /* Setup zero QWORDs into DCHECK CDBs */
+ idst = dst_cnt;
+ list_for_each_entry_reverse(iter, &sw_desc->group_list,
+ chain_node) {
+ /*
+ * The last CDB corresponds to Q-parity check,
+ * the one before last CDB corresponds
+ * P-parity check
+ */
+ if (idst == DMA_DEST_MAX_NUM) {
+ if (idst == dst_cnt) {
+ set_bit(PPC4XX_DESC_QCHECK,
+ &iter->flags);
+ } else {
+ set_bit(PPC4XX_DESC_PCHECK,
+ &iter->flags);
+ }
+ } else {
+ if (qdest) {
+ set_bit(PPC4XX_DESC_QCHECK,
+ &iter->flags);
+ } else {
+ set_bit(PPC4XX_DESC_PCHECK,
+ &iter->flags);
+ }
+ }
+ iter->xor_check_result = pqres;
+
+ /*
+ * set it to zero, if check fail then result will
+ * be updated
+ */
+ *iter->xor_check_result = 0;
+ ppc4xx_desc_set_dcheck(iter, ppc4xx_chan,
+ ppc440spe_qword);
+
+ if (!(--dst_cnt))
+ break;
+ }
+
+ /* Setup sources and mults for P/Q ops */
+ list_for_each_entry_continue_reverse(iter, &sw_desc->group_list,
+ chain_node) {
+ struct ppc4xx_adma_chan *chan;
+ u32 mult_dst;
+
+ chan = to_ppc4xx_adma_chan(iter->async_tx.chan);
+ ppc4xx_desc_set_src_addr(iter, chan, 0,
+ DMA_CUED_XOR_HB,
+ src[src_cnt - 1]);
+ if (qdest) {
+ mult_dst = (dst_cnt - 1) ? DMA_CDB_SG_DST2 :
+ DMA_CDB_SG_DST1;
+ ppc4xx_desc_set_src_mult(iter, chan,
+ DMA_CUED_MULT1_OFF,
+ mult_dst,
+ scf[src_cnt - 1]);
+ }
+ if (!(--src_cnt))
+ break;
+ }
+ }
+ spin_unlock_bh(&ppc4xx_chan->lock);
+ return sw_desc ? &sw_desc->async_tx : NULL;
+}
+
+/**
+ * ppc4xx_adma_prep_dma_xor_zero_sum - prepare CDB group for
+ * XOR ZERO_SUM operation
+ */
+static struct dma_async_tx_descriptor *ppc4xx_adma_prep_dma_xor_zero_sum(struct
+ dma_chan
+ *chan,
+ dma_addr_t
+ * src,
+ unsigned
+ int
+ src_cnt,
+ size_t
+ len,
+ enum
+ sum_check_flags
+ *result,
+ unsigned
+ long
+ flags)
+{
+ struct dma_async_tx_descriptor *tx;
+ dma_addr_t pq[2];
+
+ /* validate P, disable Q */
+ pq[0] = src[0];
+ pq[1] = 0;
+ flags |= DMA_PREP_PQ_DISABLE_Q;
+
+ tx = ppc4xx_adma_prep_dma_pqzero_sum(chan, pq, &src[1],
+ src_cnt - 1, 0, len,
+ result, flags);
+ return tx;
+}
+
+/**
+ * ppc4xx_adma_set_dest - set destination address into descriptor
+ */
+static void ppc4xx_adma_set_dest(struct ppc4xx_adma_desc_slot *sw_desc,
+ dma_addr_t addr, int index)
+{
+ struct ppc4xx_adma_chan *chan;
+
+ BUG_ON(index >= sw_desc->dst_cnt);
+
+ chan = to_ppc4xx_adma_chan(sw_desc->async_tx.chan);
+
+ switch (chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ /* to do: support transfers lengths >
+ * ppc4xx_adma_DMA/XOR_MAX_BYTE_COUNT
+ */
+ ppc4xx_desc_set_dest_addr(sw_desc->group_head,
+ chan, 0, addr, index);
+ break;
+ case PPC4XX_XOR_ID:
+ sw_desc = ppc4xx_get_group_entry(sw_desc, index);
+ ppc4xx_desc_set_dest_addr(sw_desc, chan, 0, addr, index);
+ break;
+ }
+}
+
+/**
+ * ppc4xx_desc_set_xor_src_cnt - set source count into descriptor
+ */
+static inline void ppc4xx_desc_set_xor_src_cnt(struct ppc4xx_adma_desc_slot
+ *desc, int src_cnt)
+{
+ struct xor_cb *hw_desc = desc->hw_desc;
+
+ hw_desc->cbc &= ~XOR_CDCR_OAC_MSK;
+ hw_desc->cbc |= src_cnt;
+}
+
+/**
+ * ppc4xx_adma_memcpy_xor_set_src - set source address into descriptor
+ */
+static void ppc4xx_adma_memcpy_xor_set_src(struct ppc4xx_adma_desc_slot
+ *sw_desc, dma_addr_t addr,
+ int index)
+{
+ struct ppc4xx_adma_chan *chan;
+
+ chan = to_ppc4xx_adma_chan(sw_desc->async_tx.chan);
+ sw_desc = sw_desc->group_head;
+
+ if (likely(sw_desc))
+ ppc4xx_desc_set_src_addr(sw_desc, chan, index, 0, addr);
+}
+
+/**
+ * ppc4xx_adma_dma2rxor_inc_addr -
+ */
+static void ppc4xx_adma_dma2rxor_inc_addr(struct ppc4xx_adma_desc_slot *desc,
+ struct ppc4xx_rxor *cursor,
+ int index, int src_cnt)
+{
+ cursor->addr_count++;
+ if (index == src_cnt - 1) {
+ ppc4xx_desc_set_xor_src_cnt(desc, cursor->addr_count);
+ } else if (cursor->addr_count == XOR_MAX_OPS) {
+ ppc4xx_desc_set_xor_src_cnt(desc, cursor->addr_count);
+ cursor->addr_count = 0;
+ cursor->desc_count++;
+ }
+}
+
+/**
+ * ppc4xx_adma_init_dma2rxor_slot -
+ */
+static void ppc4xx_adma_init_dma2rxor_slot(
+ struct ppc4xx_adma_desc_slot *desc,
+ dma_addr_t *src, int src_cnt)
+{
+ int i;
+
+ /* initialize CDB */
+ for (i = 0; i < src_cnt; i++) {
+ ppc4xx_adma_dma2rxor_prep_src(desc, &desc->rxor_cursor, i,
+ desc->src_cnt, (u32)src[i]);
+ }
+}
+
+
+/**
+ * ppc4xx_adma_dma2rxor_prep_src - setup RXOR types in DMA2 CDB
+ */
+static int ppc4xx_adma_dma2rxor_prep_src(struct ppc4xx_adma_desc_slot *hdesc,
+ struct ppc4xx_rxor *cursor,
+ int index, int src_cnt, u32 addr)
+{
+ int rval = 0;
+ u32 sign;
+ struct ppc4xx_adma_desc_slot *desc = hdesc;
+ int i;
+
+ for (i = 0; i < cursor->desc_count; i++) {
+ desc = list_entry(hdesc->chain_node.next,
+ struct ppc4xx_adma_desc_slot, chain_node);
+ }
+
+ switch (cursor->state) {
+ case 0:
+ if (addr == cursor->addrl + cursor->len) {
+ /* direct RXOR */
+ cursor->state = 1;
+ cursor->xor_count++;
+ if (index == src_cnt - 1) {
+ ppc440spe_rxor_set_region(desc,
+ cursor->addr_count,
+ DMA_RXOR12 <<
+ DMA_CUED_REGION_OFF);
+ ppc4xx_adma_dma2rxor_inc_addr(desc, cursor,
+ index,
+ src_cnt);
+ }
+ } else if (cursor->addrl == addr + cursor->len) {
+ /* reverse RXOR */
+ cursor->state = 1;
+ cursor->xor_count++;
+ set_bit(cursor->addr_count, &desc->reverse_flags[0]);
+ if (index == src_cnt - 1) {
+ ppc440spe_rxor_set_region(desc,
+ cursor->addr_count,
+ DMA_RXOR12 <<
+ DMA_CUED_REGION_OFF);
+ ppc4xx_adma_dma2rxor_inc_addr(desc, cursor,
+ index,
+ src_cnt);
+ }
+ } else {
+ printk(KERN_ERR "Cannot build "
+ "DMA2 RXOR command block.\n");
+ BUG();
+ }
+ break;
+ case 1:
+ sign = test_bit(cursor->addr_count, desc->reverse_flags)
+ ? -1 : 1;
+ if (index == src_cnt - 2 || (sign == -1
+ && addr !=
+ cursor->addrl - 2 * cursor->len)) {
+ cursor->state = 0;
+ cursor->xor_count = 1;
+ cursor->addrl = addr;
+ ppc440spe_rxor_set_region(desc,
+ cursor->addr_count,
+ DMA_RXOR12 <<
+ DMA_CUED_REGION_OFF);
+ ppc4xx_adma_dma2rxor_inc_addr(desc, cursor, index,
+ src_cnt);
+ } else if (addr == cursor->addrl + 2 * sign * cursor->len) {
+ cursor->state = 2;
+ cursor->xor_count = 0;
+ ppc440spe_rxor_set_region(desc,
+ cursor->addr_count,
+ DMA_RXOR123 <<
+ DMA_CUED_REGION_OFF);
+ if (index == src_cnt - 1) {
+ ppc4xx_adma_dma2rxor_inc_addr(desc, cursor,
+ index,
+ src_cnt);
+ }
+ } else if (addr == cursor->addrl + 3 * cursor->len) {
+ cursor->state = 2;
+ cursor->xor_count = 0;
+ ppc440spe_rxor_set_region(desc,
+ cursor->addr_count,
+ DMA_RXOR124 <<
+ DMA_CUED_REGION_OFF);
+ if (index == src_cnt - 1) {
+ ppc4xx_adma_dma2rxor_inc_addr(desc, cursor,
+ index,
+ src_cnt);
+ }
+ } else if (addr == cursor->addrl + 4 * cursor->len) {
+ cursor->state = 2;
+ cursor->xor_count = 0;
+ ppc440spe_rxor_set_region(desc,
+ cursor->addr_count,
+ DMA_RXOR125 <<
+ DMA_CUED_REGION_OFF);
+ if (index == src_cnt - 1) {
+ ppc4xx_adma_dma2rxor_inc_addr(desc, cursor,
+ index,
+ src_cnt);
+ }
+ } else {
+ cursor->state = 0;
+ cursor->xor_count = 1;
+ cursor->addrl = addr;
+ ppc440spe_rxor_set_region(desc,
+ cursor->addr_count,
+ DMA_RXOR12 <<
+ DMA_CUED_REGION_OFF);
+ ppc4xx_adma_dma2rxor_inc_addr(desc, cursor, index,
+ src_cnt);
+ }
+ break;
+ case 2:
+ cursor->state = 0;
+ cursor->addrl = addr;
+ cursor->xor_count++;
+ if (index) {
+ ppc4xx_adma_dma2rxor_inc_addr(desc, cursor, index,
+ src_cnt);
+ }
+ break;
+ }
+
+ return rval;
+}
+
+/**
+ * ppc4xx_adma_dma2rxor_set_src - set RXOR source address; it's assumed that
+ * ppc4xx_adma_dma2rxor_prep_src() has already done prior this call
+ */
+static void ppc4xx_adma_dma2rxor_set_src(struct ppc4xx_adma_desc_slot *desc,
+ int index, dma_addr_t addr)
+{
+ struct xor_cb *xcb = desc->hw_desc;
+ int k = 0, op = 0, lop = 0;
+
+ /* get the RXOR operand which corresponds to index addr */
+ while (op <= index) {
+ lop = op;
+ if (k == XOR_MAX_OPS) {
+ k = 0;
+ desc = list_entry(desc->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ xcb = desc->hw_desc;
+
+ }
+ if ((xcb->ops[k++].h & (DMA_RXOR12 << DMA_CUED_REGION_OFF)) ==
+ (DMA_RXOR12 << DMA_CUED_REGION_OFF))
+ op += 2;
+ else
+ op += 3;
+ }
+
+ BUG_ON(k < 1);
+
+ if (test_bit(k - 1, desc->reverse_flags)) {
+ /* reverse operand order; put last op in RXOR group */
+ if (index == op - 1)
+ ppc440spe_rxor_set_src(desc, k - 1, addr);
+ } else {
+ /* direct operand order; put first op in RXOR group */
+ if (index == lop)
+ ppc440spe_rxor_set_src(desc, k - 1, addr);
+ }
+}
+
+/**
+ * ppc4xx_adma_dma2rxor_set_mult - set RXOR multipliers; it's assumed that
+ * ppc4xx_adma_dma2rxor_prep_src() has already done prior this call
+ */
+static void ppc4xx_adma_dma2rxor_set_mult(struct ppc4xx_adma_desc_slot *desc,
+ int index, u8 mult)
+{
+ struct xor_cb *xcb = desc->hw_desc;
+ int k = 0, op = 0, lop = 0;
+
+ /* get the RXOR operand which corresponds to index mult */
+ while (op <= index) {
+ lop = op;
+ if (k == XOR_MAX_OPS) {
+ k = 0;
+ desc = list_entry(desc->chain_node.next,
+ struct ppc4xx_adma_desc_slot,
+ chain_node);
+ xcb = desc->hw_desc;
+
+ }
+ if ((xcb->ops[k++].h & (DMA_RXOR12 << DMA_CUED_REGION_OFF)) ==
+ (DMA_RXOR12 << DMA_CUED_REGION_OFF))
+ op += 2;
+ else
+ op += 3;
+ }
+
+ BUG_ON(k < 1);
+ if (test_bit(k - 1, desc->reverse_flags)) {
+ /* reverse order */
+ ppc440spe_rxor_set_mult(desc, k - 1, op - index - 1, mult);
+ } else {
+ /* direct order */
+ ppc440spe_rxor_set_mult(desc, k - 1, index - lop, mult);
+ }
+}
+
+/**
+ * ppc440spe_init_rxor_cursor -
+ */
+static void ppc440spe_init_rxor_cursor(struct ppc4xx_rxor *cursor)
+{
+ memset(cursor, 0, sizeof(struct ppc4xx_rxor));
+ cursor->state = 2;
+}
+
+static void ppc4xx_adma_set_capabilities(struct ppc4xx_adma_device *adev)
+{
+ switch (adev->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ dma_cap_set(DMA_MEMCPY, adev->common.cap_mask);
+ dma_cap_set(DMA_INTERRUPT, adev->common.cap_mask);
+ dma_cap_set(DMA_MEMSET, adev->common.cap_mask);
+ dma_cap_set(DMA_PQ, adev->common.cap_mask);
+ dma_cap_set(DMA_PQ_VAL, adev->common.cap_mask);
+ dma_cap_set(DMA_XOR_VAL, adev->common.cap_mask);
+ break;
+ case PPC4XX_XOR_ID:
+ dma_cap_set(DMA_XOR, adev->common.cap_mask);
+ dma_cap_set(DMA_PQ, adev->common.cap_mask);
+ dma_cap_set(DMA_INTERRUPT, adev->common.cap_mask);
+ adev->common.cap_mask = adev->common.cap_mask;
+ break;
+ }
+
+ if (dma_has_cap(DMA_PQ, adev->common.cap_mask)) {
+ switch (adev->id) {
+ case PPC4XX_DMA0_ID:
+ dma_set_maxpq(&adev->common,
+ DMA0_FIFO_SIZE / sizeof(struct dma_cdb),
+ 0);
+ break;
+ case PPC4XX_DMA1_ID:
+ dma_set_maxpq(&adev->common,
+ DMA1_FIFO_SIZE / sizeof(struct dma_cdb),
+ 0);
+ break;
+ case PPC4XX_XOR_ID:
+ adev->common.max_pq = XOR_MAX_OPS * 3;
+ break;
+ }
+ }
+ if (dma_has_cap(DMA_PQ_VAL, adev->common.cap_mask)) {
+ switch (adev->id) {
+ case PPC4XX_DMA0_ID:
+ adev->common.max_pq = DMA0_FIFO_SIZE /
+ sizeof(struct dma_cdb);
+ break;
+ case PPC4XX_DMA1_ID:
+ adev->common.max_pq = DMA1_FIFO_SIZE /
+ sizeof(struct dma_cdb);
+ break;
+ }
+ }
+ if (dma_has_cap(DMA_XOR_VAL, adev->common.cap_mask)) {
+ switch (adev->id) {
+ case PPC4XX_DMA0_ID:
+ adev->common.max_xor = DMA0_FIFO_SIZE /
+ sizeof(struct dma_cdb);
+ break;
+ case PPC4XX_DMA1_ID:
+ adev->common.max_xor = DMA1_FIFO_SIZE /
+ sizeof(struct dma_cdb);
+ break;
+ }
+ }
+ pr_info("%s: AMCC(R) PPC440SP(E) ADMA Engine: "
+ "( %s%s%s%s%s%s%s)\n",
+ dev_name(adev->dev),
+ dma_has_cap(DMA_PQ, adev->common.cap_mask) ? "pq " : "",
+ dma_has_cap(DMA_PQ_VAL, adev->common.cap_mask) ? "pq_val " : "",
+ dma_has_cap(DMA_XOR, adev->common.cap_mask) ? "xor " : "",
+ dma_has_cap(DMA_XOR_VAL,
+ adev->common.cap_mask) ? "xor_val " : "",
+ dma_has_cap(DMA_MEMCPY, adev->common.cap_mask) ? "memcpy " : "",
+ dma_has_cap(DMA_MEMSET, adev->common.cap_mask) ? "memset " : "",
+ dma_has_cap(DMA_INTERRUPT,
+ adev->common.cap_mask) ? "intr " : "");
+}
+static int ppc4xx_adma_setup_irqs(struct ppc4xx_adma_device *adev,
+ struct ppc4xx_adma_chan *chan, int *initcode)
+{
+ struct platform_device *ofdev;
+ struct device_node *np;
+ int ret;
+
+ ofdev = container_of(adev->dev, struct platform_device, dev);
+ np = ofdev->dev.of_node;
+ if (adev->id != PPC4XX_XOR_ID) {
+ adev->err_irq = irq_of_parse_and_map(np, 1);
+ if (adev->err_irq == NO_IRQ) {
+ dev_warn(adev->dev, "no err irq resource?\n");
+ *initcode = PPC_ADMA_INIT_IRQ2;
+ adev->err_irq = -ENXIO;
+ } else
+ atomic_inc(&ppc4xx_adma_err_irq_ref);
+ } else {
+ adev->err_irq = -ENXIO;
+ }
+
+ adev->irq = irq_of_parse_and_map(np, 0);
+ if (adev->irq == NO_IRQ) {
+ dev_err(adev->dev, "no irq resource\n");
+ *initcode = PPC_ADMA_INIT_IRQ1;
+ ret = -ENXIO;
+ goto err_irq_map;
+ }
+ dev_dbg(adev->dev, "irq %d, err irq %d\n", adev->irq, adev->err_irq);
+
+ ret = request_irq(adev->irq, ppc4xx_adma_eot_handler,
+ 0, dev_driver_string(adev->dev), chan);
+ if (ret) {
+ dev_err(adev->dev, "can't request irq %d\n", adev->irq);
+ *initcode = PPC_ADMA_INIT_IRQ1;
+ ret = -EIO;
+ goto err_req1;
+ }
+
+ /* only DMA engines have a separate error IRQ
+ * so it's Ok if err_irq < 0 in XOR engine case.
+ */
+ if (adev->err_irq > 0) {
+ /* both DMA engines share common error IRQ */
+ ret = request_irq(adev->err_irq,
+ ppc4xx_adma_err_handler,
+ IRQF_SHARED,
+ dev_driver_string(adev->dev), chan);
+ if (ret) {
+ dev_err(adev->dev, "can't request irq %d\n",
+ adev->err_irq);
+ *initcode = PPC_ADMA_INIT_IRQ2;
+ ret = -EIO;
+ goto err_req2;
+ }
+ }
+
+ if (adev->id == PPC4XX_XOR_ID) {
+ /* enable XOR engine interrupts */
+ iowrite32be(XOR_IE_CBCIE_BIT | XOR_IE_ICBIE_BIT |
+ XOR_IE_ICIE_BIT | XOR_IE_RPTIE_BIT,
+ &adev->xor_reg->ier);
+ } else {
+ u32 mask, enable;
+
+ np = of_find_compatible_node(NULL, NULL, "ibm,i2o-440spe");
+ if (!np) {
+ pr_err("%s: can't find I2O device tree node\n",
+ __func__);
+ ret = -ENODEV;
+ goto err_req2;
+ }
+ adev->i2o_reg = of_iomap(np, 0);
+ if (!adev->i2o_reg) {
+ pr_err("%s: failed to map I2O registers\n", __func__);
+ of_node_put(np);
+ ret = -EINVAL;
+ goto err_req2;
+ }
+ of_node_put(np);
+ /* Unmask 'CS FIFO Attention' interrupts and
+ * enable generating interrupts on errors
+ */
+ enable = (adev->id == PPC4XX_DMA0_ID) ?
+ ~(I2O_IOPIM_P0SNE | I2O_IOPIM_P0EM) :
+ ~(I2O_IOPIM_P1SNE | I2O_IOPIM_P1EM);
+ mask = ioread32(&adev->i2o_reg->iopim) & enable;
+ iowrite32(mask, &adev->i2o_reg->iopim);
+ }
+ return 0;
+
+ err_req2:
+ free_irq(adev->irq, chan);
+ err_req1:
+ irq_dispose_mapping(adev->irq);
+ err_irq_map:
+ if (adev->err_irq > 0) {
+ if (atomic_dec_and_test(&ppc4xx_adma_err_irq_ref))
+ irq_dispose_mapping(adev->err_irq);
+ }
+ return ret;
+}
+
+static void ppc4xx_adma_release_irqs(struct ppc4xx_adma_device *adev,
+ struct ppc4xx_adma_chan *chan)
+{
+ u32 mask, disable;
+
+ if (adev->id == PPC4XX_XOR_ID) {
+ /* disable XOR engine interrupts */
+ mask = ioread32be(&adev->xor_reg->ier);
+ mask &= ~(XOR_IE_CBCIE_BIT | XOR_IE_ICBIE_BIT |
+ XOR_IE_ICIE_BIT | XOR_IE_RPTIE_BIT);
+ iowrite32be(mask, &adev->xor_reg->ier);
+ } else {
+ /* disable DMAx engine interrupts */
+ disable = (adev->id == PPC4XX_DMA0_ID) ?
+ (I2O_IOPIM_P0SNE | I2O_IOPIM_P0EM) :
+ (I2O_IOPIM_P1SNE | I2O_IOPIM_P1EM);
+ mask = ioread32(&adev->i2o_reg->iopim) | disable;
+ iowrite32(mask, &adev->i2o_reg->iopim);
+ }
+ free_irq(adev->irq, chan);
+ irq_dispose_mapping(adev->irq);
+ if (adev->err_irq > 0) {
+ free_irq(adev->err_irq, chan);
+ if (atomic_dec_and_test(&ppc4xx_adma_err_irq_ref)) {
+ irq_dispose_mapping(adev->err_irq);
+ iounmap(adev->i2o_reg);
+ }
+ }
+}
+static void ppc4xx_free_ref(struct ppc4xx_adma_device *adev,
+ struct platform_device *ofdev,
+ struct ppc4xx_adma_chan *chan)
+{
+ if (adev->id != PPC4XX_XOR_ID) {
+ dma_unmap_page(&ofdev->dev, chan->pdest,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ dma_unmap_page(&ofdev->dev, chan->qdest,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ __free_page(chan->pdest_page);
+ __free_page(chan->qdest_page);
+ }
+}
+static void ppc4xx_free_reg(struct ppc4xx_adma_device *adev)
+{
+ if (adev->id == PPC4XX_XOR_ID)
+ iounmap(adev->xor_reg);
+ else
+ iounmap(adev->dma_reg);
+}
+static int ppc4xx_get_cdb_size(struct ppc4xx_adma_chan *ppc4xx_chan)
+{
+ int db_sz;
+ if (ppc4xx_chan->device->id != PPC4XX_XOR_ID)
+ db_sz = sizeof(struct dma_cdb);
+ else
+ db_sz = sizeof(struct xor_cb);
+ return db_sz;
+}
+
+/*
+ * initialize the channel and the chain with a null operation
+ */
+static void ppc4xx_init_chan_null_op(struct ppc4xx_adma_chan *ppc4xx_chan)
+{
+ switch (ppc4xx_chan->device->id) {
+ case PPC4XX_DMA0_ID:
+ case PPC4XX_DMA1_ID:
+ ppc4xx_chan->hw_chain_inited = 0;
+ /* Use WXOR for self-testing */
+ if (!ppc440spe_r6_tchan)
+ ppc440spe_r6_tchan = ppc4xx_chan;
+ break;
+ case PPC4XX_XOR_ID:
+ ppc4xx_chan_start_null_xor(ppc4xx_chan);
+ break;
+ default:
+ BUG();
+ }
+}
+static int ppc4xx_adma_get_devid(struct platform_device *ofdev,
+ struct device_node *np)
+{
+ unsigned int id;
+ unsigned int len;
+ const unsigned int *idx;
+ if (of_device_is_compatible(np, "amcc,xor-accelerator")) {
+ id = PPC4XX_XOR_ID;
+ } else {
+ /* it is DMA0 or DMA1 */
+ idx = of_get_property(np, "cell-index", &len);
+ /* it is DMA0 or DMA1 */
+ if (!idx || (len != sizeof(u32))) {
+ dev_err(&ofdev->dev, "Device node %s has missing "
+ "or invalid cell-index property\n",
+ np->full_name);
+ return -EINVAL;
+ }
+ id = *idx;
+ }
+ return id;
+}
+static int ppc4xx_adma_get_pool_size(struct device_node *np, int id)
+{
+ unsigned int pool_size;
+ if (of_device_is_compatible(np, "amcc,xor-accelerator")) {
+ /* As far as the XOR engine is concerned, it does not
+ * use FIFOs but uses linked list. So there is no dependency
+ * between pool size to allocate and the engine configuration.
+ */
+ pool_size = PAGE_SIZE << 1;
+ } else {
+ /* DMA0,1 engines use FIFO to maintain CDBs, so we
+ * should allocate the pool accordingly to size of this
+ * FIFO. Thus, the pool size depends on the FIFO depth:
+ * how much CDBs pointers the FIFO may contain then so
+ * much CDBs we should provide in the pool.
+ * That is
+ * CDB size = 32B;
+ * CDBs number = (DMA0_FIFO_SIZE >> 3);
+ * Pool size = CDBs number * CDB size =
+ * = (DMA0_FIFO_SIZE >> 3) << 5 = DMA0_FIFO_SIZE << 2.
+ */
+ pool_size = (id == PPC4XX_DMA0_ID) ?
+ DMA0_FIFO_SIZE : DMA1_FIFO_SIZE;
+ pool_size <<= 2;
+ }
+ return pool_size;
+}
+static void ppc4xx_adma_init_hw(struct ppc4xx_adma_device *adev, void *regs)
+{
+ if (adev->id == PPC4XX_XOR_ID) {
+ adev->xor_reg = regs;
+ /* Reset XOR */
+ iowrite32be(XOR_CRSR_XASR_BIT, &adev->xor_reg->crsr);
+ iowrite32be(XOR_CRSR_64BA_BIT, &adev->xor_reg->crrr);
+ } else {
+ size_t fifo_size = (adev->id == PPC4XX_DMA0_ID) ?
+ DMA0_FIFO_SIZE : DMA1_FIFO_SIZE;
+ adev->dma_reg = regs;
+ /* DMAx_FIFO_SIZE is defined in bytes,
+ * <fsiz> - is defined in number of CDB pointers (8byte).
+ * DMA FIFO Length = CSlength + CPlength, where
+ * CSlength = CPlength = (fsiz + 1) * 8.
+ */
+ iowrite32(DMA_FIFO_ENABLE | ((fifo_size >> 3) - 2),
+ &adev->dma_reg->fsiz);
+ /* Configure DMA engine */
+ iowrite32(DMA_CFG_DXEPR_HP | DMA_CFG_DFMPP_HP | DMA_CFG_FALGN,
+ &adev->dma_reg->cfg);
+ /* Clear Status */
+ iowrite32(~0, &adev->dma_reg->dsts);
+ }
+}
+static int ppc4xx_create_helper_pages(struct ppc4xx_adma_device *adev,
+ struct platform_device *ofdev,
+ struct ppc4xx_adma_chan *chan)
+{
+ int ret = 0;
+ /* allocate and map helper pages for async validation or
+ * async_mult/async_sum_product operations on DMA0/1.
+ */
+ if (adev->id != PPC4XX_XOR_ID) {
+ chan->pdest_page = alloc_page(GFP_KERNEL);
+ chan->qdest_page = alloc_page(GFP_KERNEL);
+ if (!chan->pdest_page || !chan->qdest_page) {
+ if (chan->pdest_page)
+ __free_page(chan->pdest_page);
+ if (chan->qdest_page)
+ __free_page(chan->qdest_page);
+ ret = -ENOMEM;
+ goto err_page_alloc;
+ }
+ chan->pdest = dma_map_page(&ofdev->dev, chan->pdest_page, 0,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ chan->qdest = dma_map_page(&ofdev->dev, chan->qdest_page, 0,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ }
+ err_page_alloc:
+ return ret;
+}
+
+/*
+ * Common initialisation for RAID engines; allocate memory for
+ * DMAx FIFOs, perform configuration common for all DMA engines.
+ * Further DMA engine specific configuration is done at probe time.
+ */
+static int ppc440spe_configure_raid_devices(void)
+{
+ struct device_node *np;
+ struct resource i2o_res;
+ struct i2o_regs __iomem *i2o_reg;
+ dcr_host_t i2o_dcr_host;
+ unsigned int dcr_base, dcr_len;
+ int i, ret;
+
+ np = of_find_compatible_node(NULL, NULL, "ibm,i2o-440spe");
+ if (!np) {
+ pr_err("%s: can't find I2O device tree node\n", __func__);
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(np, 0, &i2o_res)) {
+ of_node_put(np);
+ return -EINVAL;
+ }
+
+ i2o_reg = of_iomap(np, 0);
+ if (!i2o_reg) {
+ pr_err("%s: failed to map I2O registers\n", __func__);
+ of_node_put(np);
+ return -EINVAL;
+ }
+
+ /* Get I2O DCRs base */
+ dcr_base = dcr_resource_start(np, 0);
+ dcr_len = dcr_resource_len(np, 0);
+ if (!dcr_base && !dcr_len) {
+ pr_err("%s: can't get DCR registers base/len!\n",
+ np->full_name);
+ of_node_put(np);
+ iounmap(i2o_reg);
+ return -ENODEV;
+ }
+
+ i2o_dcr_host = dcr_map(np, dcr_base, dcr_len);
+ if (!DCR_MAP_OK(i2o_dcr_host)) {
+ pr_err("%s: failed to map DCRs!\n", np->full_name);
+ of_node_put(np);
+ iounmap(i2o_reg);
+ return -ENODEV;
+ }
+ of_node_put(np);
+
+ /* Provide memory regions for DMA's FIFOs: I2O, DMA0 and DMA1 share
+ * the base address of FIFO memory space.
+ * Actually we need twice more physical memory than programmed in the
+ * <fsiz> register (because there are two FIFOs for each DMA: CP and CS)
+ */
+ ppc440spe_dma_fifo_buf = kmalloc((DMA0_FIFO_SIZE + DMA1_FIFO_SIZE) << 1,
+ GFP_KERNEL);
+ if (!ppc440spe_dma_fifo_buf) {
+ pr_err("%s: DMA FIFO buffer allocation failed.\n", __func__);
+ iounmap(i2o_reg);
+ dcr_unmap(i2o_dcr_host, dcr_len);
+ return -ENOMEM;
+ }
+
+ /*
+ * Configure h/w
+ */
+ /* Reset I2O/DMA */
+ mtdcri(SDR0, DCRN_SDR0_SRST, DCRN_SDR0_SRST_I2ODMA);
+ mtdcri(SDR0, DCRN_SDR0_SRST, 0);
+
+ /* Setup the base address of mmaped registers */
+ dcr_write(i2o_dcr_host, DCRN_I2O0_IBAH, (u32) (i2o_res.start >> 32));
+ dcr_write(i2o_dcr_host, DCRN_I2O0_IBAL, (u32) (i2o_res.start) |
+ I2O_REG_ENABLE);
+ dcr_unmap(i2o_dcr_host, dcr_len);
+
+ /* Setup FIFO memory space base address */
+ iowrite32(0, &i2o_reg->ifbah);
+ iowrite32(((u32) __pa(ppc440spe_dma_fifo_buf)), &i2o_reg->ifbal);
+
+ /* set zero FIFO size for I2O, so the whole
+ * ppc440spe_dma_fifo_buf is used by DMAs.
+ * DMAx_FIFOs will be configured while probe.
+ */
+ iowrite32(0, &i2o_reg->ifsiz);
+ iounmap(i2o_reg);
+
+ /* To prepare WXOR/RXOR functionality we need access to
+ * Memory Queue Module DCRs (finally it will be enabled
+ * via /sys interface of the ppc440spe ADMA driver).
+ */
+ np = of_find_compatible_node(NULL, NULL, "ibm,mq-440spe");
+ if (!np) {
+ pr_err("%s: can't find MQ device tree node\n", __func__);
+ ret = -ENODEV;
+ goto out_free;
+ }
+
+ /* Get MQ DCRs base */
+ dcr_base = dcr_resource_start(np, 0);
+ dcr_len = dcr_resource_len(np, 0);
+ if (!dcr_base && !dcr_len) {
+ pr_err("%s: can't get DCR registers base/len!\n",
+ np->full_name);
+ ret = -ENODEV;
+ goto out_mq;
+ }
+
+ ppc440spe_mq_dcr_host = dcr_map(np, dcr_base, dcr_len);
+ if (!DCR_MAP_OK(ppc440spe_mq_dcr_host)) {
+ pr_err("%s: failed to map DCRs!\n", np->full_name);
+ ret = -ENODEV;
+ goto out_mq;
+ }
+ of_node_put(np);
+ ppc440spe_mq_dcr_len = dcr_len;
+
+ /* Set HB alias */
+ dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_BAUH, DMA_CUED_XOR_HB);
+
+ /* Set:
+ * - LL transaction passing limit to 1;
+ * - Memory controller cycle limit to 1;
+ * - Galois Polynomial to 0x14d (default)
+ */
+ dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_CFBHL,
+ (1 << MQ0_CFBHL_TPLM) | (1 << MQ0_CFBHL_HBCL) |
+ (PPC4XX_DEFAULT_POLY << MQ0_CFBHL_POLY));
+
+ atomic_set(&ppc4xx_adma_err_irq_ref, 0);
+ for (i = 0; i < PPC4XX_ADMA_ENGINES_NUM; i++)
+ ppc4xx_adma_devices[i] = -1;
+
+ return 0;
+
+ out_mq:
+ of_node_put(np);
+ out_free:
+ kfree(ppc440spe_dma_fifo_buf);
+ return ret;
+}
+
+/**
+ * ppc440spe_test_callback - called when test operation has been done
+ */
+static void ppc440spe_test_callback(void *unused)
+{
+ complete(&ppc440spe_r6_test_comp);
+}
+
+/**
+ * ppc440spe_test_raid6 - test are RAID-6 capabilities enabled successfully.
+ * For this we just perform one WXOR operation with the same source
+ * and destination addresses, the GF-multiplier is 1; so if RAID-6
+ * capabilities are enabled then we'll get src/dst filled with zero.
+ */
+static int ppc440spe_test_raid6(struct ppc4xx_adma_chan *chan)
+{
+ struct ppc4xx_adma_desc_slot *sw_desc, *iter;
+ struct page *pg;
+ char *a;
+ dma_addr_t dma_addr, addrs[2];
+ unsigned long op = 0;
+ int rval = 0;
+
+ set_bit(PPC4XX_DESC_WXOR, &op);
+
+ pg = alloc_page(GFP_KERNEL);
+ if (!pg)
+ return -ENOMEM;
+
+ spin_lock_bh(&chan->lock);
+ sw_desc = ppc4xx_adma_alloc_slots(chan, 1, 1);
+ if (sw_desc) {
+ /* 1 src, 1 dsr, int_ena, WXOR */
+ ppc4xx_desc_init_dma01pq(sw_desc, 1, 1, 1, op);
+ list_for_each_entry(iter, &sw_desc->group_list, chain_node) {
+ ppc4xx_desc_set_byte_count(iter, chan, PAGE_SIZE);
+ iter->unmap_len = PAGE_SIZE;
+ }
+ } else {
+ rval = -EFAULT;
+ spin_unlock_bh(&chan->lock);
+ goto exit;
+ }
+ spin_unlock_bh(&chan->lock);
+
+ /* Fill the test page with ones */
+ memset(page_address(pg), 0xFF, PAGE_SIZE);
+ dma_addr = dma_map_page(chan->device->dev, pg, 0,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+ /* Setup addresses */
+ ppc4xx_adma_pq_set_src(sw_desc, dma_addr, 0);
+ ppc4xx_adma_pq_set_src_mult(sw_desc, 1, 0, 0);
+ addrs[0] = dma_addr;
+ addrs[1] = 0;
+ ppc4xx_adma_pq_set_dest(sw_desc, addrs, DMA_PREP_PQ_DISABLE_Q);
+
+ async_tx_ack(&sw_desc->async_tx);
+ sw_desc->async_tx.callback = ppc440spe_test_callback;
+ sw_desc->async_tx.callback_param = NULL;
+
+ init_completion(&ppc440spe_r6_test_comp);
+
+ ppc4xx_adma_tx_submit(&sw_desc->async_tx);
+ ppc4xx_adma_issue_pending(&chan->common);
+
+ wait_for_completion(&ppc440spe_r6_test_comp);
+
+ /* Now check if the test page is zeroed */
+ a = page_address(pg);
+ if ((*(u32 *) a) == 0 && memcmp(a, a + 4, PAGE_SIZE - 4) == 0) {
+ /* page is zero - RAID-6 enabled */
+ rval = 0;
+ } else {
+ /* RAID-6 was not enabled */
+ rval = -EINVAL;
+ }
+ exit:
+ __free_page(pg);
+ return rval;
+}
+
+/**
+ * ppc4xx_adma_remove - remove the asynch device
+ */
+static int __devexit ppc4xx_adma_remove(struct platform_device *ofdev)
+{
+ struct ppc4xx_adma_device *adev = dev_get_drvdata(&ofdev->dev);
+ struct device_node *np = ofdev->dev.of_node;
+ struct resource res;
+ struct dma_chan *chan, *_chan;
+ struct ppc_dma_chan_ref *ref, *_ref;
+ struct ppc4xx_adma_chan *ppc4xx_chan;
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+ if (adev->id < PPC4XX_ADMA_ENGINES_NUM)
+ ppc4xx_adma_devices[adev->id] = -1;
+
+ dma_async_device_unregister(&adev->common);
+
+ list_for_each_entry_safe(chan, _chan, &adev->common.channels,
+ device_node) {
+ ppc4xx_chan = to_ppc4xx_adma_chan(chan);
+ ppc4xx_adma_release_irqs(adev, ppc4xx_chan);
+ tasklet_kill(&ppc4xx_chan->irq_tasklet);
+ if (adev->id != PPC4XX_XOR_ID) {
+ dma_unmap_page(&ofdev->dev, ppc4xx_chan->pdest,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ dma_unmap_page(&ofdev->dev, ppc4xx_chan->qdest,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ __free_page(ppc4xx_chan->pdest_page);
+ __free_page(ppc4xx_chan->qdest_page);
+ }
+ list_for_each_entry_safe(ref, _ref, &ppc4xx_adma_chan_list,
+ node) {
+ if (ppc4xx_chan == to_ppc4xx_adma_chan(ref->chan)) {
+ list_del(&ref->node);
+ kfree(ref);
+ }
+ }
+ list_del(&chan->device_node);
+ kfree(ppc4xx_chan);
+ }
+
+ dma_free_coherent(adev->dev, adev->pool_size,
+ adev->dma_desc_pool_virt, adev->dma_desc_pool);
+ if (adev->id == PPC4XX_XOR_ID)
+ iounmap(adev->xor_reg);
+ else
+ iounmap(adev->dma_reg);
+ of_address_to_resource(np, 0, &res);
+ release_mem_region(res.start, resource_size(&res));
+ kfree(adev);
+ return 0;
+}
+
+/*
+ * /sys driver interface to enable h/w RAID-6 capabilities
+ * Files created in e.g. /sys/devices/plb.0/400100100.dma0/driver/
+ * directory are "devices", "enable" and "poly".
+ * "devices" shows available engines.
+ * "enable" is used to enable RAID-6 capabilities or to check
+ * whether these has been activated.
+ * "poly" allows setting/checking used polynomial (for PPC440SPe only).
+ */
+
+static ssize_t show_ppc440spe_devices(struct device_driver *dev, char *buf)
+{
+ ssize_t size = 0;
+ int i;
+
+ for (i = 0; i < PPC4XX_ADMA_ENGINES_NUM; i++) {
+ if (ppc4xx_adma_devices[i] == -1)
+ continue;
+ size += snprintf(buf + size, PAGE_SIZE - size,
+ "PPC440SP(E)-ADMA.%d: %s\n", i,
+ ppc_adma_errors[ppc4xx_adma_devices[i]]);
+ }
+ return size;
+}
+static void print_cb_list(struct ppc4xx_adma_chan *chan,
+ struct ppc4xx_adma_desc_slot *iter)
+{
+ for (; iter; iter = iter->hw_next)
+ print_cb(chan, iter->hw_desc);
+}
+
+static ssize_t show_ppc440spe_r6enable(struct device_driver *dev, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE,
+ "PPC440SP(e) RAID-6 capabilities are %sABLED.\n",
+ ppc440spe_r6_enabled ? "EN" : "DIS");
+}
+
+static ssize_t store_ppc440spe_r6enable(struct device_driver *dev,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+
+ if (!count || count > 11)
+ return -EINVAL;
+
+ if (!ppc440spe_r6_tchan)
+ return -EFAULT;
+
+ /* Write a key */
+ sscanf(buf, "%lx", &val);
+ dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_XORBA, val);
+ isync();
+
+ /* Verify whether it really works now */
+ if (ppc440spe_test_raid6(ppc440spe_r6_tchan) == 0) {
+ pr_info("PPC440SP(e) RAID-6 has been activated "
+ "successfully\n");
+ ppc440spe_r6_enabled = 1;
+ } else {
+ pr_info("PPC440SP(e) RAID-6 hasn't been activated!"
+ " Error key ?\n");
+ ppc440spe_r6_enabled = 0;
+ }
+ return count;
+}
+
+static ssize_t show_ppc440spe_r6poly(struct device_driver *dev, char *buf)
+{
+ ssize_t size = 0;
+ u32 reg;
+
+#ifdef CONFIG_440SP
+ /* 440SP has fixed polynomial */
+ reg = 0x4d;
+#else
+ reg = dcr_read(ppc440spe_mq_dcr_host, DCRN_MQ0_CFBHL);
+ reg >>= MQ0_CFBHL_POLY;
+ reg &= 0xFF;
+#endif
+
+ size = snprintf(buf, PAGE_SIZE, "PPC440SP(e) RAID-6 driver "
+ "uses 0x1%02x polynomial.\n", reg);
+ return size;
+}
+
+static ssize_t store_ppc440spe_r6poly(struct device_driver *dev,
+ const char *buf, size_t count)
+{
+ unsigned long reg, val;
+
+#ifdef CONFIG_440SP
+ /* 440SP uses default 0x14D polynomial only */
+ return -EINVAL;
+#endif
+
+ if (!count || count > 6)
+ return -EINVAL;
+
+ /* e.g., 0x14D or 0x11D */
+ sscanf(buf, "%lx", &val);
+
+ if (val & ~0x1FF)
+ return -EINVAL;
+
+ val &= 0xFF;
+ reg = dcr_read(ppc440spe_mq_dcr_host, DCRN_MQ0_CFBHL);
+ reg &= ~(0xFF << MQ0_CFBHL_POLY);
+ reg |= val << MQ0_CFBHL_POLY;
+ dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_CFBHL, reg);
+
+ return count;
+}
+
+static DRIVER_ATTR(devices, S_IRUGO, show_ppc440spe_devices, NULL);
+static DRIVER_ATTR(enable, S_IRUGO | S_IWUSR, show_ppc440spe_r6enable,
+ store_ppc440spe_r6enable);
+static DRIVER_ATTR(poly, S_IRUGO | S_IWUSR, show_ppc440spe_r6poly,
+ store_ppc440spe_r6poly);
+
+static const struct of_device_id ppc4xx_adma_of_match[] __devinitconst = {
+ {.compatible = "ibm,dma-440spe",},
+ {.compatible = "amcc,xor-accelerator",},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, ppc4xx_adma_of_match);
+static __init int ppc4xx_adma_init(void)
+{
+ int ret;
+
+ ret = ppc440spe_configure_raid_devices();
+ if (ret)
+ return ret;
+
+ ret = of_register_platform_driver(&ppc4xx_adma_driver);
+ if (ret) {
+ pr_err("%s: failed to register platform driver\n", __func__);
+ goto out_reg;
+ }
+
+ /* Initialization status */
+ ret = driver_create_file(&ppc4xx_adma_driver.driver,
+ &driver_attr_devices);
+ if (ret)
+ goto out_dev;
+
+ /* RAID-6 h/w enable entry */
+ ret = driver_create_file(&ppc4xx_adma_driver.driver,
+ &driver_attr_enable);
+ if (ret)
+ goto out_en;
+
+ /* GF polynomial to use */
+ ret = driver_create_file(&ppc4xx_adma_driver.driver,
+ &driver_attr_poly);
+ if (!ret)
+ return ret;
+
+ driver_remove_file(&ppc4xx_adma_driver.driver, &driver_attr_enable);
+ out_en:
+ driver_remove_file(&ppc4xx_adma_driver.driver, &driver_attr_devices);
+ out_dev:
+ /* User will not be able to enable h/w RAID-6 */
+ pr_err("%s: failed to create RAID-6 driver interface\n", __func__);
+ of_unregister_platform_driver(&ppc4xx_adma_driver);
+ out_reg:
+ dcr_unmap(ppc440spe_mq_dcr_host, ppc440spe_mq_dcr_len);
+ kfree(ppc440spe_dma_fifo_buf);
+ return ret;
+}
+
+static void __exit ppc4xx_adma_exit(void)
+{
+ driver_remove_file(&ppc4xx_adma_driver.driver, &driver_attr_poly);
+ driver_remove_file(&ppc4xx_adma_driver.driver, &driver_attr_enable);
+ driver_remove_file(&ppc4xx_adma_driver.driver, &driver_attr_devices);
+ of_unregister_platform_driver(&ppc4xx_adma_driver);
+ dcr_unmap(ppc440spe_mq_dcr_host, ppc440spe_mq_dcr_len);
+ kfree(ppc440spe_dma_fifo_buf);
+}
--
1.6.1.rc3
^ permalink raw reply related
* [PATCH 2/2] PPC4xx: Merge xor.h and dma.h into onefile ppc440spe-dma.h
From: tmarri @ 2010-09-18 1:42 UTC (permalink / raw)
To: linux-raid
Cc: herbert, neilb, yur, tmarri, linux-crypto, dan.j.williams,
linuxppc-dev
From: Tirumala Marri <tmarri@apm.com>
This patch combines drivers/dma/ppc4xx/xor.h and driver/dma/dma/ppc4xx/dma.h
into drivers/dma/ppc4xx/ppx440spe-dma.h .
Signed-off-by: Tirumala R Marri <tmarri@apm.com>
---
drivers/dma/ppc4xx/dma.h | 223 -------------------------
drivers/dma/ppc4xx/ppc440spe-dma.h | 318 ++++++++++++++++++++++++++++++++++++
drivers/dma/ppc4xx/xor.h | 110 -------------
3 files changed, 318 insertions(+), 333 deletions(-)
delete mode 100644 drivers/dma/ppc4xx/dma.h
create mode 100644 drivers/dma/ppc4xx/ppc440spe-dma.h
delete mode 100644 drivers/dma/ppc4xx/xor.h
diff --git a/drivers/dma/ppc4xx/dma.h b/drivers/dma/ppc4xx/dma.h
deleted file mode 100644
index bcde2df..0000000
--- a/drivers/dma/ppc4xx/dma.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 440SPe's DMA engines support header file
- *
- * 2006-2009 (C) DENX Software Engineering.
- *
- * Author: Yuri Tikhonov <yur@emcraft.com>
- *
- * This file is licensed under the term of the GNU General Public License
- * version 2. The program licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef _PPC440SPE_DMA_H
-#define _PPC440SPE_DMA_H
-
-#include <linux/types.h>
-
-/* Number of elements in the array with statical CDBs */
-#define MAX_STAT_DMA_CDBS 16
-/* Number of DMA engines available on the contoller */
-#define DMA_ENGINES_NUM 2
-
-/* Maximum h/w supported number of destinations */
-#define DMA_DEST_MAX_NUM 2
-
-/* FIFO's params */
-#define DMA0_FIFO_SIZE 0x1000
-#define DMA1_FIFO_SIZE 0x1000
-#define DMA_FIFO_ENABLE (1<<12)
-
-/* DMA Configuration Register. Data Transfer Engine PLB Priority: */
-#define DMA_CFG_DXEPR_LP (0<<26)
-#define DMA_CFG_DXEPR_HP (3<<26)
-#define DMA_CFG_DXEPR_HHP (2<<26)
-#define DMA_CFG_DXEPR_HHHP (1<<26)
-
-/* DMA Configuration Register. DMA FIFO Manager PLB Priority: */
-#define DMA_CFG_DFMPP_LP (0<<23)
-#define DMA_CFG_DFMPP_HP (3<<23)
-#define DMA_CFG_DFMPP_HHP (2<<23)
-#define DMA_CFG_DFMPP_HHHP (1<<23)
-
-/* DMA Configuration Register. Force 64-byte Alignment */
-#define DMA_CFG_FALGN (1 << 19)
-
-/*UIC0:*/
-#define D0CPF_INT (1<<12)
-#define D0CSF_INT (1<<11)
-#define D1CPF_INT (1<<10)
-#define D1CSF_INT (1<<9)
-/*UIC1:*/
-#define DMAE_INT (1<<9)
-
-/* I2O IOP Interrupt Mask Register */
-#define I2O_IOPIM_P0SNE (1<<3)
-#define I2O_IOPIM_P0EM (1<<5)
-#define I2O_IOPIM_P1SNE (1<<6)
-#define I2O_IOPIM_P1EM (1<<8)
-
-/* DMA CDB fields */
-#define DMA_CDB_MSK (0xF)
-#define DMA_CDB_64B_ADDR (1<<2)
-#define DMA_CDB_NO_INT (1<<3)
-#define DMA_CDB_STATUS_MSK (0x3)
-#define DMA_CDB_ADDR_MSK (0xFFFFFFF0)
-
-/* DMA CDB OpCodes */
-#define DMA_CDB_OPC_NO_OP (0x00)
-#define DMA_CDB_OPC_MV_SG1_SG2 (0x01)
-#define DMA_CDB_OPC_MULTICAST (0x05)
-#define DMA_CDB_OPC_DFILL128 (0x24)
-#define DMA_CDB_OPC_DCHECK128 (0x23)
-
-#define DMA_CUED_XOR_BASE (0x10000000)
-#define DMA_CUED_XOR_HB (0x00000008)
-
-#ifdef CONFIG_440SP
-#define DMA_CUED_MULT1_OFF 0
-#define DMA_CUED_MULT2_OFF 8
-#define DMA_CUED_MULT3_OFF 16
-#define DMA_CUED_REGION_OFF 24
-#define DMA_CUED_XOR_WIN_MSK (0xFC000000)
-#else
-#define DMA_CUED_MULT1_OFF 2
-#define DMA_CUED_MULT2_OFF 10
-#define DMA_CUED_MULT3_OFF 18
-#define DMA_CUED_REGION_OFF 26
-#define DMA_CUED_XOR_WIN_MSK (0xF0000000)
-#endif
-
-#define DMA_CUED_REGION_MSK 0x3
-#define DMA_RXOR123 0x0
-#define DMA_RXOR124 0x1
-#define DMA_RXOR125 0x2
-#define DMA_RXOR12 0x3
-
-/* S/G addresses */
-#define DMA_CDB_SG_SRC 1
-#define DMA_CDB_SG_DST1 2
-#define DMA_CDB_SG_DST2 3
-
-/*
- * DMAx engines Command Descriptor Block Type
- */
-struct dma_cdb {
- /*
- * Basic CDB structure (Table 20-17, p.499, 440spe_um_1_22.pdf)
- */
- u8 pad0[2]; /* reserved */
- u8 attr; /* attributes */
- u8 opc; /* opcode */
- u32 sg1u; /* upper SG1 address */
- u32 sg1l; /* lower SG1 address */
- u32 cnt; /* SG count, 3B used */
- u32 sg2u; /* upper SG2 address */
- u32 sg2l; /* lower SG2 address */
- u32 sg3u; /* upper SG3 address */
- u32 sg3l; /* lower SG3 address */
-};
-
-/*
- * DMAx hardware registers (p.515 in 440SPe UM 1.22)
- */
-struct dma_regs {
- 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;
-};
-
-/*
- * I2O hardware registers (p.528 in 440SPe UM 1.22)
- */
-struct i2o_regs {
- 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;
-};
-
-#endif /* _PPC440SPE_DMA_H */
diff --git a/drivers/dma/ppc4xx/ppc440spe-dma.h b/drivers/dma/ppc4xx/ppc440spe-dma.h
new file mode 100644
index 0000000..c52945e
--- /dev/null
+++ b/drivers/dma/ppc4xx/ppc440spe-dma.h
@@ -0,0 +1,318 @@
+/*
+ * 440SPe's DMA engines support header file
+ *
+ * 2006-2009 (C) DENX Software Engineering.
+ *
+ * Author: Yuri Tikhonov <yur@emcraft.com>
+ *
+ * This file is licensed under the term of the GNU General Public License
+ * version 2. The program licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _PPC440SPE_DMA_H
+#define _PPC440SPE_DMA_H
+
+#include <linux/types.h>
+
+/* Number of elements in the array with statical CDBs */
+#define MAX_STAT_DMA_CDBS 16
+/* Number of DMA engines available on the contoller */
+#define DMA_ENGINES_NUM 2
+
+/* Maximum h/w supported number of destinations */
+#define DMA_DEST_MAX_NUM 2
+
+/* FIFO's params */
+#define DMA0_FIFO_SIZE 0x1000
+#define DMA1_FIFO_SIZE 0x1000
+#define DMA_FIFO_ENABLE (1<<12)
+
+/* DMA Configuration Register. Data Transfer Engine PLB Priority: */
+#define DMA_CFG_DXEPR_LP (0<<26)
+#define DMA_CFG_DXEPR_HP (3<<26)
+#define DMA_CFG_DXEPR_HHP (2<<26)
+#define DMA_CFG_DXEPR_HHHP (1<<26)
+
+/* DMA Configuration Register. DMA FIFO Manager PLB Priority: */
+#define DMA_CFG_DFMPP_LP (0<<23)
+#define DMA_CFG_DFMPP_HP (3<<23)
+#define DMA_CFG_DFMPP_HHP (2<<23)
+#define DMA_CFG_DFMPP_HHHP (1<<23)
+
+/* DMA Configuration Register. Force 64-byte Alignment */
+#define DMA_CFG_FALGN (1 << 19)
+
+/*UIC0:*/
+#define D0CPF_INT (1<<12)
+#define D0CSF_INT (1<<11)
+#define D1CPF_INT (1<<10)
+#define D1CSF_INT (1<<9)
+/*UIC1:*/
+#define DMAE_INT (1<<9)
+
+/* I2O IOP Interrupt Mask Register */
+#define I2O_IOPIM_P0SNE (1<<3)
+#define I2O_IOPIM_P0EM (1<<5)
+#define I2O_IOPIM_P1SNE (1<<6)
+#define I2O_IOPIM_P1EM (1<<8)
+
+/* DMA CDB fields */
+#define DMA_CDB_MSK (0xF)
+#define DMA_CDB_64B_ADDR (1<<2)
+#define DMA_CDB_NO_INT (1<<3)
+#define DMA_CDB_STATUS_MSK (0x3)
+#define DMA_CDB_ADDR_MSK (0xFFFFFFF0)
+
+/* DMA CDB OpCodes */
+#define DMA_CDB_OPC_NO_OP (0x00)
+#define DMA_CDB_OPC_MV_SG1_SG2 (0x01)
+#define DMA_CDB_OPC_MULTICAST (0x05)
+#define DMA_CDB_OPC_DFILL128 (0x24)
+#define DMA_CDB_OPC_DCHECK128 (0x23)
+
+#define DMA_CUED_XOR_BASE (0x10000000)
+#define DMA_CUED_XOR_HB (0x00000008)
+
+#ifdef CONFIG_440SP
+#define DMA_CUED_MULT1_OFF 0
+#define DMA_CUED_MULT2_OFF 8
+#define DMA_CUED_MULT3_OFF 16
+#define DMA_CUED_REGION_OFF 24
+#define DMA_CUED_XOR_WIN_MSK (0xFC000000)
+#else
+#define DMA_CUED_MULT1_OFF 2
+#define DMA_CUED_MULT2_OFF 10
+#define DMA_CUED_MULT3_OFF 18
+#define DMA_CUED_REGION_OFF 26
+#define DMA_CUED_XOR_WIN_MSK (0xF0000000)
+#endif
+
+#define DMA_CUED_REGION_MSK 0x3
+#define DMA_RXOR123 0x0
+#define DMA_RXOR124 0x1
+#define DMA_RXOR125 0x2
+#define DMA_RXOR12 0x3
+
+/* S/G addresses */
+#define DMA_CDB_SG_SRC 1
+#define DMA_CDB_SG_DST1 2
+#define DMA_CDB_SG_DST2 3
+
+/*
+ * XOR Endgine definies
+ */
+
+/* Number of XOR engines available on the contoller */
+#define XOR_ENGINES_NUM 1
+
+/* Number of operands supported in the h/w */
+#define XOR_MAX_OPS 16
+
+/*
+ * XOR Command Block Control Register bits
+ */
+#define XOR_CBCR_LNK_BIT (1<<31) /* link present */
+#define XOR_CBCR_TGT_BIT (1<<30) /* target present */
+#define XOR_CBCR_CBCE_BIT (1<<29) /* command block compete enable */
+#define XOR_CBCR_RNZE_BIT (1<<28) /* result not zero enable */
+#define XOR_CBCR_XNOR_BIT (1<<15) /* XOR/XNOR */
+#define XOR_CDCR_OAC_MSK (0x7F) /* operand address count */
+
+/*
+ * XORCore Status Register bits
+ */
+#define XOR_SR_XCP_BIT (1<<31) /* core processing */
+#define XOR_SR_ICB_BIT (1<<17) /* invalid CB */
+#define XOR_SR_IC_BIT (1<<16) /* invalid command */
+#define XOR_SR_IPE_BIT (1<<15) /* internal parity error */
+#define XOR_SR_RNZ_BIT (1<<2) /* result not Zero */
+#define XOR_SR_CBC_BIT (1<<1) /* CB complete */
+#define XOR_SR_CBLC_BIT (1<<0) /* CB list complete */
+
+/*
+ * XORCore Control Set and Reset Register bits
+ */
+#define XOR_CRSR_XASR_BIT (1<<31) /* soft reset */
+#define XOR_CRSR_XAE_BIT (1<<30) /* enable */
+#define XOR_CRSR_RCBE_BIT (1<<29) /* refetch CB enable */
+#define XOR_CRSR_PAUS_BIT (1<<28) /* pause */
+#define XOR_CRSR_64BA_BIT (1<<27) /* 64/32 CB format */
+#define XOR_CRSR_CLP_BIT (1<<25) /* continue list processing */
+
+/*
+ * XORCore Interrupt Enable Register
+ */
+#define XOR_IE_ICBIE_BIT (1<<17) /* Invalid Command Block IRQ Enable */
+#define XOR_IE_ICIE_BIT (1<<16) /* Invalid Command IRQ Enable */
+#define XOR_IE_RPTIE_BIT (1<<14) /* Read PLB Timeout Error IRQ Enable */
+#define XOR_IE_CBCIE_BIT (1<<1) /* CB complete interrupt enable */
+#define XOR_IE_CBLCI_BIT (1<<0) /* CB list complete interrupt enable */
+/*
+ * DMAx engines Command Descriptor Block Type
+ */
+struct dma_cdb {
+ /*
+ * Basic CDB structure (Table 20-17, p.499, 440spe_um_1_22.pdf)
+ */
+ u8 pad0[2]; /* reserved */
+ u8 attr; /* attributes */
+ u8 opc; /* opcode */
+ u32 sg1u; /* upper SG1 address */
+ u32 sg1l; /* lower SG1 address */
+ u32 cnt; /* SG count, 3B used */
+ u32 sg2u; /* upper SG2 address */
+ u32 sg2l; /* lower SG2 address */
+ u32 sg3u; /* upper SG3 address */
+ u32 sg3l; /* lower SG3 address */
+};
+
+/*
+ * DMAx hardware registers (p.515 in 440SPe UM 1.22)
+ */
+struct dma_regs {
+ 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;
+};
+
+/*
+ * I2O hardware registers (p.528 in 440SPe UM 1.22)
+ */
+struct i2o_regs {
+ 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;
+};
+
+/*
+ * XOR Accelerator engine Command Block Type
+ */
+struct xor_cb {
+ /*
+ * Basic 64-bit format XOR CB (Table 19-1, p.463, 440spe_um_1_22.pdf)
+ */
+ u32 cbc; /* control */
+ u32 cbbc; /* byte count */
+ u32 cbs; /* status */
+ u8 pad0[4]; /* reserved */
+ u32 cbtah; /* target address high */
+ u32 cbtal; /* target address low */
+ u32 cblah; /* link address high */
+ u32 cblal; /* link address low */
+ struct {
+ u32 h;
+ u32 l;
+ } __attribute__ ((packed)) ops[16];
+} __attribute__ ((packed));
+
+/*
+ * XOR hardware registers Table 19-3, UM 1.22
+ */
+struct xor_regs {
+ u32 op_ar[16][2]; /* operand address[0]-high,[1]-low registers */
+ u8 pad0[352]; /* reserved */
+ u32 cbcr; /* CB control register */
+ u32 cbbcr; /* CB byte count register */
+ u32 cbsr; /* CB status register */
+ u8 pad1[4]; /* reserved */
+ u32 cbtahr; /* operand target address high register */
+ u32 cbtalr; /* operand target address low register */
+ u32 cblahr; /* CB link address high register */
+ u32 cblalr; /* CB link address low register */
+ u32 crsr; /* control set register */
+ u32 crrr; /* control reset register */
+ u32 ccbahr; /* current CB address high register */
+ u32 ccbalr; /* current CB address low register */
+ u32 plbr; /* PLB configuration register */
+ u32 ier; /* interrupt enable register */
+ u32 pecr; /* parity error count register */
+ u32 sr; /* status register */
+ u32 revidr; /* revision ID register */
+};
+
+#endif /* _PPC440SPE_XOR_H */
diff --git a/drivers/dma/ppc4xx/xor.h b/drivers/dma/ppc4xx/xor.h
deleted file mode 100644
index daed738..0000000
--- a/drivers/dma/ppc4xx/xor.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 440SPe's XOR engines support header file
- *
- * 2006-2009 (C) DENX Software Engineering.
- *
- * Author: Yuri Tikhonov <yur@emcraft.com>
- *
- * This file is licensed under the term of the GNU General Public License
- * version 2. The program licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef _PPC440SPE_XOR_H
-#define _PPC440SPE_XOR_H
-
-#include <linux/types.h>
-
-/* Number of XOR engines available on the contoller */
-#define XOR_ENGINES_NUM 1
-
-/* Number of operands supported in the h/w */
-#define XOR_MAX_OPS 16
-
-/*
- * XOR Command Block Control Register bits
- */
-#define XOR_CBCR_LNK_BIT (1<<31) /* link present */
-#define XOR_CBCR_TGT_BIT (1<<30) /* target present */
-#define XOR_CBCR_CBCE_BIT (1<<29) /* command block compete enable */
-#define XOR_CBCR_RNZE_BIT (1<<28) /* result not zero enable */
-#define XOR_CBCR_XNOR_BIT (1<<15) /* XOR/XNOR */
-#define XOR_CDCR_OAC_MSK (0x7F) /* operand address count */
-
-/*
- * XORCore Status Register bits
- */
-#define XOR_SR_XCP_BIT (1<<31) /* core processing */
-#define XOR_SR_ICB_BIT (1<<17) /* invalid CB */
-#define XOR_SR_IC_BIT (1<<16) /* invalid command */
-#define XOR_SR_IPE_BIT (1<<15) /* internal parity error */
-#define XOR_SR_RNZ_BIT (1<<2) /* result not Zero */
-#define XOR_SR_CBC_BIT (1<<1) /* CB complete */
-#define XOR_SR_CBLC_BIT (1<<0) /* CB list complete */
-
-/*
- * XORCore Control Set and Reset Register bits
- */
-#define XOR_CRSR_XASR_BIT (1<<31) /* soft reset */
-#define XOR_CRSR_XAE_BIT (1<<30) /* enable */
-#define XOR_CRSR_RCBE_BIT (1<<29) /* refetch CB enable */
-#define XOR_CRSR_PAUS_BIT (1<<28) /* pause */
-#define XOR_CRSR_64BA_BIT (1<<27) /* 64/32 CB format */
-#define XOR_CRSR_CLP_BIT (1<<25) /* continue list processing */
-
-/*
- * XORCore Interrupt Enable Register
- */
-#define XOR_IE_ICBIE_BIT (1<<17) /* Invalid Command Block IRQ Enable */
-#define XOR_IE_ICIE_BIT (1<<16) /* Invalid Command IRQ Enable */
-#define XOR_IE_RPTIE_BIT (1<<14) /* Read PLB Timeout Error IRQ Enable */
-#define XOR_IE_CBCIE_BIT (1<<1) /* CB complete interrupt enable */
-#define XOR_IE_CBLCI_BIT (1<<0) /* CB list complete interrupt enable */
-
-/*
- * XOR Accelerator engine Command Block Type
- */
-struct xor_cb {
- /*
- * Basic 64-bit format XOR CB (Table 19-1, p.463, 440spe_um_1_22.pdf)
- */
- u32 cbc; /* control */
- u32 cbbc; /* byte count */
- u32 cbs; /* status */
- u8 pad0[4]; /* reserved */
- u32 cbtah; /* target address high */
- u32 cbtal; /* target address low */
- u32 cblah; /* link address high */
- u32 cblal; /* link address low */
- struct {
- u32 h;
- u32 l;
- } __attribute__ ((packed)) ops[16];
-} __attribute__ ((packed));
-
-/*
- * XOR hardware registers Table 19-3, UM 1.22
- */
-struct xor_regs {
- u32 op_ar[16][2]; /* operand address[0]-high,[1]-low registers */
- u8 pad0[352]; /* reserved */
- u32 cbcr; /* CB control register */
- u32 cbbcr; /* CB byte count register */
- u32 cbsr; /* CB status register */
- u8 pad1[4]; /* reserved */
- u32 cbtahr; /* operand target address high register */
- u32 cbtalr; /* operand target address low register */
- u32 cblahr; /* CB link address high register */
- u32 cblalr; /* CB link address low register */
- u32 crsr; /* control set register */
- u32 crrr; /* control reset register */
- u32 ccbahr; /* current CB address high register */
- u32 ccbalr; /* current CB address low register */
- u32 plbr; /* PLB configuration register */
- u32 ier; /* interrupt enable register */
- u32 pecr; /* parity error count register */
- u32 sr; /* status register */
- u32 revidr; /* revision ID register */
-};
-
-#endif /* _PPC440SPE_XOR_H */
--
1.6.1.rc3
^ permalink raw reply related
* Re: [PATCH 1/2] powerpc: export ppc_tb_freq so that modules can reference it
From: Timur Tabi @ 2010-09-18 1:20 UTC (permalink / raw)
To: Josh Boyer; +Cc: kumar.gala, linux-watchdog, linuxppc-dev
In-Reply-To: <AANLkTikmfd=2N3GE1zpTqQ59583EEe1PDXggwHBUAj_5@mail.gmail.com>
On Fri, Sep 17, 2010 at 7:38 PM, Josh Boyer <jwboyer@gmail.com> wrote:
>> =A0unsigned long ppc_proc_freq;
>> =A0EXPORT_SYMBOL(ppc_proc_freq);
>> =A0unsigned long ppc_tb_freq;
>> +EXPORT_SYMBOL(ppc_tb_freq);
>
> EXPORT_SYMBOL_GPL probably, no?
I don't see any reason to limit it to GPL drivers. Not only that, but
then we'll have this:
EXPORT_SYMBOL(ppc_proc_freq);
EXPORT_SYMBOL_GPL(ppc_tb_freq);
That just looks dumb.
--=20
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: [PATCH 1/2] powerpc: export ppc_tb_freq so that modules can reference it
From: Josh Boyer @ 2010-09-18 0:38 UTC (permalink / raw)
To: Timur Tabi; +Cc: kumar.gala, linux-watchdog, linuxppc-dev
In-Reply-To: <1284764008-19469-1-git-send-email-timur@freescale.com>
On Fri, Sep 17, 2010 at 6:53 PM, Timur Tabi <timur@freescale.com> wrote:
> Export the global variable 'ppc_tb_freq', so that modules (like the Book-=
E
> watchdog driver) can use it.
>
> Signed-off-by: Timur Tabi <timur@freescale.com>
> ---
>
> This export is necessary for the Book-E watchdog driver to be compiled as=
a
> module. =A0Since ppc_proc_freq is already exported, I figured it's okay f=
or
> ppc_tb_freq to be exported as well.
>
> =A0arch/powerpc/kernel/time.c | =A0 =A01 +
> =A01 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
> index 8533b3b..49aa130 100644
> --- a/arch/powerpc/kernel/time.c
> +++ b/arch/powerpc/kernel/time.c
> @@ -163,6 +163,7 @@ static long timezone_offset;
> =A0unsigned long ppc_proc_freq;
> =A0EXPORT_SYMBOL(ppc_proc_freq);
> =A0unsigned long ppc_tb_freq;
> +EXPORT_SYMBOL(ppc_tb_freq);
EXPORT_SYMBOL_GPL probably, no?
josh
^ permalink raw reply
* Re: [PATCH 2/2] powerpc/watchdog: allow the e500 watchdog driver to be compiled as a module
From: Josh Boyer @ 2010-09-18 0:37 UTC (permalink / raw)
To: Timur Tabi; +Cc: kumar.gala, linux-watchdog, linuxppc-dev
In-Reply-To: <1284764008-19469-2-git-send-email-timur@freescale.com>
On Fri, Sep 17, 2010 at 6:53 PM, Timur Tabi <timur@freescale.com> wrote:
> Register the __init and __exit functions in the PowerPC e500 watchdog dri=
ver
> as module entry/exit functions, and modify the Kconfig entry.
>
> Add a .release method for the PowerPC e500 watchdog driver, so that the
> watchdog is disabled when the driver is closed.
This is used for more than just e500.
>
> Loosely based on original code from Jiang Yutang <b14898@freescale.com>.
>
> Signed-off-by: Timur Tabi <timur@freescale.com>
> ---
>
> This patch requires:
>
> =A0 =A0 =A0 =A0powerpc: export ppc_tb_freq so that modules can reference =
it
>
> =A0drivers/watchdog/Kconfig =A0 =A0 | =A0 =A05 ++++-
> =A0drivers/watchdog/booke_wdt.c | =A0 39 ++++++++++++++++++++++++++++++++=
+++++--
> =A02 files changed, 41 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 24efd8e..d9cf5a9 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -957,9 +957,12 @@ config PIKA_WDT
> =A0 =A0 =A0 =A0 =A0the Warp platform.
>
> =A0config BOOKE_WDT
> - =A0 =A0 =A0 bool "PowerPC Book-E Watchdog Timer"
> + =A0 =A0 =A0 tristate "PowerPC Book-E Watchdog Timer"
> =A0 =A0 =A0 =A0depends on BOOKE || 4xx
> =A0 =A0 =A0 =A0---help---
> + =A0 =A0 =A0 =A0 Watchdog driver for PowerPC e500 chips, such as the Fre=
escale
> + =A0 =A0 =A0 =A0 MPC85xx SOCs.
> +
Again, used for more than e500. That || 4xx in the depends statement
right above your addition isn't there for fun :).
josh
^ permalink raw reply
* [PATCH 2/2] powerpc/watchdog: allow the e500 watchdog driver to be compiled as a module
From: Timur Tabi @ 2010-09-17 22:53 UTC (permalink / raw)
To: benh, linuxppc-dev, kumar.gala, linux-watchdog
In-Reply-To: <1284764008-19469-1-git-send-email-timur@freescale.com>
Register the __init and __exit functions in the PowerPC e500 watchdog driver
as module entry/exit functions, and modify the Kconfig entry.
Add a .release method for the PowerPC e500 watchdog driver, so that the
watchdog is disabled when the driver is closed.
Loosely based on original code from Jiang Yutang <b14898@freescale.com>.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
This patch requires:
powerpc: export ppc_tb_freq so that modules can reference it
drivers/watchdog/Kconfig | 5 ++++-
drivers/watchdog/booke_wdt.c | 39 +++++++++++++++++++++++++++++++++++++--
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 24efd8e..d9cf5a9 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -957,9 +957,12 @@ config PIKA_WDT
the Warp platform.
config BOOKE_WDT
- bool "PowerPC Book-E Watchdog Timer"
+ tristate "PowerPC Book-E Watchdog Timer"
depends on BOOKE || 4xx
---help---
+ Watchdog driver for PowerPC e500 chips, such as the Freescale
+ MPC85xx SOCs.
+
Please see Documentation/watchdog/watchdog-api.txt for
more information.
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index 3d49671..a989998 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -4,7 +4,7 @@
* Author: Matthew McClintock
* Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
- * Copyright 2005, 2008 Freescale Semiconductor Inc.
+ * Copyright 2005, 2008, 2010 Freescale Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -114,6 +114,27 @@ static void __booke_wdt_enable(void *data)
mtspr(SPRN_TCR, val);
}
+/**
+ * booke_wdt_disable - disable the watchdog on the given CPU
+ *
+ * This function is called on each CPU. It disables the watchdog on that CPU.
+ *
+ * TCR[WRC] cannot be changed once it has been set to non-zero, but we can
+ * effectively disable the watchdog by setting its period to the maximum value.
+ */
+static void __booke_wdt_disable(void *data)
+{
+ u32 val;
+
+ val = mfspr(SPRN_TCR);
+ val &= ~(TCR_WIE | WDTP_MASK);
+ mtspr(SPRN_TCR, val);
+
+ /* clear status to make sure nothing is pending */
+ __booke_wdt_ping(NULL);
+
+}
+
static ssize_t booke_wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
@@ -193,12 +214,21 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
+static int booke_wdt_release(struct inode *inode, struct file *file)
+{
+ on_each_cpu(__booke_wdt_disable, NULL, 0);
+ booke_wdt_enabled = 0;
+
+ return 0;
+}
+
static const struct file_operations booke_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = booke_wdt_write,
.unlocked_ioctl = booke_wdt_ioctl,
.open = booke_wdt_open,
+ .release = booke_wdt_release,
};
static struct miscdevice booke_wdt_miscdev = {
@@ -237,4 +267,9 @@ static int __init booke_wdt_init(void)
return ret;
}
-device_initcall(booke_wdt_init);
+
+module_init(booke_wdt_init);
+module_exit(booke_wdt_exit);
+
+MODULE_DESCRIPTION("PowerPC Book-E watchdog driver");
+MODULE_LICENSE("GPL");
--
1.7.2.3
^ permalink raw reply related
* [PATCH 1/2] powerpc: export ppc_tb_freq so that modules can reference it
From: Timur Tabi @ 2010-09-17 22:53 UTC (permalink / raw)
To: benh, linuxppc-dev, kumar.gala, linux-watchdog
Export the global variable 'ppc_tb_freq', so that modules (like the Book-E
watchdog driver) can use it.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
This export is necessary for the Book-E watchdog driver to be compiled as a
module. Since ppc_proc_freq is already exported, I figured it's okay for
ppc_tb_freq to be exported as well.
arch/powerpc/kernel/time.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 8533b3b..49aa130 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -163,6 +163,7 @@ static long timezone_offset;
unsigned long ppc_proc_freq;
EXPORT_SYMBOL(ppc_proc_freq);
unsigned long ppc_tb_freq;
+EXPORT_SYMBOL(ppc_tb_freq);
static DEFINE_PER_CPU(u64, last_jiffy);
--
1.7.2.3
^ permalink raw reply related
* Re: [PATCH RFCv2 0/5] CARMA Board Support
From: Ira W. Snyder @ 2010-09-17 18:41 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
In-Reply-To: <1283964082-30133-1-git-send-email-iws@ovro.caltech.edu>
On Wed, Sep 08, 2010 at 09:41:17AM -0700, Ira W. Snyder wrote:
> Hello everyone,
>
> This is the second posting of these drivers, taking into account comments
> from the RFCv1 post. Thanks to all that contributed.
>
Any comments on this series? I haven't heard anything for more than a
week. Is there somebody else I should be CC'ing?
Thanks,
Ira
^ permalink raw reply
* Re: Generating elf kernel ?
From: Scott Wood @ 2010-09-17 17:44 UTC (permalink / raw)
To: tiejun.chen; +Cc: linuxppc-dev, Guillaume Dargaud
In-Reply-To: <4C92CB51.5010008@windriver.com>
On Fri, 17 Sep 2010 09:58:41 +0800
"tiejun.chen" <tiejun.chen@windriver.com> wrote:
> Scott Wood wrote:
> > The guest OS *is* the same as native Linux, as far as TLB handling is
> > concerned.
>
> Looks you means the TLB exception handler should be same between the native and
> the guest OS. Right?
Yes.
> Here I assume we're talking about e500mc since as far as I know for Freescale
> only e500mc is designed to support virtual machine based on ISA 2.0.6.
Yes, though there's nothing preventing virtualization on cores without
category E.HV (KVM supports this) -- it's just slower.
> I also know all TLB exceptions can direct to the guest OS when we enable
> EPCR[DTLBGS|ITLBGS|DSIGS|ISIGS]. But some TLB instructions (i.e. tlbwe )are the
> privileged instructions. So the guest OS always trap into the hypervisor and
> then the hypervisor should complete the real action with appropriate physical
> address.
Yes, of course. But that's not the point. I was just using it as a
convenient example because that's what I've recently done ELF loading
with... There's no reason U-Boot couldn't do the same if its ELF
loader were updated to support device trees. Currently U-Boot loads
bootwrapperless uImages to physical address zero.
And FWIW, we have run setups where our hv loads Linux to true
physical zero (with the hv living elsewhere), not just guest physical.
-Scott
^ permalink raw reply
* Re: Initial kernel command string (Was: Generating elf kernel ?)
From: tiejun.chen @ 2010-09-17 9:46 UTC (permalink / raw)
To: Guillaume Dargaud; +Cc: linuxppc-dev
In-Reply-To: <201009171127.51017.dargaud@lpsc.in2p3.fr>
Guillaume Dargaud wrote:
> Thanks for helping about the elf issue, I got it running. The problem was that
> I wasn't using the proper file produced by make !
>
>
> Now I have a strange and probably simple problem that the Initial kernel
> command string is incorrect. I want, and I have set in the .config:
> CONFIG_CMDLINE="console=ttyUL0,115200 rw root=/dev/nfs ip=bootp"
I think you should modify the bootargs on your dts.
------
chosen {
bootargs = "console=ttyS0 root=/dev/ram";
linux,stdout-path = "/plb@0/serial@83e00000";
} ;
>
> But when my kernel boots it uses:
> console=ttyUL0 root=/dev/ram
>
> I can check:
> strings arch/powerpc/boot/simpleImage.virtex405-ml405.elf | grep console
> Vconsole=ttyUL0 root=/dev/ram
>
>
> Also my previous kernel would wait for 2 seconds at the beginning to allow me
> to change the initial command string via the serial port, but now it just runs
> right through. How can I enable this option ?
It's possible on PowerPC kernel :)
You can take a look at the file, arch/powerpc/boot/main.c.
------
static void prep_cmdline(void *chosen)
{
if (cmdline[0] == '\0')
getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
printf("\n\rLinux/PowerPC load: %s", cmdline);
/* If possible, edit the command line */
if (console_ops.edit_cmdline)
console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
printf("\n\r");
.......
So you have to define one function, console_ops.edit_cmdline -->
serial_edit_cmdline. Or you can try bind this to your boot console ops directly.
Please refer to the file, arch/powerpc/boot/serial.c.
Cheers!
Tiejun
>
> On the plus side it boots in .5 seconds !
>
> Here's my .config:
> CONFIG_40x=y
> CONFIG_4xx=y
> CONFIG_PPC_MMU_NOHASH=y
> CONFIG_PPC_MMU_NOHASH_32=y
> CONFIG_NOT_COHERENT_CACHE=y
> CONFIG_PPC32=y
> CONFIG_WORD_SIZE=32
> CONFIG_MMU=y
> CONFIG_GENERIC_CMOS_UPDATE=y
> CONFIG_GENERIC_TIME=y
> CONFIG_GENERIC_TIME_VSYSCALL=y
> CONFIG_GENERIC_CLOCKEVENTS=y
> CONFIG_GENERIC_HARDIRQS=y
> CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
> CONFIG_IRQ_PER_CPU=y
> CONFIG_NR_IRQS=512
> CONFIG_STACKTRACE_SUPPORT=y
> CONFIG_HAVE_LATENCYTOP_SUPPORT=y
> CONFIG_TRACE_IRQFLAGS_SUPPORT=y
> CONFIG_LOCKDEP_SUPPORT=y
> CONFIG_RWSEM_XCHGADD_ALGORITHM=y
> CONFIG_ARCH_HAS_ILOG2_U32=y
> CONFIG_GENERIC_HWEIGHT=y
> CONFIG_GENERIC_FIND_NEXT_BIT=y
> CONFIG_GENERIC_GPIO=y
> CONFIG_PPC=y
> CONFIG_EARLY_PRINTK=y
> CONFIG_GENERIC_NVRAM=y
> CONFIG_SCHED_OMIT_FRAME_POINTER=y
> CONFIG_ARCH_MAY_HAVE_PC_FDC=y
> CONFIG_PPC_OF=y
> CONFIG_OF=y
> CONFIG_PPC_UDBG_16550=y
> CONFIG_AUDIT_ARCH=y
> CONFIG_GENERIC_BUG=y
> CONFIG_DTC=y
> CONFIG_DEFAULT_UIMAGE=y
> CONFIG_ARCH_HIBERNATION_POSSIBLE=y
> CONFIG_PPC_DCR_NATIVE=y
> CONFIG_PPC_DCR_MMIO=y
> CONFIG_PPC_DCR=y
> CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
> CONFIG_PPC_ADV_DEBUG_REGS=y
> CONFIG_PPC_ADV_DEBUG_IACS=2
> CONFIG_PPC_ADV_DEBUG_DACS=2
> CONFIG_PPC_ADV_DEBUG_DVCS=0
> CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
> CONFIG_CONSTRUCTORS=y
> CONFIG_EXPERIMENTAL=y
> CONFIG_BROKEN_ON_SMP=y
> CONFIG_INIT_ENV_ARG_LIMIT=32
> CONFIG_LOCALVERSION=""
> CONFIG_TREE_RCU=y
> CONFIG_RCU_FANOUT=32
> CONFIG_IKCONFIG=y
> CONFIG_IKCONFIG_PROC=y
> CONFIG_LOG_BUF_SHIFT=14
> CONFIG_NAMESPACES=y
> CONFIG_CC_OPTIMIZE_FOR_SIZE=y
> CONFIG_SYSCTL=y
> CONFIG_ANON_INODES=y
> CONFIG_SYSCTL_SYSCALL=y
> CONFIG_KALLSYMS=y
> CONFIG_HOTPLUG=y
> CONFIG_PRINTK=y
> CONFIG_BUG=y
> CONFIG_ELF_CORE=y
> CONFIG_BASE_FULL=y
> CONFIG_FUTEX=y
> CONFIG_EPOLL=y
> CONFIG_SIGNALFD=y
> CONFIG_TIMERFD=y
> CONFIG_EVENTFD=y
> CONFIG_SHMEM=y
> CONFIG_AIO=y
> CONFIG_HAVE_PERF_EVENTS=y
> CONFIG_PERF_EVENTS=y
> CONFIG_VM_EVENT_COUNTERS=y
> CONFIG_COMPAT_BRK=y
> CONFIG_SLAB=y
> CONFIG_HAVE_OPROFILE=y
> CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
> CONFIG_HAVE_IOREMAP_PROT=y
> CONFIG_HAVE_KPROBES=y
> CONFIG_HAVE_KRETPROBES=y
> CONFIG_HAVE_ARCH_TRACEHOOK=y
> CONFIG_HAVE_DMA_ATTRS=y
> CONFIG_HAVE_DMA_API_DEBUG=y
> CONFIG_SLABINFO=y
> CONFIG_RT_MUTEXES=y
> CONFIG_BASE_SMALL=0
> CONFIG_MODULES=y
> CONFIG_MODULE_UNLOAD=y
> CONFIG_MODULE_FORCE_UNLOAD=y
> CONFIG_BLOCK=y
> CONFIG_IOSCHED_NOOP=y
> CONFIG_IOSCHED_DEADLINE=y
> CONFIG_IOSCHED_CFQ=y
> CONFIG_DEFAULT_CFQ=y
> CONFIG_DEFAULT_IOSCHED="cfq"
> CONFIG_INLINE_SPIN_UNLOCK=y
> CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
> CONFIG_INLINE_READ_UNLOCK=y
> CONFIG_INLINE_READ_UNLOCK_IRQ=y
> CONFIG_INLINE_WRITE_UNLOCK=y
> CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
> CONFIG_PPC4xx_GPIO=y
> CONFIG_XILINX_VIRTEX=y
> CONFIG_XILINX_VIRTEX_GENERIC_BOARD=y
> CONFIG_PPC40x_SIMPLE=y
> CONFIG_XILINX_VIRTEX_II_PRO=y
> CONFIG_XILINX_VIRTEX_4_FX=y
> CONFIG_IBM405_ERR77=y
> CONFIG_IBM405_ERR51=y
> CONFIG_SIMPLE_GPIO=y
> CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
> CONFIG_HZ_250=y
> CONFIG_HZ=250
> CONFIG_PREEMPT_VOLUNTARY=y
> CONFIG_BINFMT_ELF=y
> CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
> CONFIG_ARCH_HAS_WALK_MEMORY=y
> CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
> CONFIG_SPARSE_IRQ=y
> CONFIG_MAX_ACTIVE_REGIONS=32
> CONFIG_ARCH_FLATMEM_ENABLE=y
> CONFIG_ARCH_POPULATES_NODE_MAP=y
> CONFIG_SELECT_MEMORY_MODEL=y
> CONFIG_FLATMEM_MANUAL=y
> CONFIG_FLATMEM=y
> CONFIG_FLAT_NODE_MEM_MAP=y
> CONFIG_PAGEFLAGS_EXTENDED=y
> CONFIG_SPLIT_PTLOCK_CPUS=4
> CONFIG_ZONE_DMA_FLAG=1
> CONFIG_BOUNCE=y
> CONFIG_VIRT_TO_BUS=y
> CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
> CONFIG_PPC_4K_PAGES=y
> CONFIG_FORCE_MAX_ZONEORDER=11
> CONFIG_PROC_DEVICETREE=y
> CONFIG_CMDLINE_BOOL=y
> CONFIG_CMDLINE="console=ttyUL0,115200 rw root=/dev/nfs ip=bootp"
> CONFIG_EXTRA_TARGETS=""
> CONFIG_ISA_DMA_API=y
> CONFIG_ZONE_DMA=y
> CONFIG_NEED_DMA_MAP_STATE=y
> CONFIG_4xx_SOC=y
> CONFIG_PPC_PCI_CHOICE=y
> CONFIG_ADVANCED_OPTIONS=y
> CONFIG_LOWMEM_SIZE=0x30000000
> CONFIG_PAGE_OFFSET=0xc0000000
> CONFIG_KERNEL_START=0xc0000000
> CONFIG_PHYSICAL_START=0x00000000
> CONFIG_TASK_SIZE=0xc0000000
> CONFIG_CONSISTENT_SIZE=0x00200000
> CONFIG_NET=y
> CONFIG_PACKET=y
> CONFIG_UNIX=y
> CONFIG_INET=y
> CONFIG_IP_FIB_HASH=y
> CONFIG_IP_PNP=y
> CONFIG_IP_PNP_DHCP=y
> CONFIG_IP_PNP_BOOTP=y
> CONFIG_INET_DIAG=y
> CONFIG_INET_TCP_DIAG=y
> CONFIG_TCP_CONG_CUBIC=y
> CONFIG_DEFAULT_TCP_CONG="cubic"
> CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
> CONFIG_STANDALONE=y
> CONFIG_PREVENT_FIRMWARE_BUILD=y
> CONFIG_FW_LOADER=y
> CONFIG_FIRMWARE_IN_KERNEL=y
> CONFIG_EXTRA_FIRMWARE=""
> CONFIG_OF_FLATTREE=y
> CONFIG_OF_DYNAMIC=y
> CONFIG_OF_DEVICE=y
> CONFIG_OF_GPIO=y
> CONFIG_XILINX_DRIVERS=y
> CONFIG_NEED_XILINX_LLDMA=y
> CONFIG_HAVE_IDE=y
> CONFIG_SCSI_MOD=y
> CONFIG_NETDEVICES=y
> CONFIG_NETDEV_1000=y
> CONFIG_XILINX_LLTEMAC=y
> CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_GMII=y
> CONFIG_INPUT=y
> CONFIG_INPUT_MOUSEDEV=y
> CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
> CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
> CONFIG_SERIO=y
> CONFIG_SERIO_SERPORT=y
> CONFIG_VT=y
> CONFIG_CONSOLE_TRANSLATIONS=y
> CONFIG_VT_CONSOLE=y
> CONFIG_HW_CONSOLE=y
> CONFIG_DEVKMEM=y
> CONFIG_SERIAL_UARTLITE=y
> CONFIG_SERIAL_UARTLITE_CONSOLE=y
> CONFIG_SERIAL_CORE=y
> CONFIG_SERIAL_CORE_CONSOLE=y
> CONFIG_UNIX98_PTYS=y
> CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
> CONFIG_ARCH_REQUIRE_GPIOLIB=y
> CONFIG_GPIOLIB=y
> CONFIG_GPIO_SYSFS=y
> CONFIG_GPIO_XILINX=y
> CONFIG_SSB_POSSIBLE=y
> CONFIG_DUMMY_CONSOLE=y
> CONFIG_XILINX_EDK=y
> CONFIG_UIO=y
> CONFIG_UIO_PDRV=y
> CONFIG_UIO_PDRV_GENIRQ=y
> CONFIG_FILE_LOCKING=y
> CONFIG_PROC_FS=y
> CONFIG_PROC_SYSCTL=y
> CONFIG_PROC_PAGE_MONITOR=y
> CONFIG_SYSFS=y
> CONFIG_CONFIGFS_FS=y
> CONFIG_NETWORK_FILESYSTEMS=y
> CONFIG_NFS_FS=y
> CONFIG_NFS_V3=y
> CONFIG_ROOT_NFS=y
> CONFIG_LOCKD=y
> CONFIG_LOCKD_V4=y
> CONFIG_NFS_COMMON=y
> CONFIG_SUNRPC=y
> CONFIG_MSDOS_PARTITION=y
> CONFIG_BITREVERSE=y
> CONFIG_GENERIC_FIND_LAST_BIT=y
> CONFIG_CRC_CCITT=y
> CONFIG_CRC32=y
> CONFIG_HAS_IOMEM=y
> CONFIG_HAS_IOPORT=y
> CONFIG_HAS_DMA=y
> CONFIG_HAVE_LMB=y
> CONFIG_NLATTR=y
> CONFIG_GENERIC_ATOMIC64=y
> CONFIG_PRINTK_TIME=y
> CONFIG_ENABLE_WARN_DEPRECATED=y
> CONFIG_ENABLE_MUST_CHECK=y
> CONFIG_FRAME_WARN=1024
> CONFIG_DEBUG_BUGVERBOSE=y
> CONFIG_DEBUG_MEMORY_INIT=y
> CONFIG_RCU_CPU_STALL_DETECTOR=y
> CONFIG_SYSCTL_SYSCALL_CHECK=y
> CONFIG_HAVE_FUNCTION_TRACER=y
> CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
> CONFIG_HAVE_DYNAMIC_FTRACE=y
> CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
> CONFIG_TRACING_SUPPORT=y
> CONFIG_HAVE_ARCH_KGDB=y
> CONFIG_PPC_WERROR=y
> CONFIG_PRINT_STACK_DEPTH=64
> CONFIG_DEFAULT_SECURITY_DAC=y
> CONFIG_DEFAULT_SECURITY=""
> CONFIG_CRYPTO=y
> CONFIG_CRYPTO_ALGAPI=y
> CONFIG_CRYPTO_ALGAPI2=y
> CONFIG_CRYPTO_RNG=y
> CONFIG_CRYPTO_RNG2=y
> CONFIG_CRYPTO_AES=y
> CONFIG_CRYPTO_ANSI_CPRNG=y
>
^ permalink raw reply
* Initial kernel command string (Was: Generating elf kernel ?)
From: Guillaume Dargaud @ 2010-09-17 9:27 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <4C91CC78.2020802@windriver.com>
Thanks for helping about the elf issue, I got it running. The problem was that
I wasn't using the proper file produced by make !
Now I have a strange and probably simple problem that the Initial kernel
command string is incorrect. I want, and I have set in the .config:
CONFIG_CMDLINE="console=ttyUL0,115200 rw root=/dev/nfs ip=bootp"
But when my kernel boots it uses:
console=ttyUL0 root=/dev/ram
I can check:
strings arch/powerpc/boot/simpleImage.virtex405-ml405.elf | grep console
Vconsole=ttyUL0 root=/dev/ram
Also my previous kernel would wait for 2 seconds at the beginning to allow me
to change the initial command string via the serial port, but now it just runs
right through. How can I enable this option ?
On the plus side it boots in .5 seconds !
Here's my .config:
CONFIG_40x=y
CONFIG_4xx=y
CONFIG_PPC_MMU_NOHASH=y
CONFIG_PPC_MMU_NOHASH_32=y
CONFIG_NOT_COHERENT_CACHE=y
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
CONFIG_MMU=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_IRQ_PER_CPU=y
CONFIG_NR_IRQS=512
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
CONFIG_PPC=y
CONFIG_EARLY_PRINTK=y
CONFIG_GENERIC_NVRAM=y
CONFIG_SCHED_OMIT_FRAME_POINTER=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_PPC_OF=y
CONFIG_OF=y
CONFIG_PPC_UDBG_16550=y
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_PPC_DCR_NATIVE=y
CONFIG_PPC_DCR_MMIO=y
CONFIG_PPC_DCR=y
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_PPC_ADV_DEBUG_REGS=y
CONFIG_PPC_ADV_DEBUG_IACS=2
CONFIG_PPC_ADV_DEBUG_DACS=2
CONFIG_PPC_ADV_DEBUG_DVCS=0
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
CONFIG_CONSTRUCTORS=y
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_TREE_RCU=y
CONFIG_RCU_FANOUT=32
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_NAMESPACES=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_ANON_INODES=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_PERF_EVENTS=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_BLOCK=y
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_CFQ=y
CONFIG_DEFAULT_IOSCHED="cfq"
CONFIG_INLINE_SPIN_UNLOCK=y
CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
CONFIG_INLINE_READ_UNLOCK=y
CONFIG_INLINE_READ_UNLOCK_IRQ=y
CONFIG_INLINE_WRITE_UNLOCK=y
CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
CONFIG_PPC4xx_GPIO=y
CONFIG_XILINX_VIRTEX=y
CONFIG_XILINX_VIRTEX_GENERIC_BOARD=y
CONFIG_PPC40x_SIMPLE=y
CONFIG_XILINX_VIRTEX_II_PRO=y
CONFIG_XILINX_VIRTEX_4_FX=y
CONFIG_IBM405_ERR77=y
CONFIG_IBM405_ERR51=y
CONFIG_SIMPLE_GPIO=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_HZ_250=y
CONFIG_HZ=250
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_BINFMT_ELF=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
CONFIG_SPARSE_IRQ=y
CONFIG_MAX_ACTIVE_REGIONS=32
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
CONFIG_FORCE_MAX_ZONEORDER=11
CONFIG_PROC_DEVICETREE=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE="console=ttyUL0,115200 rw root=/dev/nfs ip=bootp"
CONFIG_EXTRA_TARGETS=""
CONFIG_ISA_DMA_API=y
CONFIG_ZONE_DMA=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_4xx_SOC=y
CONFIG_PPC_PCI_CHOICE=y
CONFIG_ADVANCED_OPTIONS=y
CONFIG_LOWMEM_SIZE=0x30000000
CONFIG_PAGE_OFFSET=0xc0000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_PHYSICAL_START=0x00000000
CONFIG_TASK_SIZE=0xc0000000
CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y
CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE=""
CONFIG_OF_FLATTREE=y
CONFIG_OF_DYNAMIC=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_XILINX_DRIVERS=y
CONFIG_NEED_XILINX_LLDMA=y
CONFIG_HAVE_IDE=y
CONFIG_SCSI_MOD=y
CONFIG_NETDEVICES=y
CONFIG_NETDEV_1000=y
CONFIG_XILINX_LLTEMAC=y
CONFIG_XILINX_LLTEMAC_MARVELL_88E1111_GMII=y
CONFIG_INPUT=y
CONFIG_INPUT_MOUSEDEV=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_SERIO=y
CONFIG_SERIO_SERPORT=y
CONFIG_VT=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
CONFIG_DEVKMEM=y
CONFIG_SERIAL_UARTLITE=y
CONFIG_SERIAL_UARTLITE_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_XILINX=y
CONFIG_SSB_POSSIBLE=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_XILINX_EDK=y
CONFIG_UIO=y
CONFIG_UIO_PDRV=y
CONFIG_UIO_PDRV_GENIRQ=y
CONFIG_FILE_LOCKING=y
CONFIG_PROC_FS=y
CONFIG_PROC_SYSCTL=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_SYSFS=y
CONFIG_CONFIGFS_FS=y
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_MSDOS_PARTITION=y
CONFIG_BITREVERSE=y
CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_CRC_CCITT=y
CONFIG_CRC32=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_PRINTK_TIME=y
CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_RCU_CPU_STALL_DETECTOR=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
CONFIG_DEFAULT_SECURITY_DAC=y
CONFIG_DEFAULT_SECURITY=""
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_ANSI_CPRNG=y
--
Guillaume Dargaud
http://www.gdargaud.net/
^ permalink raw reply
* Re: linux support for freescale e5500 core?
From: Kumar Gala @ 2010-09-17 7:39 UTC (permalink / raw)
To: Chris Friesen; +Cc: linuxppc-dev, paulus, Scott Wood, timur
In-Reply-To: <4C930C55.5030008@genband.com>
On Sep 17, 2010, at 1:36 AM, Chris Friesen wrote:
> On 09/16/2010 11:33 PM, Benjamin Herrenschmidt wrote:
>> On Fri, 2010-09-17 at 00:17 -0500, Kumar Gala wrote:
>>> Not sure how the 970 bit worked, but this seems a bit problematic =
for
>>> switching between kernel and application for how we do this on
>>> e500mc/e5500. We'd have to touch the control bit on every exception
>>> path which seems ugly to me.
>>=20
>> Unless the kernel uses dcbzl (feature fixup replacement ?)
>>=20
>> In that case it's on context switch only.
>=20
> This is basically what we did. Kernel and system libraries (glibc and
> friends) always use dcbzl, process flag indicates compatibility, touch
> the control bit on task context switch if the prev and next processes
> have different compatibility modes.
>=20
> On the 970 you have to invalidate the entire icache whenever you =
change
> the control bit. This is a pain involving a loop that calls icbi on =
512
> cachelines.
I'm pretty sure on e500mc / e5500 you only need proper sync/isync/msync =
after the change in the control register.
- k=
^ permalink raw reply
* [PATCH 3/3 v4] P4080/mtd: Fix the freescale lbc issue with 36bit mode
From: Roy Zang @ 2010-09-17 7:01 UTC (permalink / raw)
To: linux-mtd; +Cc: B07421, dedekind1, B25806, linuxppc-dev, akpm, dwmw2, B11780
In-Reply-To: <1284706869-12555-2-git-send-email-tie-fei.zang@freescale.com>
From: Lan Chunhe-B25806 <b25806@freescale.com>
When system uses 36bit physical address, res.start is 36bit
physical address. But the function of in_be32 returns 32bit
physical address. Then both of them compared each other is
wrong. So by converting the address of res.start into
the right format fixes this issue.
Signed-off-by: Lan Chunhe-B25806 <b25806@freescale.com>
Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
Reviewed-by: Anton Vorontsov <cbouatmailru@gmail.com>
---
arch/powerpc/include/asm/fsl_lbc.h | 1 +
arch/powerpc/sysdev/fsl_lbc.c | 23 ++++++++++++++++++++++-
drivers/mtd/nand/fsl_elbc_nand.c | 2 +-
3 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h
index db94698..ad663e8 100644
--- a/arch/powerpc/include/asm/fsl_lbc.h
+++ b/arch/powerpc/include/asm/fsl_lbc.h
@@ -246,6 +246,7 @@ struct fsl_upm {
int width;
};
+extern u32 fsl_lbc_addr(phys_addr_t addr_base);
extern int fsl_lbc_find(phys_addr_t addr_base);
extern int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm);
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index 4920cd3..32c2120 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -34,6 +34,27 @@ struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
/**
+ * fsl_lbc_addr - convert the base address
+ * @addr_base: base address of the memory bank
+ *
+ * This function converts a base address of lbc into the right format for the
+ * BR register. If the SOC has eLBC then it returns 32bit physical address
+ * else it convers a 34bit local bus physical address to correct format of
+ * 32bit address for BR register (Example: MPC8641).
+ */
+u32 fsl_lbc_addr(phys_addr_t addr_base)
+{
+ struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node;
+ u32 addr = addr_base & 0xffff8000;
+
+ if (of_device_is_compatible(np, "fsl,elbc"))
+ return addr;
+
+ return addr | ((addr_base & 0x300000000ull) >> 19);
+}
+EXPORT_SYMBOL(fsl_lbc_addr);
+
+/**
* fsl_lbc_find - find Localbus bank
* @addr_base: base address of the memory bank
*
@@ -55,7 +76,7 @@ int fsl_lbc_find(phys_addr_t addr_base)
__be32 br = in_be32(&lbc->bank[i].br);
__be32 or = in_be32(&lbc->bank[i].or);
- if (br & BR_V && (br & or & BR_BA) == addr_base)
+ if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base))
return i;
}
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 76ffd24..227618b 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -865,7 +865,7 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *dev)
(in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
(in_be32(&lbc->bank[bank].br) &
in_be32(&lbc->bank[bank].or) & BR_BA)
- == res.start)
+ == fsl_lbc_addr(res.start))
break;
if (bank >= MAX_BANKS) {
--
1.5.6.5
^ permalink raw reply related
* [PATCH 1/3 v4] P4080/eLBC: Make Freescale elbc interrupt common to elbc devices
From: Roy Zang @ 2010-09-17 7:01 UTC (permalink / raw)
To: linux-mtd; +Cc: B07421, dedekind1, B25806, linuxppc-dev, akpm, dwmw2, B11780
From: Lan Chunhe-B25806 <b25806@freescale.com>
Move Freescale elbc interrupt from nand dirver to elbc driver.
Then all elbc devices can use the interrupt instead of ONLY nand.
Signed-off-by: Lan Chunhe-B25806 <b25806@freescale.com>
Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
---
Comparing v3:
1. minor fix from type unsigned int to u32
2. fix platform_driver issue.
3. add mutex for nand probe
arch/powerpc/Kconfig | 7 +-
arch/powerpc/include/asm/fsl_lbc.h | 31 +++++-
arch/powerpc/sysdev/fsl_lbc.c | 246 ++++++++++++++++++++++++++++++------
3 files changed, 242 insertions(+), 42 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 631e5a0..44df1ba 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -687,9 +687,12 @@ config 4xx_SOC
bool
config FSL_LBC
- bool
+ bool "Freescale Local Bus support"
+ depends on FSL_SOC
help
- Freescale Localbus support
+ Enables reporting of errors from the Freescale local bus
+ controller. Also contains some common code used by
+ drivers for specific local bus peripherals.
config FSL_GTM
bool
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h
index 1b5a210..db94698 100644
--- a/arch/powerpc/include/asm/fsl_lbc.h
+++ b/arch/powerpc/include/asm/fsl_lbc.h
@@ -1,9 +1,10 @@
/* Freescale Local Bus Controller
*
- * Copyright (c) 2006-2007 Freescale Semiconductor
+ * Copyright (c) 2006-2007, 2010 Freescale Semiconductor
*
* Authors: Nick Spence <nick.spence@freescale.com>,
* Scott Wood <scottwood@freescale.com>
+ * Jack Lan <jack.lan@freescale.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -125,13 +126,23 @@ struct fsl_lbc_regs {
#define LTESR_ATMW 0x00800000
#define LTESR_ATMR 0x00400000
#define LTESR_CS 0x00080000
+#define LTESR_UPM 0x00000002
#define LTESR_CC 0x00000001
#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
+#define LTESR_MASK (LTESR_BM | LTESR_FCT | LTESR_PAR | LTESR_WP \
+ | LTESR_ATMW | LTESR_ATMR | LTESR_CS | LTESR_UPM \
+ | LTESR_CC)
+#define LTESR_CLEAR 0xFFFFFFFF
+#define LTECCR_CLEAR 0xFFFFFFFF
+#define LTESR_STATUS LTESR_MASK
+#define LTEIR_ENABLE LTESR_MASK
+#define LTEDR_ENABLE 0x00000000
__be32 ltedr; /**< Transfer Error Disable Register */
__be32 lteir; /**< Transfer Error Interrupt Register */
__be32 lteatr; /**< Transfer Error Attributes Register */
__be32 ltear; /**< Transfer Error Address Register */
- u8 res6[0xC];
+ __be32 lteccr; /**< Transfer Error ECC Register */
+ u8 res6[0x8];
__be32 lbcr; /**< Configuration Register */
#define LBCR_LDIS 0x80000000
#define LBCR_LDIS_SHIFT 31
@@ -265,7 +276,23 @@ static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
cpu_relax();
}
+/* overview of the fsl lbc controller */
+
+struct fsl_lbc_ctrl {
+ /* device info */
+ struct device *dev;
+ struct fsl_lbc_regs __iomem *regs;
+ int irq;
+ wait_queue_head_t irq_wait;
+ spinlock_t lock;
+ void *nand;
+
+ /* status read from LTESR by irq handler */
+ unsigned int irq_status;
+};
+
extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base,
u32 mar);
+extern struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
#endif /* __ASM_FSL_LBC_H */
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index dceb8d1..4920cd3 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -2,8 +2,11 @@
* Freescale LBC and UPM routines.
*
* Copyright (c) 2007-2008 MontaVista Software, Inc.
+ * Copyright (c) 2010 Freescale Semiconductor
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ * Author: Jack Lan <Jack.Lan@freescale.com>
+ * Author: Roy Zang <tie-fei.zang@freescale.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,37 +24,14 @@
#include <linux/of.h>
#include <asm/prom.h>
#include <asm/fsl_lbc.h>
+#include <linux/slab.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
-static struct fsl_lbc_regs __iomem *fsl_lbc_regs;
-
-static char __initdata *compat_lbc[] = {
- "fsl,pq2-localbus",
- "fsl,pq2pro-localbus",
- "fsl,pq3-localbus",
- "fsl,elbc",
-};
-
-static int __init fsl_lbc_init(void)
-{
- struct device_node *lbus;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
- lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
- if (lbus)
- goto found;
- }
- return -ENODEV;
-
-found:
- fsl_lbc_regs = of_iomap(lbus, 0);
- of_node_put(lbus);
- if (!fsl_lbc_regs)
- return -ENOMEM;
- return 0;
-}
-arch_initcall(fsl_lbc_init);
+struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
+EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
/**
* fsl_lbc_find - find Localbus bank
@@ -65,13 +45,15 @@ arch_initcall(fsl_lbc_init);
int fsl_lbc_find(phys_addr_t addr_base)
{
int i;
+ struct fsl_lbc_regs __iomem *lbc;
- if (!fsl_lbc_regs)
+ if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
return -ENODEV;
- for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
- __be32 br = in_be32(&fsl_lbc_regs->bank[i].br);
- __be32 or = in_be32(&fsl_lbc_regs->bank[i].or);
+ lbc = fsl_lbc_ctrl_dev->regs;
+ for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
+ __be32 br = in_be32(&lbc->bank[i].br);
+ __be32 or = in_be32(&lbc->bank[i].or);
if (br & BR_V && (br & or & BR_BA) == addr_base)
return i;
@@ -94,22 +76,27 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
{
int bank;
__be32 br;
+ struct fsl_lbc_regs __iomem *lbc;
bank = fsl_lbc_find(addr_base);
if (bank < 0)
return bank;
- br = in_be32(&fsl_lbc_regs->bank[bank].br);
+ if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+ return -ENODEV;
+
+ lbc = fsl_lbc_ctrl_dev->regs;
+ br = in_be32(&lbc->bank[bank].br);
switch (br & BR_MSEL) {
case BR_MS_UPMA:
- upm->mxmr = &fsl_lbc_regs->mamr;
+ upm->mxmr = &lbc->mamr;
break;
case BR_MS_UPMB:
- upm->mxmr = &fsl_lbc_regs->mbmr;
+ upm->mxmr = &lbc->mbmr;
break;
case BR_MS_UPMC:
- upm->mxmr = &fsl_lbc_regs->mcmr;
+ upm->mxmr = &lbc->mcmr;
break;
default:
return -EINVAL;
@@ -143,14 +130,18 @@ EXPORT_SYMBOL(fsl_upm_find);
* thus UPM pattern actually executed. Note that mar usage depends on the
* pre-programmed AMX bits in the UPM RAM.
*/
+
int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
{
int ret = 0;
unsigned long flags;
+ if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+ return -ENODEV;
+
spin_lock_irqsave(&fsl_lbc_lock, flags);
- out_be32(&fsl_lbc_regs->mar, mar);
+ out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
switch (upm->width) {
case 8:
@@ -172,3 +163,182 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
return ret;
}
EXPORT_SYMBOL(fsl_upm_run_pattern);
+
+static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
+{
+ struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+
+ /* clear event registers */
+ setbits32(&lbc->ltesr, LTESR_CLEAR);
+ out_be32(&lbc->lteatr, 0);
+ out_be32(&lbc->ltear, 0);
+ out_be32(&lbc->lteccr, LTECCR_CLEAR);
+ out_be32(&lbc->ltedr, LTEDR_ENABLE);
+
+ /* Enable interrupts for any detected events */
+ out_be32(&lbc->lteir, LTEIR_ENABLE);
+
+ return 0;
+}
+
+static int __devexit fsl_lbc_ctrl_remove(struct platform_device *dev)
+{
+ struct fsl_lbc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
+
+ if (ctrl->irq)
+ free_irq(ctrl->irq, ctrl);
+
+ if (ctrl->regs)
+ iounmap(ctrl->regs);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ kfree(ctrl);
+
+ return 0;
+}
+
+/*
+ * NOTE: This interrupt is used to report localbus events of various kinds,
+ * such as transaction errors on the chipselects.
+ */
+
+static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
+{
+ struct fsl_lbc_ctrl *ctrl = data;
+ struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+ u32 status;
+
+ status = in_be32(&lbc->ltesr);
+ if (!status)
+ return IRQ_NONE;
+
+ out_be32(&lbc->ltesr, LTESR_CLEAR);
+ out_be32(&lbc->lteatr, 0);
+ out_be32(&lbc->ltear, 0);
+ ctrl->irq_status = status;
+
+ if (status & LTESR_BM)
+ dev_err(ctrl->dev, "Local bus monitor time-out: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_WP)
+ dev_err(ctrl->dev, "Write protect error: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_ATMW)
+ dev_err(ctrl->dev, "Atomic write error: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_ATMR)
+ dev_err(ctrl->dev, "Atomic read error: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_CS)
+ dev_err(ctrl->dev, "Chip select error: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_UPM)
+ ;
+ if (status & LTESR_FCT) {
+ dev_err(ctrl->dev, "FCM command time-out: "
+ "LTESR 0x%08X\n", status);
+ smp_wmb();
+ wake_up(&ctrl->irq_wait);
+ }
+ if (status & LTESR_PAR) {
+ dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: "
+ "LTESR 0x%08X\n", status);
+ smp_wmb();
+ wake_up(&ctrl->irq_wait);
+ }
+ if (status & LTESR_CC) {
+ smp_wmb();
+ wake_up(&ctrl->irq_wait);
+ }
+ if (status & ~LTESR_MASK)
+ dev_err(ctrl->dev, "Unknown error: "
+ "LTESR 0x%08X\n", status);
+ return IRQ_HANDLED;
+}
+
+/*
+ * fsl_lbc_ctrl_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code allocates all of
+ * the resources needed for the controller only. The
+ * resources for the NAND banks themselves are allocated
+ * in the chip probe function.
+*/
+
+static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
+{
+ int ret;
+
+ if (!dev->dev.of_node) {
+ dev_err(&dev->dev, "Device OF-Node is NULL");
+ return -EFAULT;
+ }
+ fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL);
+ if (!fsl_lbc_ctrl_dev)
+ return -ENOMEM;
+
+ dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev);
+
+ spin_lock_init(&fsl_lbc_ctrl_dev->lock);
+ init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait);
+
+ fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
+ if (!fsl_lbc_ctrl_dev->regs) {
+ dev_err(&dev->dev, "failed to get memory region\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
+ if (fsl_lbc_ctrl_dev->irq == NO_IRQ) {
+ dev_err(&dev->dev, "failed to get irq resource\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ fsl_lbc_ctrl_dev->dev = &dev->dev;
+
+ ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
+ if (ret < 0)
+ goto err;
+
+ ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0,
+ "fsl-lbc", fsl_lbc_ctrl_dev);
+ if (ret != 0) {
+ dev_err(&dev->dev, "failed to install irq (%d)\n",
+ fsl_lbc_ctrl_dev->irq);
+ ret = fsl_lbc_ctrl_dev->irq;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ iounmap(fsl_lbc_ctrl_dev->regs);
+ kfree(fsl_lbc_ctrl_dev);
+ return ret;
+}
+
+static const struct of_device_id fsl_lbc_match[] = {
+ { .compatible = "fsl,elbc", },
+ { .compatible = "fsl,pq3-localbus", },
+ { .compatible = "fsl,pq2-localbus", },
+ { .compatible = "fsl,pq2pro-localbus", },
+ {},
+};
+
+static struct platform_driver fsl_lbc_ctrl_driver = {
+ .driver = {
+ .name = "fsl-lbc",
+ .of_match_table = fsl_lbc_match,
+ },
+ .probe = fsl_lbc_ctrl_probe,
+};
+
+static int __init fsl_lbc_init(void)
+{
+ return platform_driver_register(&fsl_lbc_ctrl_driver);
+}
+module_init(fsl_lbc_init);
--
1.5.6.5
^ permalink raw reply related
* [PATCH 2/3 v4] P4080/mtd: Only make elbc nand driver detect nand flash partitions
From: Roy Zang @ 2010-09-17 7:01 UTC (permalink / raw)
To: linux-mtd; +Cc: B07421, dedekind1, B25806, linuxppc-dev, akpm, dwmw2, B11780
In-Reply-To: <1284706869-12555-1-git-send-email-tie-fei.zang@freescale.com>
From: Jack Lan <jack.lan@freescale.com>
The former driver had the two functions:
1. detecting nand flash partitions;
2. registering elbc interrupt.
Now, second function is removed to fsl_lbc.c.
Signed-off-by: Lan Chunhe-B25806 <b25806@freescale.com>
Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
---
drivers/mtd/nand/Kconfig | 1 +
drivers/mtd/nand/fsl_elbc_nand.c | 477 +++++++++++++++-----------------------
2 files changed, 193 insertions(+), 285 deletions(-)
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 8b4b67c..4132c46 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -458,6 +458,7 @@ config MTD_NAND_ORION
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on PPC_OF
+ select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
Controller Module with built-in hardware ECC capabilities.
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 80de0bf..76ffd24 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -1,9 +1,11 @@
/* Freescale Enhanced Local Bus Controller NAND driver
*
- * Copyright (c) 2006-2007 Freescale Semiconductor
+ * Copyright (c) 2006-2007, 2010 Freescale Semiconductor
*
* Authors: Nick Spence <nick.spence@freescale.com>,
* Scott Wood <scottwood@freescale.com>
+ * Jack Lan <jack.lan@freescale.com>
+ * Roy Zang <tie-fei.zang@freescale.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,6 +29,7 @@
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -42,14 +45,12 @@
#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
-struct fsl_elbc_ctrl;
-
/* mtd information per set */
struct fsl_elbc_mtd {
struct mtd_info mtd;
struct nand_chip chip;
- struct fsl_elbc_ctrl *ctrl;
+ struct fsl_lbc_ctrl *ctrl;
struct device *dev;
int bank; /* Chip select bank number */
@@ -58,18 +59,12 @@ struct fsl_elbc_mtd {
unsigned int fmr; /* FCM Flash Mode Register value */
};
-/* overview of the fsl elbc controller */
+/* Freescale eLBC FCM controller infomation */
-struct fsl_elbc_ctrl {
+struct fsl_elbc_fcm_ctrl {
struct nand_hw_control controller;
struct fsl_elbc_mtd *chips[MAX_BANKS];
- /* device info */
- struct device *dev;
- struct fsl_lbc_regs __iomem *regs;
- int irq;
- wait_queue_head_t irq_wait;
- unsigned int irq_status; /* status read from LTESR by irq handler */
u8 __iomem *addr; /* Address of assigned FCM buffer */
unsigned int page; /* Last page written to / read from */
unsigned int read_bytes; /* Number of bytes read during command */
@@ -164,11 +159,12 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
int buf_num;
- ctrl->page = page_addr;
+ elbc_fcm_ctrl->page = page_addr;
out_be32(&lbc->fbar,
page_addr >> (chip->phys_erase_shift - chip->page_shift));
@@ -185,16 +181,18 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
buf_num = page_addr & 7;
}
- ctrl->addr = priv->vbase + buf_num * 1024;
- ctrl->index = column;
+ elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024;
+ elbc_fcm_ctrl->index = column;
/* for OOB data point to the second half of the buffer */
if (oob)
- ctrl->index += priv->page_size ? 2048 : 512;
+ elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
- dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), "
+ dev_vdbg(priv->dev, "set_addr: bank=%d, "
+ "elbc_fcm_ctrl->addr=0x%p (0x%p), "
"index %x, pes %d ps %d\n",
- buf_num, ctrl->addr, priv->vbase, ctrl->index,
+ buf_num, elbc_fcm_ctrl->addr, priv->vbase,
+ elbc_fcm_ctrl->index,
chip->phys_erase_shift, chip->page_shift);
}
@@ -205,18 +203,19 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
/* Setup the FMR[OP] to execute without write protection */
out_be32(&lbc->fmr, priv->fmr | 3);
- if (ctrl->use_mdr)
- out_be32(&lbc->mdr, ctrl->mdr);
+ if (elbc_fcm_ctrl->use_mdr)
+ out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_run_command: fbar=%08x fpar=%08x "
"fbcr=%08x bank=%d\n",
in_be32(&lbc->fbar), in_be32(&lbc->fpar),
@@ -229,19 +228,18 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
/* wait for FCM complete flag or timeout */
wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
FCM_TIMEOUT_MSECS * HZ/1000);
- ctrl->status = ctrl->irq_status;
-
+ elbc_fcm_ctrl->status = ctrl->irq_status;
/* store mdr value in case it was needed */
- if (ctrl->use_mdr)
- ctrl->mdr = in_be32(&lbc->mdr);
+ if (elbc_fcm_ctrl->use_mdr)
+ elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
- ctrl->use_mdr = 0;
+ elbc_fcm_ctrl->use_mdr = 0;
- if (ctrl->status != LTESR_CC) {
- dev_info(ctrl->dev,
+ if (elbc_fcm_ctrl->status != LTESR_CC) {
+ dev_info(priv->dev,
"command failed: fir %x fcr %x status %x mdr %x\n",
in_be32(&lbc->fir), in_be32(&lbc->fcr),
- ctrl->status, ctrl->mdr);
+ elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
return -EIO;
}
@@ -251,7 +249,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
{
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
if (priv->page_size) {
@@ -284,15 +282,16 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
- ctrl->use_mdr = 0;
+ elbc_fcm_ctrl->use_mdr = 0;
/* clear the read buffer */
- ctrl->read_bytes = 0;
+ elbc_fcm_ctrl->read_bytes = 0;
if (command != NAND_CMD_PAGEPROG)
- ctrl->index = 0;
+ elbc_fcm_ctrl->index = 0;
switch (command) {
/* READ0 and READ1 read the entire buffer to use hardware ECC. */
@@ -301,7 +300,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* fall-through */
case NAND_CMD_READ0:
- dev_dbg(ctrl->dev,
+ dev_dbg(priv->dev,
"fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
" 0x%x, column: 0x%x.\n", page_addr, column);
@@ -309,8 +308,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
set_addr(mtd, 0, page_addr, 0);
- ctrl->read_bytes = mtd->writesize + mtd->oobsize;
- ctrl->index += column;
+ elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+ elbc_fcm_ctrl->index += column;
fsl_elbc_do_read(chip, 0);
fsl_elbc_run_command(mtd);
@@ -318,14 +317,14 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* READOOB reads only the OOB because no ECC is performed. */
case NAND_CMD_READOOB:
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
" 0x%x, column: 0x%x.\n", page_addr, column);
out_be32(&lbc->fbcr, mtd->oobsize - column);
set_addr(mtd, column, page_addr, 1);
- ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+ elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
fsl_elbc_do_read(chip, 1);
fsl_elbc_run_command(mtd);
@@ -333,7 +332,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* READID must read all 5 possible bytes while CEB is active */
case NAND_CMD_READID:
- dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
+ dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_UA << FIR_OP1_SHIFT) |
@@ -341,9 +340,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
/* 5 bytes for manuf, device and exts */
out_be32(&lbc->fbcr, 5);
- ctrl->read_bytes = 5;
- ctrl->use_mdr = 1;
- ctrl->mdr = 0;
+ elbc_fcm_ctrl->read_bytes = 5;
+ elbc_fcm_ctrl->use_mdr = 1;
+ elbc_fcm_ctrl->mdr = 0;
set_addr(mtd, 0, 0, 0);
fsl_elbc_run_command(mtd);
@@ -351,7 +350,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* ERASE1 stores the block and page address */
case NAND_CMD_ERASE1:
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
"page_addr: 0x%x.\n", page_addr);
set_addr(mtd, 0, page_addr, 0);
@@ -359,7 +358,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* ERASE2 uses the block and page address from ERASE1 */
case NAND_CMD_ERASE2:
- dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
+ dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
out_be32(&lbc->fir,
(FIR_OP_CM0 << FIR_OP0_SHIFT) |
@@ -374,8 +373,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
(NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
out_be32(&lbc->fbcr, 0);
- ctrl->read_bytes = 0;
- ctrl->use_mdr = 1;
+ elbc_fcm_ctrl->read_bytes = 0;
+ elbc_fcm_ctrl->use_mdr = 1;
fsl_elbc_run_command(mtd);
return;
@@ -383,14 +382,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* SEQIN sets up the addr buffer and all registers except the length */
case NAND_CMD_SEQIN: {
__be32 fcr;
- dev_vdbg(ctrl->dev,
- "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
+ dev_vdbg(priv->dev,
+ "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
"page_addr: 0x%x, column: 0x%x.\n",
page_addr, column);
- ctrl->column = column;
- ctrl->oob = 0;
- ctrl->use_mdr = 1;
+ elbc_fcm_ctrl->use_mdr = 1;
fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
(NAND_CMD_SEQIN << FCR_CMD2_SHIFT) |
@@ -420,7 +417,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* OOB area --> READOOB */
column -= mtd->writesize;
fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
- ctrl->oob = 1;
+ elbc_fcm_ctrl->oob = 1;
} else {
WARN_ON(column != 0);
/* First 256 bytes --> READ0 */
@@ -429,24 +426,24 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
}
out_be32(&lbc->fcr, fcr);
- set_addr(mtd, column, page_addr, ctrl->oob);
+ set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
return;
}
/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
case NAND_CMD_PAGEPROG: {
int full_page;
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
- "writing %d bytes.\n", ctrl->index);
+ "writing %d bytes.\n", elbc_fcm_ctrl->index);
/* if the write did not start at 0 or is not a full page
* then set the exact length, otherwise use a full page
* write so the HW generates the ECC.
*/
- if (ctrl->oob || ctrl->column != 0 ||
- ctrl->index != mtd->writesize + mtd->oobsize) {
- out_be32(&lbc->fbcr, ctrl->index);
+ if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
+ elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) {
+ out_be32(&lbc->fbcr, elbc_fcm_ctrl->index);
full_page = 0;
} else {
out_be32(&lbc->fbcr, 0);
@@ -458,21 +455,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* Read back the page in order to fill in the ECC for the
* caller. Is this really needed?
*/
- if (full_page && ctrl->oob_poi) {
+ if (full_page && elbc_fcm_ctrl->oob_poi) {
out_be32(&lbc->fbcr, 3);
set_addr(mtd, 6, page_addr, 1);
- ctrl->read_bytes = mtd->writesize + 9;
+ elbc_fcm_ctrl->read_bytes = mtd->writesize + 9;
fsl_elbc_do_read(chip, 1);
fsl_elbc_run_command(mtd);
- memcpy_fromio(ctrl->oob_poi + 6,
- &ctrl->addr[ctrl->index], 3);
- ctrl->index += 3;
+ memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6,
+ &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3);
+ elbc_fcm_ctrl->index += 3;
}
- ctrl->oob_poi = NULL;
+ elbc_fcm_ctrl->oob_poi = NULL;
return;
}
@@ -485,26 +482,26 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
out_be32(&lbc->fbcr, 1);
set_addr(mtd, 0, 0, 0);
- ctrl->read_bytes = 1;
+ elbc_fcm_ctrl->read_bytes = 1;
fsl_elbc_run_command(mtd);
/* The chip always seems to report that it is
* write-protected, even when it is not.
*/
- setbits8(ctrl->addr, NAND_STATUS_WP);
+ setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
return;
/* RESET without waiting for the ready line */
case NAND_CMD_RESET:
- dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
+ dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
fsl_elbc_run_command(mtd);
return;
default:
- dev_err(ctrl->dev,
+ dev_err(priv->dev,
"fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
command);
}
@@ -524,24 +521,24 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
unsigned int bufsize = mtd->writesize + mtd->oobsize;
if (len <= 0) {
- dev_err(ctrl->dev, "write_buf of %d bytes", len);
- ctrl->status = 0;
+ dev_err(priv->dev, "write_buf of %d bytes", len);
+ elbc_fcm_ctrl->status = 0;
return;
}
- if ((unsigned int)len > bufsize - ctrl->index) {
- dev_err(ctrl->dev,
+ if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
+ dev_err(priv->dev,
"write_buf beyond end of buffer "
"(%d requested, %u available)\n",
- len, bufsize - ctrl->index);
- len = bufsize - ctrl->index;
+ len, bufsize - elbc_fcm_ctrl->index);
+ len = bufsize - elbc_fcm_ctrl->index;
}
- memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
+ memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
/*
* This is workaround for the weird elbc hangs during nand write,
* Scott Wood says: "...perhaps difference in how long it takes a
@@ -549,9 +546,9 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
* is causing problems, and sync isn't helping for some reason."
* Reading back the last byte helps though.
*/
- in_8(&ctrl->addr[ctrl->index] + len - 1);
+ in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
- ctrl->index += len;
+ elbc_fcm_ctrl->index += len;
}
/*
@@ -562,13 +559,13 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
/* If there are still bytes in the FCM, then use the next byte. */
- if (ctrl->index < ctrl->read_bytes)
- return in_8(&ctrl->addr[ctrl->index++]);
+ if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
+ return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
- dev_err(ctrl->dev, "read_byte beyond end of buffer\n");
+ dev_err(priv->dev, "read_byte beyond end of buffer\n");
return ERR_BYTE;
}
@@ -579,18 +576,19 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
int avail;
if (len < 0)
return;
- avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
- memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail);
- ctrl->index += avail;
+ avail = min((unsigned int)len,
+ elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
+ memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
+ elbc_fcm_ctrl->index += avail;
if (len > avail)
- dev_err(ctrl->dev,
+ dev_err(priv->dev,
"read_buf beyond end of buffer "
"(%d requested, %d available)\n",
len, avail);
@@ -603,30 +601,32 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
int i;
if (len < 0) {
- dev_err(ctrl->dev, "write_buf of %d bytes", len);
+ dev_err(priv->dev, "write_buf of %d bytes", len);
return -EINVAL;
}
- if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
- dev_err(ctrl->dev,
- "verify_buf beyond end of buffer "
- "(%d requested, %u available)\n",
- len, ctrl->read_bytes - ctrl->index);
+ if ((unsigned int)len >
+ elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index) {
+ dev_err(priv->dev,
+ "verify_buf beyond end of buffer "
+ "(%d requested, %u available)\n",
+ len, elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
- ctrl->index = ctrl->read_bytes;
+ elbc_fcm_ctrl->index = elbc_fcm_ctrl->read_bytes;
return -EINVAL;
}
for (i = 0; i < len; i++)
- if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
+ if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i])
+ != buf[i])
break;
- ctrl->index += len;
- return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
+ elbc_fcm_ctrl->index += len;
+ return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO;
}
/* This function is called after Program and Erase Operations to
@@ -635,22 +635,22 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
- if (ctrl->status != LTESR_CC)
+ if (elbc_fcm_ctrl->status != LTESR_CC)
return NAND_STATUS_FAIL;
/* The chip always seems to report that it is
* write-protected, even when it is not.
*/
- return (ctrl->mdr & 0xff) | NAND_STATUS_WP;
+ return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
}
static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
unsigned int al;
@@ -665,41 +665,41 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
priv->fmr |= (12 << FMR_CWTO_SHIFT) | /* Timeout > 12 ms */
(al << FMR_AL_SHIFT);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
chip->numchips);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
chip->chipsize);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
chip->pagemask);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
chip->chip_delay);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
chip->badblockpos);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
chip->chip_shift);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
chip->page_shift);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
chip->phys_erase_shift);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
chip->ecclayout);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
chip->ecc.mode);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
chip->ecc.steps);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
chip->ecc.bytes);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
chip->ecc.total);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
chip->ecc.layout);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
mtd->erasesize);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
mtd->writesize);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
mtd->oobsize);
/* adjust Option Register and ECC to match Flash page size */
@@ -719,7 +719,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
chip->badblock_pattern = &largepage_memorybased;
}
} else {
- dev_err(ctrl->dev,
+ dev_err(priv->dev,
"fsl_elbc_init: page size %d is not supported\n",
mtd->writesize);
return -1;
@@ -750,18 +750,19 @@ static void fsl_elbc_write_page(struct mtd_info *mtd,
const uint8_t *buf)
{
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
- ctrl->oob_poi = chip->oob_poi;
+ elbc_fcm_ctrl->oob_poi = chip->oob_poi;
}
static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
{
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct nand_chip *chip = &priv->chip;
dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
@@ -790,7 +791,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
NAND_USE_FLASH_BBT;
- chip->controller = &ctrl->controller;
+ chip->controller = &elbc_fcm_ctrl->controller;
chip->priv = priv;
chip->ecc.read_page = fsl_elbc_read_page;
@@ -815,8 +816,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
{
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
-
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
nand_release(&priv->mtd);
kfree(priv->mtd.name);
@@ -824,18 +824,21 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
if (priv->vbase)
iounmap(priv->vbase);
- ctrl->chips[priv->bank] = NULL;
+ elbc_fcm_ctrl->chips[priv->bank] = NULL;
kfree(priv);
-
+ kfree(elbc_fcm_ctrl);
return 0;
}
-static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
- struct device_node *node)
+static struct mutex fsl_elbc_nand_mutex;
+
+static int __devinit fsl_elbc_nand_probe(struct platform_device *dev)
{
- struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+ struct fsl_lbc_regs __iomem *lbc;
struct fsl_elbc_mtd *priv;
struct resource res;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = NULL;
+
#ifdef CONFIG_MTD_PARTITIONS
static const char *part_probe_types[]
= { "cmdlinepart", "RedBoot", NULL };
@@ -843,11 +846,16 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
#endif
int ret;
int bank;
+ struct device_node *node = dev->dev.of_node;
+
+ if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+ return -ENODEV;
+ lbc = fsl_lbc_ctrl_dev->regs;
/* get, allocate and map the memory resource */
ret = of_address_to_resource(node, 0, &res);
if (ret) {
- dev_err(ctrl->dev, "failed to get resource\n");
+ dev_err(fsl_lbc_ctrl_dev->dev, "failed to get resource\n");
return ret;
}
@@ -861,7 +869,8 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
break;
if (bank >= MAX_BANKS) {
- dev_err(ctrl->dev, "address did not match any chip selects\n");
+ dev_err(fsl_lbc_ctrl_dev->dev, "address did not match any "
+ "chip selects\n");
return -ENODEV;
}
@@ -869,14 +878,35 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
if (!priv)
return -ENOMEM;
- ctrl->chips[bank] = priv;
+ mutex_init(&fsl_elbc_nand_mutex);
+
+ mutex_lock(&fsl_elbc_nand_mutex);
+ if (!fsl_lbc_ctrl_dev->nand) {
+ elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
+ if (!elbc_fcm_ctrl) {
+ dev_err(fsl_lbc_ctrl_dev->dev, "failed to allocate "
+ "memory\n");
+ mutex_unlock(&fsl_elbc_nand_mutex);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ spin_lock_init(&elbc_fcm_ctrl->controller.lock);
+ init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
+ fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
+ } else {
+ elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
+ }
+ mutex_unlock(&fsl_elbc_nand_mutex);
+
+ elbc_fcm_ctrl->chips[bank] = priv;
priv->bank = bank;
- priv->ctrl = ctrl;
- priv->dev = ctrl->dev;
+ priv->ctrl = fsl_lbc_ctrl_dev;
+ priv->dev = fsl_lbc_ctrl_dev->dev;
priv->vbase = ioremap(res.start, resource_size(&res));
if (!priv->vbase) {
- dev_err(ctrl->dev, "failed to map chip region\n");
+ dev_err(fsl_lbc_ctrl_dev->dev, "failed to map chip region\n");
ret = -ENOMEM;
goto err;
}
@@ -933,171 +963,48 @@ err:
return ret;
}
-static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl)
+static int fsl_elbc_nand_remove(struct platform_device *dev)
{
- struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
-
- /*
- * NAND transactions can tie up the bus for a long time, so set the
- * bus timeout to max by clearing LBCR[BMT] (highest base counter
- * value) and setting LBCR[BMTPS] to the highest prescaler value.
- */
- clrsetbits_be32(&lbc->lbcr, LBCR_BMT, 15);
-
- /* clear event registers */
- setbits32(&lbc->ltesr, LTESR_NAND_MASK);
- out_be32(&lbc->lteatr, 0);
-
- /* Enable interrupts for any detected events */
- out_be32(&lbc->lteir, LTESR_NAND_MASK);
-
- ctrl->read_bytes = 0;
- ctrl->index = 0;
- ctrl->addr = NULL;
-
- return 0;
-}
-
-static int fsl_elbc_ctrl_remove(struct platform_device *ofdev)
-{
- struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev);
int i;
-
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
for (i = 0; i < MAX_BANKS; i++)
- if (ctrl->chips[i])
- fsl_elbc_chip_remove(ctrl->chips[i]);
-
- if (ctrl->irq)
- free_irq(ctrl->irq, ctrl);
+ if (elbc_fcm_ctrl->chips[i])
+ fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]);
- if (ctrl->regs)
- iounmap(ctrl->regs);
+ fsl_lbc_ctrl_dev->nand = NULL;
+ kfree(elbc_fcm_ctrl);
- dev_set_drvdata(&ofdev->dev, NULL);
- kfree(ctrl);
return 0;
-}
-
-/* NOTE: This interrupt is also used to report other localbus events,
- * such as transaction errors on other chipselects. If we want to
- * capture those, we'll need to move the IRQ code into a shared
- * LBC driver.
- */
-static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data)
-{
- struct fsl_elbc_ctrl *ctrl = data;
- struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
- __be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK;
-
- if (status) {
- out_be32(&lbc->ltesr, status);
- out_be32(&lbc->lteatr, 0);
-
- ctrl->irq_status = status;
- smp_wmb();
- wake_up(&ctrl->irq_wait);
-
- return IRQ_HANDLED;
- }
-
- return IRQ_NONE;
}
-/* fsl_elbc_ctrl_probe
- *
- * called by device layer when it finds a device matching
- * one our driver can handled. This code allocates all of
- * the resources needed for the controller only. The
- * resources for the NAND banks themselves are allocated
- * in the chip probe function.
-*/
-
-static int __devinit fsl_elbc_ctrl_probe(struct platform_device *ofdev,
- const struct of_device_id *match)
-{
- struct device_node *child;
- struct fsl_elbc_ctrl *ctrl;
- int ret;
-
- ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
- if (!ctrl)
- return -ENOMEM;
-
- dev_set_drvdata(&ofdev->dev, ctrl);
-
- spin_lock_init(&ctrl->controller.lock);
- init_waitqueue_head(&ctrl->controller.wq);
- init_waitqueue_head(&ctrl->irq_wait);
-
- ctrl->regs = of_iomap(ofdev->dev.of_node, 0);
- if (!ctrl->regs) {
- dev_err(&ofdev->dev, "failed to get memory region\n");
- ret = -ENODEV;
- goto err;
- }
-
- ctrl->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
- if (ctrl->irq == NO_IRQ) {
- dev_err(&ofdev->dev, "failed to get irq resource\n");
- ret = -ENODEV;
- goto err;
- }
-
- ctrl->dev = &ofdev->dev;
-
- ret = fsl_elbc_ctrl_init(ctrl);
- if (ret < 0)
- goto err;
-
- ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl);
- if (ret != 0) {
- dev_err(&ofdev->dev, "failed to install irq (%d)\n",
- ctrl->irq);
- ret = ctrl->irq;
- goto err;
- }
-
- for_each_child_of_node(ofdev->dev.of_node, child)
- if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
- fsl_elbc_chip_probe(ctrl, child);
-
- return 0;
-
-err:
- fsl_elbc_ctrl_remove(ofdev);
- return ret;
-}
-
-static const struct of_device_id fsl_elbc_match[] = {
- {
- .compatible = "fsl,elbc",
- },
+static const struct of_device_id fsl_elbc_nand_match[] = {
+ { .compatible = "fsl,elbc-fcm-nand", },
{}
};
-static struct of_platform_driver fsl_elbc_ctrl_driver = {
+static struct platform_driver fsl_elbc_nand_driver = {
.driver = {
- .name = "fsl-elbc",
+ .name = "fsl,elbc-fcm-nand",
.owner = THIS_MODULE,
- .of_match_table = fsl_elbc_match,
+ .of_match_table = fsl_elbc_nand_match,
},
- .probe = fsl_elbc_ctrl_probe,
- .remove = fsl_elbc_ctrl_remove,
+ .probe = fsl_elbc_nand_probe,
+ .remove = fsl_elbc_nand_remove,
};
-static int __init fsl_elbc_init(void)
+static int __init fsl_elbc_nand_init(void)
{
- return of_register_platform_driver(&fsl_elbc_ctrl_driver);
+ return platform_driver_register(&fsl_elbc_nand_driver);
}
-static void __exit fsl_elbc_exit(void)
+static void __exit fsl_elbc_nand_exit(void)
{
- of_unregister_platform_driver(&fsl_elbc_ctrl_driver);
+ platform_driver_unregister(&fsl_elbc_nand_driver);
}
-module_init(fsl_elbc_init);
-module_exit(fsl_elbc_exit);
+module_init(fsl_elbc_nand_init);
+module_exit(fsl_elbc_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Freescale");
--
1.5.6.5
^ permalink raw reply related
* [PATCH] powerpc: define a compat_sys_recv cond_syscall
From: Ian Munsie @ 2010-09-17 7:05 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Stephen Rothwell, linux-kernel, Eric Paris, linux-next,
Paul Mackerras, Ian Munsie, Russell King, Andrew Morton,
linuxppc-dev, David S. Miller, Eric W. Biederman
In-Reply-To: <20100903132410.ede593ed.sfr@canb.auug.org.au>
From: Stephen Rothwell <sfr@canb.auug.org.au>
Since compat_sys_recv is an optionl syscall if the kernel is compiled
without networking we need a cond_syscall defined for it since it is now
wired up directly on PowerPC.
Other architectures that wire up the socket calls directly as syscalls
do not run into this issue either because they don't have to deal with
the 32bit compat versions of the syscalls or just don't wire up that
particular compat syscall directly.
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>
---
kernel/sys_ni.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index bad369e..c782fe9 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -50,6 +50,7 @@ cond_syscall(compat_sys_sendmsg);
cond_syscall(sys_recvmsg);
cond_syscall(sys_recvmmsg);
cond_syscall(compat_sys_recvmsg);
+cond_syscall(compat_sys_recv);
cond_syscall(compat_sys_recvfrom);
cond_syscall(compat_sys_recvmmsg);
cond_syscall(sys_socketcall);
--
1.7.1
^ permalink raw reply related
* Re: linux support for freescale e5500 core?
From: Chris Friesen @ 2010-09-17 6:36 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, paulus, Scott Wood, timur
In-Reply-To: <1284701585.30449.102.camel@pasglop>
On 09/16/2010 11:33 PM, Benjamin Herrenschmidt wrote:
> On Fri, 2010-09-17 at 00:17 -0500, Kumar Gala wrote:
>> Not sure how the 970 bit worked, but this seems a bit problematic for
>> switching between kernel and application for how we do this on
>> e500mc/e5500. We'd have to touch the control bit on every exception
>> path which seems ugly to me.
>
> Unless the kernel uses dcbzl (feature fixup replacement ?)
>
> In that case it's on context switch only.
This is basically what we did. Kernel and system libraries (glibc and
friends) always use dcbzl, process flag indicates compatibility, touch
the control bit on task context switch if the prev and next processes
have different compatibility modes.
On the 970 you have to invalidate the entire icache whenever you change
the control bit. This is a pain involving a loop that calls icbi on 512
cachelines.
Chris
--
Chris Friesen
Software Developer
GENBAND
chris.friesen@genband.com
www.genband.com
^ permalink raw reply
* Re: linux support for freescale e5500 core?
From: Benjamin Herrenschmidt @ 2010-09-17 5:33 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, Chris Friesen, paulus, Scott Wood, timur
In-Reply-To: <7EDBB1DD-BB9D-417D-8F4E-B9D5D9E030EF@kernel.crashing.org>
On Fri, 2010-09-17 at 00:17 -0500, Kumar Gala wrote:
> Not sure how the 970 bit worked, but this seems a bit problematic for
> switching between kernel and application for how we do this on
> e500mc/e5500. We'd have to touch the control bit on every exception
> path which seems ugly to me.
Unless the kernel uses dcbzl (feature fixup replacement ?)
In that case it's on context switch only.
Cheers,
Ben.
^ permalink raw reply
* Re: linux support for freescale e5500 core?
From: Kumar Gala @ 2010-09-17 5:17 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev, Chris Friesen, paulus, Scott Wood, timur
In-Reply-To: <1284681832.30449.101.camel@pasglop>
On Sep 16, 2010, at 7:03 PM, Benjamin Herrenschmidt wrote:
> On Thu, 2010-09-16 at 16:26 -0600, Chris Friesen wrote:
>>> Sounds like a candidate for upstreaming the patch :-)
>>=20
>> As I recall we proposed upstreaming it a while back but there wasn't =
a
>> lot of interest since it's most useful in supporting poorly-written
>> legacy apps. :)=20
>=20
> Heh. Well as long as only 970 had that bit ... but with e5500 coming =
up
> with that too, I suppose it makes -some- sense. Let's at least look at
> the approach you took and we can decide based on how invasive/ugly it
> is :-)
Not sure how the 970 bit worked, but this seems a bit problematic for =
switching between kernel and application for how we do this on =
e500mc/e5500. We'd have to touch the control bit on every exception =
path which seems ugly to me.
- k=
^ permalink raw reply
* Re: linux-next: build failure after merge of the final tree (powerpc related)
From: Stephen Rothwell @ 2010-09-17 4:27 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev
Cc: linux-next, linux-kernel, Ian Munsie
In-Reply-To: <20100903132410.ede593ed.sfr@canb.auug.org.au>
[-- Attachment #1: Type: text/plain, Size: 1374 bytes --]
Hi Ben,
On Fri, 3 Sep 2010 13:24:10 +1000 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
>
> After merging the final tree, today's linux-next build
> (powerpc64 allnoconfig) failed like this:
>
> arch/powerpc/kernel/built-in.o: In function `.sys_call_table':
> (.text+0x8d48): undefined reference to `.compat_sys_recv'
>
> Caused by commit 86250b9d12caa1a3dee12a7cf638b7dd70eaadb6 ("powerpc: Wire
> up direct socket system calls").
>
> I have applied this patch for today:
>
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Fri, 3 Sep 2010 13:19:04 +1000
> Subject: [PATCH] powerpc: define a compat_sys_recv cond_syscall
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
> kernel/sys_ni.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
> index bad369e..c782fe9 100644
> --- a/kernel/sys_ni.c
> +++ b/kernel/sys_ni.c
> @@ -50,6 +50,7 @@ cond_syscall(compat_sys_sendmsg);
> cond_syscall(sys_recvmsg);
> cond_syscall(sys_recvmmsg);
> cond_syscall(compat_sys_recvmsg);
> +cond_syscall(compat_sys_recv);
> cond_syscall(compat_sys_recvfrom);
> cond_syscall(compat_sys_recvmmsg);
> cond_syscall(sys_socketcall);
> --
> 1.7.1
Ping?
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* Re: Generating elf kernel ?
From: tiejun.chen @ 2010-09-17 1:58 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, Guillaume Dargaud
In-Reply-To: <20100916120944.11c45c31@schlenkerla.am.freescale.net>
Scott Wood wrote:
> On Thu, 16 Sep 2010 10:37:32 +0800
> "tiejun.chen" <tiejun.chen@windriver.com> wrote:
>
>> 1> can you load the Linux vmlinux directly to the physical address '0' on
>> current bootloader?
>
> That depends on what bootloader we're talking about -- I don't know
> what the original poster's custom loader can do. Obviously the
> bootloader itself would have to be executing from some other address
> (e.g. U-Boot runs from the top of RAM).
>
>> 2> additionally you have to find a way to pass dtb to the native vmlinux.
>
> Yes, of course. But that's a different issue. :-)
>
>> I believe the hypervisor can boot vmlinux directly. But your so-called vmlinux
>> should be guest OS. And the hypervisor will handle/assit TLB exception for the
>> guest OS on MMU. Right? So you can use the hypervisor to load vmlinux to any
>> physical address as you expect.
>
> I was just using our hypervisor as an example, since it has an ELF
> loader that can pass a device tree.
>
>> But the guest OS should not be same as the native Linux.
>
> The guest OS *is* the same as native Linux, as far as TLB handling is
> concerned.
Looks you means the TLB exception handler should be same between the native and
the guest OS. Right?
Here I assume we're talking about e500mc since as far as I know for Freescale
only e500mc is designed to support virtual machine based on ISA 2.0.6.
I also know all TLB exceptions can direct to the guest OS when we enable
EPCR[DTLBGS|ITLBGS|DSIGS|ISIGS]. But some TLB instructions (i.e. tlbwe )are the
privileged instructions. So the guest OS always trap into the hypervisor and
then the hypervisor should complete the real action with appropriate physical
address. And also the hypervisor can supervisor if the guest OS want to access
the invalid physical space.
So I don't think the guest OS is same as native Linux :)
Cheers
Tiejun
>
> -Scott
>
>
^ permalink raw reply
* Re: linux support for freescale e5500 core?
From: Benjamin Herrenschmidt @ 2010-09-17 0:03 UTC (permalink / raw)
To: Chris Friesen; +Cc: Chris Friesen, Scott Wood, paulus, timur, linuxppc-dev
In-Reply-To: <4C92998C.7000903@nortel.com>
On Thu, 2010-09-16 at 16:26 -0600, Chris Friesen wrote:
> > Sounds like a candidate for upstreaming the patch :-)
>
> As I recall we proposed upstreaming it a while back but there wasn't a
> lot of interest since it's most useful in supporting poorly-written
> legacy apps. :)
Heh. Well as long as only 970 had that bit ... but with e5500 coming up
with that too, I suppose it makes -some- sense. Let's at least look at
the approach you took and we can decide based on how invasive/ugly it
is :-)
Cheers,
Ben.
^ permalink raw reply
* [PATCH 3/4] powerpc/85xx: Minor fixups for kexec on 85xx
From: Matthew McClintock @ 2010-09-16 22:58 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Matthew McClintock, kumar.gala
In-Reply-To: <1284677906-23787-1-git-send-email-msm@freescale.com>
Make kexec_down_cpus atmoic since it will be incremented by all
cores as they are coming down
Remove duplicate calls to mpc85xx_smp_kexec_down, now it's called
by the crash and normal kexec pathway only once
Increase the timeout to wait for other cores to shutdown
Signed-off-by: Matthew McClintock <msm@freescale.com>
---
arch/powerpc/platforms/85xx/smp.c | 24 +++++++++++-------------
1 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index cb8ad3b..29416a9 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -114,17 +114,15 @@ struct smp_ops_t smp_85xx_ops = {
};
#ifdef CONFIG_KEXEC
-static int kexec_down_cpus = 0;
+atomic_t kexec_down_cpus = ATOMIC_INIT(0);
void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary)
{
- /* When crashing, this gets called on all CPU's we only
- * take down the non-boot cpus */
- if (smp_processor_id() != boot_cpuid)
- {
- local_irq_disable();
- kexec_down_cpus++;
+ local_irq_disable();
+ if (secondary) {
+ atomic_inc(&kexec_down_cpus);
+ /* loop forever */
while (1);
}
}
@@ -137,14 +135,14 @@ static void mpc85xx_smp_kexec_down(void *arg)
static void mpc85xx_smp_machine_kexec(struct kimage *image)
{
- int timeout = 2000;
- int i;
+ int timeout = INT_MAX;
+ int i, num_cpus = num_present_cpus();
- set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid));
- smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
+ if (image->type == KEXEC_TYPE_DEFAULT)
+ smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
- while ( (kexec_down_cpus != (num_online_cpus() - 1)) &&
+ while ( (atomic_read(&kexec_down_cpus) != (num_cpus - 1)) &&
( timeout > 0 ) )
{
timeout--;
@@ -153,7 +151,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
if ( !timeout )
printk(KERN_ERR "Unable to bring down secondary cpu(s)");
- for (i = 0; i < num_present_cpus(); i++)
+ for (i = 0; i < num_cpus; i++)
{
if ( i == smp_processor_id() ) continue;
mpic_reset_core(i);
--
1.6.6.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox