Merge branch 'dmaengine' into async-tx-next

Conflicts:
	crypto/async_tx/async_xor.c
	drivers/dma/ioat/dma_v2.h
	drivers/dma/ioat/pci.c
	drivers/md/raid5.c
This commit is contained in:
Dan Williams
2009-09-08 17:55:21 -07:00
7762 changed files with 785472 additions and 404091 deletions

View File

@@ -50,6 +50,14 @@ config DW_DMAC
Support the Synopsys DesignWare AHB DMA controller. This
can be integrated in chips such as the Atmel AT32ap7000.
config AT_HDMAC
tristate "Atmel AHB DMA support"
depends on ARCH_AT91SAM9RL
select DMA_ENGINE
help
Support the Atmel AHB DMA controller. This can be integrated in
chips such as the Atmel AT91SAM9RL.
config FSL_DMA
tristate "Freescale Elo and Elo Plus DMA support"
depends on FSL_SOC
@@ -85,6 +93,14 @@ config MX3_IPU_IRQS
To avoid bloating the irq_desc[] array we allocate a sufficient
number of IRQ slots and map them dynamically to specific sources.
config TXX9_DMAC
tristate "Toshiba TXx9 SoC DMA support"
depends on MACH_TX49XX || MACH_TX39XX
select DMA_ENGINE
help
Support the TXx9 SoC internal DMA controller. This can be
integrated in chips such as the Toshiba TX4927/38/39.
config DMA_ENGINE
bool
@@ -104,7 +120,7 @@ config NET_DMA
config ASYNC_TX_DMA
bool "Async_tx: Offload support for the async_tx api"
depends on DMA_ENGINE
depends on DMA_ENGINE && !HIGHMEM64G
help
This allows the async_tx api to take advantage of offload engines for
memcpy, memset, xor, and raid6 p+q operations. If your platform has

View File

@@ -6,4 +6,6 @@ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
obj-$(CONFIG_MV_XOR) += mv_xor.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
obj-$(CONFIG_MX3_IPU) += ipu/
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o

1215
drivers/dma/at_hdmac.c Normal file

File diff suppressed because it is too large Load Diff

354
drivers/dma/at_hdmac_regs.h Normal file
View File

@@ -0,0 +1,354 @@
/*
* Header file for the Atmel AHB DMA Controller driver
*
* Copyright (C) 2008 Atmel Corporation
*
* 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.
*/
#ifndef AT_HDMAC_REGS_H
#define AT_HDMAC_REGS_H
#include <mach/at_hdmac.h>
#define AT_DMA_MAX_NR_CHANNELS 8
#define AT_DMA_GCFG 0x00 /* Global Configuration Register */
#define AT_DMA_IF_BIGEND(i) (0x1 << (i)) /* AHB-Lite Interface i in Big-endian mode */
#define AT_DMA_ARB_CFG (0x1 << 4) /* Arbiter mode. */
#define AT_DMA_ARB_CFG_FIXED (0x0 << 4)
#define AT_DMA_ARB_CFG_ROUND_ROBIN (0x1 << 4)
#define AT_DMA_EN 0x04 /* Controller Enable Register */
#define AT_DMA_ENABLE (0x1 << 0)
#define AT_DMA_SREQ 0x08 /* Software Single Request Register */
#define AT_DMA_SSREQ(x) (0x1 << ((x) << 1)) /* Request a source single transfer on channel x */
#define AT_DMA_DSREQ(x) (0x1 << (1 + ((x) << 1))) /* Request a destination single transfer on channel x */
#define AT_DMA_CREQ 0x0C /* Software Chunk Transfer Request Register */
#define AT_DMA_SCREQ(x) (0x1 << ((x) << 1)) /* Request a source chunk transfer on channel x */
#define AT_DMA_DCREQ(x) (0x1 << (1 + ((x) << 1))) /* Request a destination chunk transfer on channel x */
#define AT_DMA_LAST 0x10 /* Software Last Transfer Flag Register */
#define AT_DMA_SLAST(x) (0x1 << ((x) << 1)) /* This src rq is last tx of buffer on channel x */
#define AT_DMA_DLAST(x) (0x1 << (1 + ((x) << 1))) /* This dst rq is last tx of buffer on channel x */
#define AT_DMA_SYNC 0x14 /* Request Synchronization Register */
#define AT_DMA_SYR(h) (0x1 << (h)) /* Synchronize handshake line h */
/* Error, Chained Buffer transfer completed and Buffer transfer completed Interrupt registers */
#define AT_DMA_EBCIER 0x18 /* Enable register */
#define AT_DMA_EBCIDR 0x1C /* Disable register */
#define AT_DMA_EBCIMR 0x20 /* Mask Register */
#define AT_DMA_EBCISR 0x24 /* Status Register */
#define AT_DMA_CBTC_OFFSET 8
#define AT_DMA_ERR_OFFSET 16
#define AT_DMA_BTC(x) (0x1 << (x))
#define AT_DMA_CBTC(x) (0x1 << (AT_DMA_CBTC_OFFSET + (x)))
#define AT_DMA_ERR(x) (0x1 << (AT_DMA_ERR_OFFSET + (x)))
#define AT_DMA_CHER 0x28 /* Channel Handler Enable Register */
#define AT_DMA_ENA(x) (0x1 << (x))
#define AT_DMA_SUSP(x) (0x1 << ( 8 + (x)))
#define AT_DMA_KEEP(x) (0x1 << (24 + (x)))
#define AT_DMA_CHDR 0x2C /* Channel Handler Disable Register */
#define AT_DMA_DIS(x) (0x1 << (x))
#define AT_DMA_RES(x) (0x1 << ( 8 + (x)))
#define AT_DMA_CHSR 0x30 /* Channel Handler Status Register */
#define AT_DMA_EMPT(x) (0x1 << (16 + (x)))
#define AT_DMA_STAL(x) (0x1 << (24 + (x)))
#define AT_DMA_CH_REGS_BASE 0x3C /* Channel registers base address */
#define ch_regs(x) (AT_DMA_CH_REGS_BASE + (x) * 0x28) /* Channel x base addr */
/* Hardware register offset for each channel */
#define ATC_SADDR_OFFSET 0x00 /* Source Address Register */
#define ATC_DADDR_OFFSET 0x04 /* Destination Address Register */
#define ATC_DSCR_OFFSET 0x08 /* Descriptor Address Register */
#define ATC_CTRLA_OFFSET 0x0C /* Control A Register */
#define ATC_CTRLB_OFFSET 0x10 /* Control B Register */
#define ATC_CFG_OFFSET 0x14 /* Configuration Register */
#define ATC_SPIP_OFFSET 0x18 /* Src PIP Configuration Register */
#define ATC_DPIP_OFFSET 0x1C /* Dst PIP Configuration Register */
/* Bitfield definitions */
/* Bitfields in DSCR */
#define ATC_DSCR_IF(i) (0x3 & (i)) /* Dsc feched via AHB-Lite Interface i */
/* Bitfields in CTRLA */
#define ATC_BTSIZE_MAX 0xFFFFUL /* Maximum Buffer Transfer Size */
#define ATC_BTSIZE(x) (ATC_BTSIZE_MAX & (x)) /* Buffer Transfer Size */
/* Chunck Tranfer size definitions are in at_hdmac.h */
#define ATC_SRC_WIDTH_MASK (0x3 << 24) /* Source Single Transfer Size */
#define ATC_SRC_WIDTH(x) ((x) << 24)
#define ATC_SRC_WIDTH_BYTE (0x0 << 24)
#define ATC_SRC_WIDTH_HALFWORD (0x1 << 24)
#define ATC_SRC_WIDTH_WORD (0x2 << 24)
#define ATC_DST_WIDTH_MASK (0x3 << 28) /* Destination Single Transfer Size */
#define ATC_DST_WIDTH(x) ((x) << 28)
#define ATC_DST_WIDTH_BYTE (0x0 << 28)
#define ATC_DST_WIDTH_HALFWORD (0x1 << 28)
#define ATC_DST_WIDTH_WORD (0x2 << 28)
#define ATC_DONE (0x1 << 31) /* Tx Done (only written back in descriptor) */
/* Bitfields in CTRLB */
#define ATC_SIF(i) (0x3 & (i)) /* Src tx done via AHB-Lite Interface i */
#define ATC_DIF(i) ((0x3 & (i)) << 4) /* Dst tx done via AHB-Lite Interface i */
#define ATC_SRC_PIP (0x1 << 8) /* Source Picture-in-Picture enabled */
#define ATC_DST_PIP (0x1 << 12) /* Destination Picture-in-Picture enabled */
#define ATC_SRC_DSCR_DIS (0x1 << 16) /* Src Descriptor fetch disable */
#define ATC_DST_DSCR_DIS (0x1 << 20) /* Dst Descriptor fetch disable */
#define ATC_FC_MASK (0x7 << 21) /* Choose Flow Controller */
#define ATC_FC_MEM2MEM (0x0 << 21) /* Mem-to-Mem (DMA) */
#define ATC_FC_MEM2PER (0x1 << 21) /* Mem-to-Periph (DMA) */
#define ATC_FC_PER2MEM (0x2 << 21) /* Periph-to-Mem (DMA) */
#define ATC_FC_PER2PER (0x3 << 21) /* Periph-to-Periph (DMA) */
#define ATC_FC_PER2MEM_PER (0x4 << 21) /* Periph-to-Mem (Peripheral) */
#define ATC_FC_MEM2PER_PER (0x5 << 21) /* Mem-to-Periph (Peripheral) */
#define ATC_FC_PER2PER_SRCPER (0x6 << 21) /* Periph-to-Periph (Src Peripheral) */
#define ATC_FC_PER2PER_DSTPER (0x7 << 21) /* Periph-to-Periph (Dst Peripheral) */
#define ATC_SRC_ADDR_MODE_MASK (0x3 << 24)
#define ATC_SRC_ADDR_MODE_INCR (0x0 << 24) /* Incrementing Mode */
#define ATC_SRC_ADDR_MODE_DECR (0x1 << 24) /* Decrementing Mode */
#define ATC_SRC_ADDR_MODE_FIXED (0x2 << 24) /* Fixed Mode */
#define ATC_DST_ADDR_MODE_MASK (0x3 << 28)
#define ATC_DST_ADDR_MODE_INCR (0x0 << 28) /* Incrementing Mode */
#define ATC_DST_ADDR_MODE_DECR (0x1 << 28) /* Decrementing Mode */
#define ATC_DST_ADDR_MODE_FIXED (0x2 << 28) /* Fixed Mode */
#define ATC_IEN (0x1 << 30) /* BTC interrupt enable (active low) */
#define ATC_AUTO (0x1 << 31) /* Auto multiple buffer tx enable */
/* Bitfields in CFG */
/* are in at_hdmac.h */
/* Bitfields in SPIP */
#define ATC_SPIP_HOLE(x) (0xFFFFU & (x))
#define ATC_SPIP_BOUNDARY(x) ((0x3FF & (x)) << 16)
/* Bitfields in DPIP */
#define ATC_DPIP_HOLE(x) (0xFFFFU & (x))
#define ATC_DPIP_BOUNDARY(x) ((0x3FF & (x)) << 16)
/*-- descriptors -----------------------------------------------------*/
/* LLI == Linked List Item; aka DMA buffer descriptor */
struct at_lli {
/* values that are not changed by hardware */
dma_addr_t saddr;
dma_addr_t daddr;
/* value that may get written back: */
u32 ctrla;
/* more values that are not changed by hardware */
u32 ctrlb;
dma_addr_t dscr; /* chain to next lli */
};
/**
* struct at_desc - software descriptor
* @at_lli: hardware lli structure
* @txd: support for the async_tx api
* @desc_node: node on the channed descriptors list
* @len: total transaction bytecount
*/
struct at_desc {
/* FIRST values the hardware uses */
struct at_lli lli;
/* THEN values for driver housekeeping */
struct list_head tx_list;
struct dma_async_tx_descriptor txd;
struct list_head desc_node;
size_t len;
};
static inline struct at_desc *
txd_to_at_desc(struct dma_async_tx_descriptor *txd)
{
return container_of(txd, struct at_desc, txd);
}
/*-- Channels --------------------------------------------------------*/
/**
* struct at_dma_chan - internal representation of an Atmel HDMAC channel
* @chan_common: common dmaengine channel object members
* @device: parent device
* @ch_regs: memory mapped register base
* @mask: channel index in a mask
* @error_status: transmit error status information from irq handler
* to tasklet (use atomic operations)
* @tasklet: bottom half to finish transaction work
* @lock: serializes enqueue/dequeue operations to descriptors lists
* @completed_cookie: identifier for the most recently completed operation
* @active_list: list of descriptors dmaengine is being running on
* @queue: list of descriptors ready to be submitted to engine
* @free_list: list of descriptors usable by the channel
* @descs_allocated: records the actual size of the descriptor pool
*/
struct at_dma_chan {
struct dma_chan chan_common;
struct at_dma *device;
void __iomem *ch_regs;
u8 mask;
unsigned long error_status;
struct tasklet_struct tasklet;
spinlock_t lock;
/* these other elements are all protected by lock */
dma_cookie_t completed_cookie;
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
unsigned int descs_allocated;
};
#define channel_readl(atchan, name) \
__raw_readl((atchan)->ch_regs + ATC_##name##_OFFSET)
#define channel_writel(atchan, name, val) \
__raw_writel((val), (atchan)->ch_regs + ATC_##name##_OFFSET)
static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
{
return container_of(dchan, struct at_dma_chan, chan_common);
}
/*-- Controller ------------------------------------------------------*/
/**
* struct at_dma - internal representation of an Atmel HDMA Controller
* @chan_common: common dmaengine dma_device object members
* @ch_regs: memory mapped register base
* @clk: dma controller clock
* @all_chan_mask: all channels availlable in a mask
* @dma_desc_pool: base of DMA descriptor region (DMA address)
* @chan: channels table to store at_dma_chan structures
*/
struct at_dma {
struct dma_device dma_common;
void __iomem *regs;
struct clk *clk;
u8 all_chan_mask;
struct dma_pool *dma_desc_pool;
/* AT THE END channels table */
struct at_dma_chan chan[0];
};
#define dma_readl(atdma, name) \
__raw_readl((atdma)->regs + AT_DMA_##name)
#define dma_writel(atdma, name, val) \
__raw_writel((val), (atdma)->regs + AT_DMA_##name)
static inline struct at_dma *to_at_dma(struct dma_device *ddev)
{
return container_of(ddev, struct at_dma, dma_common);
}
/*-- Helper functions ------------------------------------------------*/
static struct device *chan2dev(struct dma_chan *chan)
{
return &chan->dev->device;
}
static struct device *chan2parent(struct dma_chan *chan)
{
return chan->dev->device.parent;
}
#if defined(VERBOSE_DEBUG)
static void vdbg_dump_regs(struct at_dma_chan *atchan)
{
struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
dev_err(chan2dev(&atchan->chan_common),
" channel %d : imr = 0x%x, chsr = 0x%x\n",
atchan->chan_common.chan_id,
dma_readl(atdma, EBCIMR),
dma_readl(atdma, CHSR));
dev_err(chan2dev(&atchan->chan_common),
" channel: s0x%x d0x%x ctrl0x%x:0x%x cfg0x%x l0x%x\n",
channel_readl(atchan, SADDR),
channel_readl(atchan, DADDR),
channel_readl(atchan, CTRLA),
channel_readl(atchan, CTRLB),
channel_readl(atchan, CFG),
channel_readl(atchan, DSCR));
}
#else
static void vdbg_dump_regs(struct at_dma_chan *atchan) {}
#endif
static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli)
{
dev_printk(KERN_CRIT, chan2dev(&atchan->chan_common),
" desc: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n",
lli->saddr, lli->daddr,
lli->ctrla, lli->ctrlb, lli->dscr);
}
static void atc_setup_irq(struct at_dma_chan *atchan, int on)
{
struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
u32 ebci;
/* enable interrupts on buffer chain completion & error */
ebci = AT_DMA_CBTC(atchan->chan_common.chan_id)
| AT_DMA_ERR(atchan->chan_common.chan_id);
if (on)
dma_writel(atdma, EBCIER, ebci);
else
dma_writel(atdma, EBCIDR, ebci);
}
static inline void atc_enable_irq(struct at_dma_chan *atchan)
{
atc_setup_irq(atchan, 1);
}
static inline void atc_disable_irq(struct at_dma_chan *atchan)
{
atc_setup_irq(atchan, 0);
}
/**
* atc_chan_is_enabled - test if given channel is enabled
* @atchan: channel we want to test status
*/
static inline int atc_chan_is_enabled(struct at_dma_chan *atchan)
{
struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
return !!(dma_readl(atdma, CHSR) & atchan->mask);
}
/**
* set_desc_eol - set end-of-link to descriptor so it will end transfer
* @desc: descriptor, signle or at the end of a chain, to end chain on
*/
static void set_desc_eol(struct at_desc *desc)
{
desc->lli.ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS;
desc->lli.dscr = 0;
}
#endif /* AT_HDMAC_REGS_H */

View File

@@ -977,7 +977,6 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
{
tx->chan = chan;
spin_lock_init(&tx->lock);
INIT_LIST_HEAD(&tx->tx_list);
}
EXPORT_SYMBOL(dma_async_tx_descriptor_init);

View File

@@ -38,6 +38,11 @@ module_param(max_channels, uint, S_IRUGO);
MODULE_PARM_DESC(max_channels,
"Maximum number of channels to use (default: all)");
static unsigned int iterations;
module_param(iterations, uint, S_IRUGO);
MODULE_PARM_DESC(iterations,
"Iterations before stopping test (default: infinite)");
static unsigned int xor_sources = 3;
module_param(xor_sources, uint, S_IRUGO);
MODULE_PARM_DESC(xor_sources,
@@ -119,7 +124,7 @@ static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len)
buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
for ( ; i < start + len; i++)
buf[i] = PATTERN_SRC | PATTERN_COPY
| (~i & PATTERN_COUNT_MASK);;
| (~i & PATTERN_COUNT_MASK);
for ( ; i < test_buf_size; i++)
buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
buf++;
@@ -281,7 +286,8 @@ static int dmatest_func(void *data)
flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT;
while (!kthread_should_stop()) {
while (!kthread_should_stop()
&& !(iterations && total_tests >= iterations)) {
struct dma_device *dev = chan->device;
struct dma_async_tx_descriptor *tx = NULL;
dma_addr_t dma_srcs[src_cnt];
@@ -450,6 +456,13 @@ err_srcbuf:
err_srcs:
pr_notice("%s: terminating after %u tests, %u failures (status %d)\n",
thread_name, total_tests, failed_tests, ret);
if (iterations > 0)
while (!kthread_should_stop()) {
DECLARE_WAIT_QUEUE_HEAD(wait_dmatest_exit);
interruptible_sleep_on(&wait_dmatest_exit);
}
return ret;
}
@@ -531,11 +544,11 @@ static int dmatest_add_channel(struct dma_chan *chan)
if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
cnt = dmatest_add_threads(dtc, DMA_MEMCPY);
thread_count += cnt > 0 ?: 0;
thread_count += cnt > 0 ? cnt : 0;
}
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
cnt = dmatest_add_threads(dtc, DMA_XOR);
thread_count += cnt > 0 ?: 0;
thread_count += cnt > 0 ? cnt : 0;
}
if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) {
cnt = dmatest_add_threads(dtc, DMA_PQ);

View File

@@ -116,7 +116,7 @@ static void dwc_sync_desc_for_cpu(struct dw_dma_chan *dwc, struct dw_desc *desc)
{
struct dw_desc *child;
list_for_each_entry(child, &desc->txd.tx_list, desc_node)
list_for_each_entry(child, &desc->tx_list, desc_node)
dma_sync_single_for_cpu(chan2parent(&dwc->chan),
child->txd.phys, sizeof(child->lli),
DMA_TO_DEVICE);
@@ -137,11 +137,11 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
dwc_sync_desc_for_cpu(dwc, desc);
spin_lock_bh(&dwc->lock);
list_for_each_entry(child, &desc->txd.tx_list, desc_node)
list_for_each_entry(child, &desc->tx_list, desc_node)
dev_vdbg(chan2dev(&dwc->chan),
"moving child desc %p to freelist\n",
child);
list_splice_init(&desc->txd.tx_list, &dwc->free_list);
list_splice_init(&desc->tx_list, &dwc->free_list);
dev_vdbg(chan2dev(&dwc->chan), "moving desc %p to freelist\n", desc);
list_add(&desc->desc_node, &dwc->free_list);
spin_unlock_bh(&dwc->lock);
@@ -209,19 +209,28 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
param = txd->callback_param;
dwc_sync_desc_for_cpu(dwc, desc);
list_splice_init(&txd->tx_list, &dwc->free_list);
list_splice_init(&desc->tx_list, &dwc->free_list);
list_move(&desc->desc_node, &dwc->free_list);
/*
* We use dma_unmap_page() regardless of how the buffers were
* mapped before they were submitted...
*/
if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP))
dma_unmap_page(chan2parent(&dwc->chan), desc->lli.dar,
desc->len, DMA_FROM_DEVICE);
if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP))
dma_unmap_page(chan2parent(&dwc->chan), desc->lli.sar,
desc->len, DMA_TO_DEVICE);
if (!dwc->chan.private) {
struct device *parent = chan2parent(&dwc->chan);
if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
dma_unmap_single(parent, desc->lli.dar,
desc->len, DMA_FROM_DEVICE);
else
dma_unmap_page(parent, desc->lli.dar,
desc->len, DMA_FROM_DEVICE);
}
if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
dma_unmap_single(parent, desc->lli.sar,
desc->len, DMA_TO_DEVICE);
else
dma_unmap_page(parent, desc->lli.sar,
desc->len, DMA_TO_DEVICE);
}
}
/*
* The API requires that no submissions are done from a
@@ -289,7 +298,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
/* This one is currently in progress */
return;
list_for_each_entry(child, &desc->txd.tx_list, desc_node)
list_for_each_entry(child, &desc->tx_list, desc_node)
if (child->lli.llp == llp)
/* Currently in progress */
return;
@@ -356,7 +365,7 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
dev_printk(KERN_CRIT, chan2dev(&dwc->chan),
" cookie: %d\n", bad_desc->txd.cookie);
dwc_dump_lli(dwc, &bad_desc->lli);
list_for_each_entry(child, &bad_desc->txd.tx_list, desc_node)
list_for_each_entry(child, &bad_desc->tx_list, desc_node)
dwc_dump_lli(dwc, &child->lli);
/* Pretend the descriptor completed successfully */
@@ -608,7 +617,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
prev->txd.phys, sizeof(prev->lli),
DMA_TO_DEVICE);
list_add_tail(&desc->desc_node,
&first->txd.tx_list);
&first->tx_list);
}
prev = desc;
}
@@ -658,8 +667,6 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
reg_width = dws->reg_width;
prev = first = NULL;
sg_len = dma_map_sg(chan2parent(chan), sgl, sg_len, direction);
switch (direction) {
case DMA_TO_DEVICE:
ctllo = (DWC_DEFAULT_CTLLO
@@ -700,7 +707,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
sizeof(prev->lli),
DMA_TO_DEVICE);
list_add_tail(&desc->desc_node,
&first->txd.tx_list);
&first->tx_list);
}
prev = desc;
total_len += len;
@@ -746,7 +753,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
sizeof(prev->lli),
DMA_TO_DEVICE);
list_add_tail(&desc->desc_node,
&first->txd.tx_list);
&first->tx_list);
}
prev = desc;
total_len += len;
@@ -902,6 +909,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
break;
}
INIT_LIST_HEAD(&desc->tx_list);
dma_async_tx_descriptor_init(&desc->txd, chan);
desc->txd.tx_submit = dwc_tx_submit;
desc->txd.flags = DMA_CTRL_ACK;

View File

@@ -217,6 +217,7 @@ struct dw_desc {
/* THEN values for driver housekeeping */
struct list_head desc_node;
struct list_head tx_list;
struct dma_async_tx_descriptor txd;
size_t len;
};

View File

@@ -12,6 +12,11 @@
* also fit for MPC8560, MPC8555, MPC8548, MPC8641, and etc.
* The support for MPC8349 DMA contorller is also added.
*
* This driver instructs the DMA controller to issue the PCI Read Multiple
* command for PCI read operations, instead of using the default PCI Read Line
* command. Please be aware that this setting may result in read pre-fetching
* on some platforms.
*
* This 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
@@ -29,6 +34,7 @@
#include <linux/dmapool.h>
#include <linux/of_platform.h>
#include <asm/fsldma.h>
#include "fsldma.h"
static void dma_init(struct fsl_dma_chan *fsl_chan)
@@ -49,9 +55,10 @@ static void dma_init(struct fsl_dma_chan *fsl_chan)
case FSL_DMA_IP_83XX:
/* Set the channel to below modes:
* EOTIE - End-of-transfer interrupt enable
* PRC_RM - PCI read multiple
*/
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE,
32);
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE
| FSL_DMA_MR_PRC_RM, 32);
break;
}
@@ -136,15 +143,16 @@ static int dma_is_idle(struct fsl_dma_chan *fsl_chan)
static void dma_start(struct fsl_dma_chan *fsl_chan)
{
u32 mr_set = 0;;
u32 mr_set = 0;
if (fsl_chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
DMA_OUT(fsl_chan, &fsl_chan->reg_base->bcr, 0, 32);
mr_set |= FSL_DMA_MR_EMP_EN;
} else
} else if ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
& ~FSL_DMA_MR_EMP_EN, 32);
}
if (fsl_chan->feature & FSL_DMA_CHAN_START_EXT)
mr_set |= FSL_DMA_MR_EMS_EN;
@@ -272,29 +280,41 @@ static void fsl_chan_set_dest_loop_size(struct fsl_dma_chan *fsl_chan, int size)
}
}
/**
* fsl_chan_set_request_count - Set DMA Request Count for external control
* @fsl_chan : Freescale DMA channel
* @size : Number of bytes to transfer in a single request
*
* The Freescale DMA channel can be controlled by the external signal DREQ#.
* The DMA request count is how many bytes are allowed to transfer before
* pausing the channel, after which a new assertion of DREQ# resumes channel
* operation.
*
* A size of 0 disables external pause control. The maximum size is 1024.
*/
static void fsl_chan_set_request_count(struct fsl_dma_chan *fsl_chan, int size)
{
BUG_ON(size > 1024);
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
| ((__ilog2(size) << 24) & 0x0f000000),
32);
}
/**
* fsl_chan_toggle_ext_pause - Toggle channel external pause status
* @fsl_chan : Freescale DMA channel
* @size : Pause control size, 0 for disable external pause control.
* The maximum is 1024.
* @enable : 0 is disabled, 1 is enabled.
*
* The Freescale DMA channel can be controlled by the external
* signal DREQ#. The pause control size is how many bytes are allowed
* to transfer before pausing the channel, after which a new assertion
* of DREQ# resumes channel operation.
* The Freescale DMA channel can be controlled by the external signal DREQ#.
* The DMA Request Count feature should be used in addition to this feature
* to set the number of bytes to transfer before pausing the channel.
*/
static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int size)
static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int enable)
{
if (size > 1024)
return;
if (size) {
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
| ((__ilog2(size) << 24) & 0x0f000000),
32);
if (enable)
fsl_chan->feature |= FSL_DMA_CHAN_PAUSE_EXT;
} else
else
fsl_chan->feature &= ~FSL_DMA_CHAN_PAUSE_EXT;
}
@@ -319,7 +339,8 @@ static void fsl_chan_toggle_ext_start(struct fsl_dma_chan *fsl_chan, int enable)
static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
{
struct fsl_dma_chan *fsl_chan = to_fsl_chan(tx->chan);
struct fsl_desc_sw *desc;
struct fsl_desc_sw *desc = tx_to_fsl_desc(tx);
struct fsl_desc_sw *child;
unsigned long flags;
dma_cookie_t cookie;
@@ -327,7 +348,7 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
spin_lock_irqsave(&fsl_chan->desc_lock, flags);
cookie = fsl_chan->common.cookie;
list_for_each_entry(desc, &tx->tx_list, node) {
list_for_each_entry(child, &desc->tx_list, node) {
cookie++;
if (cookie < 0)
cookie = 1;
@@ -336,8 +357,8 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
}
fsl_chan->common.cookie = cookie;
append_ld_queue(fsl_chan, tx_to_fsl_desc(tx));
list_splice_init(&tx->tx_list, fsl_chan->ld_queue.prev);
append_ld_queue(fsl_chan, desc);
list_splice_init(&desc->tx_list, fsl_chan->ld_queue.prev);
spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
@@ -359,6 +380,7 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
desc_sw = dma_pool_alloc(fsl_chan->desc_pool, GFP_ATOMIC, &pdesc);
if (desc_sw) {
memset(desc_sw, 0, sizeof(struct fsl_desc_sw));
INIT_LIST_HEAD(&desc_sw->tx_list);
dma_async_tx_descriptor_init(&desc_sw->async_tx,
&fsl_chan->common);
desc_sw->async_tx.tx_submit = fsl_dma_tx_submit;
@@ -448,7 +470,7 @@ fsl_dma_prep_interrupt(struct dma_chan *chan, unsigned long flags)
new->async_tx.flags = flags;
/* Insert the link descriptor to the LD ring */
list_add_tail(&new->node, &new->async_tx.tx_list);
list_add_tail(&new->node, &new->tx_list);
/* Set End-of-link to the last link descriptor of new list*/
set_ld_eol(fsl_chan, new);
@@ -506,7 +528,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
dma_dest += copy;
/* Insert the link descriptor to the LD ring */
list_add_tail(&new->node, &first->async_tx.tx_list);
list_add_tail(&new->node, &first->tx_list);
} while (len);
new->async_tx.flags = flags; /* client is in control of this ack */
@@ -521,7 +543,7 @@ fail:
if (!first)
return NULL;
list = &first->async_tx.tx_list;
list = &first->tx_list;
list_for_each_entry_safe_reverse(new, prev, list, node) {
list_del(&new->node);
dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys);
@@ -530,6 +552,229 @@ fail:
return NULL;
}
/**
* fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
* @chan: DMA channel
* @sgl: scatterlist to transfer to/from
* @sg_len: number of entries in @scatterlist
* @direction: DMA direction
* @flags: DMAEngine flags
*
* Prepare a set of descriptors for a DMA_SLAVE transaction. Following the
* DMA_SLAVE API, this gets the device-specific information from the
* chan->private variable.
*/
static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
enum dma_data_direction direction, unsigned long flags)
{
struct fsl_dma_chan *fsl_chan;
struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
struct fsl_dma_slave *slave;
struct list_head *tx_list;
size_t copy;
int i;
struct scatterlist *sg;
size_t sg_used;
size_t hw_used;
struct fsl_dma_hw_addr *hw;
dma_addr_t dma_dst, dma_src;
if (!chan)
return NULL;
if (!chan->private)
return NULL;
fsl_chan = to_fsl_chan(chan);
slave = chan->private;
if (list_empty(&slave->addresses))
return NULL;
hw = list_first_entry(&slave->addresses, struct fsl_dma_hw_addr, entry);
hw_used = 0;
/*
* Build the hardware transaction to copy from the scatterlist to
* the hardware, or from the hardware to the scatterlist
*
* If you are copying from the hardware to the scatterlist and it
* takes two hardware entries to fill an entire page, then both
* hardware entries will be coalesced into the same page
*
* If you are copying from the scatterlist to the hardware and a
* single page can fill two hardware entries, then the data will
* be read out of the page into the first hardware entry, and so on
*/
for_each_sg(sgl, sg, sg_len, i) {
sg_used = 0;
/* Loop until the entire scatterlist entry is used */
while (sg_used < sg_dma_len(sg)) {
/*
* If we've used up the current hardware address/length
* pair, we need to load a new one
*
* This is done in a while loop so that descriptors with
* length == 0 will be skipped
*/
while (hw_used >= hw->length) {
/*
* If the current hardware entry is the last
* entry in the list, we're finished
*/
if (list_is_last(&hw->entry, &slave->addresses))
goto finished;
/* Get the next hardware address/length pair */
hw = list_entry(hw->entry.next,
struct fsl_dma_hw_addr, entry);
hw_used = 0;
}
/* Allocate the link descriptor from DMA pool */
new = fsl_dma_alloc_descriptor(fsl_chan);
if (!new) {
dev_err(fsl_chan->dev, "No free memory for "
"link descriptor\n");
goto fail;
}
#ifdef FSL_DMA_LD_DEBUG
dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new);
#endif
/*
* Calculate the maximum number of bytes to transfer,
* making sure it is less than the DMA controller limit
*/
copy = min_t(size_t, sg_dma_len(sg) - sg_used,
hw->length - hw_used);
copy = min_t(size_t, copy, FSL_DMA_BCR_MAX_CNT);
/*
* DMA_FROM_DEVICE
* from the hardware to the scatterlist
*
* DMA_TO_DEVICE
* from the scatterlist to the hardware
*/
if (direction == DMA_FROM_DEVICE) {
dma_src = hw->address + hw_used;
dma_dst = sg_dma_address(sg) + sg_used;
} else {
dma_src = sg_dma_address(sg) + sg_used;
dma_dst = hw->address + hw_used;
}
/* Fill in the descriptor */
set_desc_cnt(fsl_chan, &new->hw, copy);
set_desc_src(fsl_chan, &new->hw, dma_src);
set_desc_dest(fsl_chan, &new->hw, dma_dst);
/*
* If this is not the first descriptor, chain the
* current descriptor after the previous descriptor
*/
if (!first) {
first = new;
} else {
set_desc_next(fsl_chan, &prev->hw,
new->async_tx.phys);
}
new->async_tx.cookie = 0;
async_tx_ack(&new->async_tx);
prev = new;
sg_used += copy;
hw_used += copy;
/* Insert the link descriptor into the LD ring */
list_add_tail(&new->node, &first->tx_list);
}
}
finished:
/* All of the hardware address/length pairs had length == 0 */
if (!first || !new)
return NULL;
new->async_tx.flags = flags;
new->async_tx.cookie = -EBUSY;
/* Set End-of-link to the last link descriptor of new list */
set_ld_eol(fsl_chan, new);
/* Enable extra controller features */
if (fsl_chan->set_src_loop_size)
fsl_chan->set_src_loop_size(fsl_chan, slave->src_loop_size);
if (fsl_chan->set_dest_loop_size)
fsl_chan->set_dest_loop_size(fsl_chan, slave->dst_loop_size);
if (fsl_chan->toggle_ext_start)
fsl_chan->toggle_ext_start(fsl_chan, slave->external_start);
if (fsl_chan->toggle_ext_pause)
fsl_chan->toggle_ext_pause(fsl_chan, slave->external_pause);
if (fsl_chan->set_request_count)
fsl_chan->set_request_count(fsl_chan, slave->request_count);
return &first->async_tx;
fail:
/* If first was not set, then we failed to allocate the very first
* descriptor, and we're done */
if (!first)
return NULL;
/*
* First is set, so all of the descriptors we allocated have been added
* to first->tx_list, INCLUDING "first" itself. Therefore we
* must traverse the list backwards freeing each descriptor in turn
*
* We're re-using variables for the loop, oh well
*/
tx_list = &first->tx_list;
list_for_each_entry_safe_reverse(new, prev, tx_list, node) {
list_del_init(&new->node);
dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys);
}
return NULL;
}
static void fsl_dma_device_terminate_all(struct dma_chan *chan)
{
struct fsl_dma_chan *fsl_chan;
struct fsl_desc_sw *desc, *tmp;
unsigned long flags;
if (!chan)
return;
fsl_chan = to_fsl_chan(chan);
/* Halt the DMA engine */
dma_halt(fsl_chan);
spin_lock_irqsave(&fsl_chan->desc_lock, flags);
/* Remove and free all of the descriptors in the LD queue */
list_for_each_entry_safe(desc, tmp, &fsl_chan->ld_queue, node) {
list_del(&desc->node);
dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys);
}
spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
}
/**
* fsl_dma_update_completed_cookie - Update the completed cookie.
* @fsl_chan : Freescale DMA channel
@@ -871,11 +1116,12 @@ static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev,
switch (new_fsl_chan->feature & FSL_DMA_IP_MASK) {
case FSL_DMA_IP_85XX:
new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start;
new_fsl_chan->toggle_ext_pause = fsl_chan_toggle_ext_pause;
case FSL_DMA_IP_83XX:
new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start;
new_fsl_chan->set_src_loop_size = fsl_chan_set_src_loop_size;
new_fsl_chan->set_dest_loop_size = fsl_chan_set_dest_loop_size;
new_fsl_chan->set_request_count = fsl_chan_set_request_count;
}
spin_lock_init(&new_fsl_chan->desc_lock);
@@ -955,12 +1201,15 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
fdev->common.device_is_tx_complete = fsl_dma_is_complete;
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;
fdev->common.device_terminate_all = fsl_dma_device_terminate_all;
fdev->common.dev = &dev->dev;
fdev->irq = irq_of_parse_and_map(dev->node, 0);

View File

@@ -38,6 +38,7 @@
/* Special MR definition for MPC8349 */
#define FSL_DMA_MR_EOTIE 0x00000080
#define FSL_DMA_MR_PRC_RM 0x00000800
#define FSL_DMA_SR_CH 0x00000020
#define FSL_DMA_SR_PE 0x00000010
@@ -89,6 +90,7 @@ struct fsl_dma_ld_hw {
struct fsl_desc_sw {
struct fsl_dma_ld_hw hw;
struct list_head node;
struct list_head tx_list;
struct dma_async_tx_descriptor async_tx;
struct list_head *ld;
void *priv;
@@ -142,10 +144,11 @@ struct fsl_dma_chan {
struct tasklet_struct tasklet;
u32 feature;
void (*toggle_ext_pause)(struct fsl_dma_chan *fsl_chan, int size);
void (*toggle_ext_pause)(struct fsl_dma_chan *fsl_chan, int enable);
void (*toggle_ext_start)(struct fsl_dma_chan *fsl_chan, int enable);
void (*set_src_loop_size)(struct fsl_dma_chan *fsl_chan, int size);
void (*set_dest_loop_size)(struct fsl_dma_chan *fsl_chan, int size);
void (*set_request_count)(struct fsl_dma_chan *fsl_chan, int size);
};
#define to_fsl_chan(chan) container_of(chan, struct fsl_dma_chan, common)

View File

@@ -251,12 +251,12 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx)
dev_dbg(to_dev(&ioat->base), "%s: cookie: %d\n", __func__, cookie);
/* write address into NextDescriptor field of last desc in chain */
first = to_ioat_desc(tx->tx_list.next);
first = to_ioat_desc(desc->tx_list.next);
chain_tail = to_ioat_desc(ioat->used_desc.prev);
/* make descriptor updates globally visible before chaining */
wmb();
chain_tail->hw->next = first->txd.phys;
list_splice_tail_init(&tx->tx_list, &ioat->used_desc);
list_splice_tail_init(&desc->tx_list, &ioat->used_desc);
dump_desc_dbg(ioat, chain_tail);
dump_desc_dbg(ioat, first);
@@ -298,6 +298,7 @@ ioat_dma_alloc_descriptor(struct ioat_dma_chan *ioat, gfp_t flags)
memset(desc, 0, sizeof(*desc));
INIT_LIST_HEAD(&desc_sw->tx_list);
dma_async_tx_descriptor_init(&desc_sw->txd, &ioat->base.common);
desc_sw->txd.tx_submit = ioat1_tx_submit;
desc_sw->hw = desc;
@@ -522,7 +523,7 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest,
desc->txd.flags = flags;
desc->len = total_len;
list_splice(&chain, &desc->txd.tx_list);
list_splice(&chain, &desc->tx_list);
hw->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT);
hw->ctl_f.compl_write = 1;
hw->tx_cnt = tx_cnt;

View File

@@ -171,7 +171,7 @@ ioat_is_complete(struct dma_chan *c, dma_cookie_t cookie,
* struct ioat_desc_sw - wrapper around hardware descriptor
* @hw: hardware DMA descriptor (for memcpy)
* @node: this descriptor will either be on the free list,
* or attached to a transaction list (async_tx.tx_list)
* or attached to a transaction list (tx_list)
* @txd: the generic software descriptor for all engines
* @id: identifier for debug
*/
@@ -179,6 +179,7 @@ struct ioat_desc_sw {
struct ioat_dma_descriptor *hw;
struct list_head node;
size_t len;
struct list_head tx_list;
struct dma_async_tx_descriptor txd;
#ifdef DEBUG
int id;

View File

@@ -397,11 +397,12 @@ static struct ioat_ring_ent *ioat2_alloc_ring_ent(struct dma_chan *chan, gfp_t f
return NULL;
memset(hw, 0, sizeof(*hw));
desc = kzalloc(sizeof(*desc), flags);
desc = kmem_cache_alloc(ioat2_cache, flags);
if (!desc) {
pci_pool_free(dma->dma_pool, hw, phys);
return NULL;
}
memset(desc, 0, sizeof(*desc));
dma_async_tx_descriptor_init(&desc->txd, chan);
desc->txd.tx_submit = ioat2_tx_submit_unlock;
@@ -416,7 +417,7 @@ static void ioat2_free_ring_ent(struct ioat_ring_ent *desc, struct dma_chan *cha
dma = to_ioatdma_device(chan->device);
pci_pool_free(dma->dma_pool, desc->hw, desc->txd.phys);
kfree(desc);
kmem_cache_free(ioat2_cache, desc);
}
static struct ioat_ring_ent **ioat2_alloc_ring(struct dma_chan *c, int order, gfp_t flags)

View File

@@ -142,8 +142,8 @@ struct ioat_ring_ent {
struct ioat_pq_update_descriptor *pqu;
struct ioat_raw_descriptor *raw;
};
struct dma_async_tx_descriptor txd;
size_t len;
struct dma_async_tx_descriptor txd;
enum sum_check_flags *result;
#ifdef DEBUG
int id;
@@ -186,4 +186,5 @@ void __ioat2_issue_pending(struct ioat2_dma_chan *ioat);
void ioat2_cleanup_tasklet(unsigned long data);
void ioat2_timer_event(unsigned long data);
extern struct kobj_type ioat2_ktype;
extern struct kmem_cache *ioat2_cache;
#endif /* IOATDMA_V2_H */

View File

@@ -83,6 +83,8 @@ static int ioat_dca_enabled = 1;
module_param(ioat_dca_enabled, int, 0644);
MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)");
struct kmem_cache *ioat2_cache;
#define DRV_NAME "ioatdma"
static struct pci_driver ioat_pci_driver = {
@@ -182,15 +184,27 @@ static void __devexit ioat_remove(struct pci_dev *pdev)
static int __init ioat_init_module(void)
{
int err;
pr_info("%s: Intel(R) QuickData Technology Driver %s\n",
DRV_NAME, IOAT_DMA_VERSION);
return pci_register_driver(&ioat_pci_driver);
ioat2_cache = kmem_cache_create("ioat2", sizeof(struct ioat_ring_ent),
0, SLAB_HWCACHE_ALIGN, NULL);
if (!ioat2_cache)
return -ENOMEM;
err = pci_register_driver(&ioat_pci_driver);
if (err)
kmem_cache_destroy(ioat2_cache);
return err;
}
module_init(ioat_init_module);
static void __exit ioat_exit_module(void)
{
pci_unregister_driver(&ioat_pci_driver);
kmem_cache_destroy(ioat2_cache);
}
module_exit(ioat_exit_module);

View File

@@ -421,7 +421,7 @@ retry:
}
alloc_tail->group_head = alloc_start;
alloc_tail->async_tx.cookie = -EBUSY;
list_splice(&chain, &alloc_tail->async_tx.tx_list);
list_splice(&chain, &alloc_tail->tx_list);
iop_chan->last_used = last_used;
iop_desc_clear_next_desc(alloc_start);
iop_desc_clear_next_desc(alloc_tail);
@@ -480,7 +480,7 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx)
old_chain_tail = list_entry(iop_chan->chain.prev,
struct iop_adma_desc_slot, chain_node);
list_splice_init(&sw_desc->async_tx.tx_list,
list_splice_init(&sw_desc->tx_list,
&old_chain_tail->chain_node);
/* fix up the hardware chain */
@@ -547,6 +547,7 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan)
dma_async_tx_descriptor_init(&slot->async_tx, chan);
slot->async_tx.tx_submit = iop_adma_tx_submit;
INIT_LIST_HEAD(&slot->tx_list);
INIT_LIST_HEAD(&slot->chain_node);
INIT_LIST_HEAD(&slot->slot_node);
hw_desc = (char *) iop_chan->device->dma_desc_pool;
@@ -1642,7 +1643,7 @@ static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan)
if (sw_desc) {
grp_start = sw_desc->group_head;
list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain);
list_splice_init(&sw_desc->tx_list, &iop_chan->chain);
async_tx_ack(&sw_desc->async_tx);
iop_desc_init_memcpy(grp_start, 0);
iop_desc_set_byte_count(grp_start, iop_chan, 0);
@@ -1698,7 +1699,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan)
sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
if (sw_desc) {
grp_start = sw_desc->group_head;
list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain);
list_splice_init(&sw_desc->tx_list, &iop_chan->chain);
async_tx_ack(&sw_desc->async_tx);
iop_desc_init_null_xor(grp_start, 2, 0);
iop_desc_set_byte_count(grp_start, iop_chan, 0);

View File

@@ -517,7 +517,7 @@ retry:
}
alloc_tail->group_head = alloc_start;
alloc_tail->async_tx.cookie = -EBUSY;
list_splice(&chain, &alloc_tail->async_tx.tx_list);
list_splice(&chain, &alloc_tail->tx_list);
mv_chan->last_used = last_used;
mv_desc_clear_next_desc(alloc_start);
mv_desc_clear_next_desc(alloc_tail);
@@ -565,14 +565,14 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx)
cookie = mv_desc_assign_cookie(mv_chan, sw_desc);
if (list_empty(&mv_chan->chain))
list_splice_init(&sw_desc->async_tx.tx_list, &mv_chan->chain);
list_splice_init(&sw_desc->tx_list, &mv_chan->chain);
else {
new_hw_chain = 0;
old_chain_tail = list_entry(mv_chan->chain.prev,
struct mv_xor_desc_slot,
chain_node);
list_splice_init(&grp_start->async_tx.tx_list,
list_splice_init(&grp_start->tx_list,
&old_chain_tail->chain_node);
if (!mv_can_chain(grp_start))
@@ -632,6 +632,7 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
slot->async_tx.tx_submit = mv_xor_tx_submit;
INIT_LIST_HEAD(&slot->chain_node);
INIT_LIST_HEAD(&slot->slot_node);
INIT_LIST_HEAD(&slot->tx_list);
hw_desc = (char *) mv_chan->device->dma_desc_pool;
slot->async_tx.phys =
(dma_addr_t) &hw_desc[idx * MV_XOR_SLOT_SIZE];
@@ -1176,7 +1177,7 @@ static int __devinit mv_xor_probe(struct platform_device *pdev)
if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask))
dma_dev->device_prep_dma_memset = mv_xor_prep_dma_memset;
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
dma_dev->max_xor = 8; ;
dma_dev->max_xor = 8;
dma_dev->device_prep_dma_xor = mv_xor_prep_dma_xor;
}

View File

@@ -126,9 +126,8 @@ struct mv_xor_chan {
* @idx: pool index
* @unmap_src_cnt: number of xor sources
* @unmap_len: transaction bytecount
* @tx_list: list of slots that make up a multi-descriptor transaction
* @async_tx: support for the async_tx api
* @group_list: list of slots that make up a multi-descriptor transaction
* for example transfer lengths larger than the supported hw max
* @xor_check_result: result of zero sum
* @crc32_result: result crc calculation
*/
@@ -145,6 +144,7 @@ struct mv_xor_desc_slot {
u16 unmap_src_cnt;
u32 value;
size_t unmap_len;
struct list_head tx_list;
struct dma_async_tx_descriptor async_tx;
union {
u32 *xor_check_result;

1356
drivers/dma/txx9dmac.c Normal file

File diff suppressed because it is too large Load Diff

308
drivers/dma/txx9dmac.h Normal file
View File

@@ -0,0 +1,308 @@
/*
* Driver for the TXx9 SoC DMA Controller
*
* Copyright (C) 2009 Atsushi Nemoto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef TXX9DMAC_H
#define TXX9DMAC_H
#include <linux/dmaengine.h>
#include <asm/txx9/dmac.h>
/*
* Design Notes:
*
* This DMAC have four channels and one FIFO buffer. Each channel can
* be configured for memory-memory or device-memory transfer, but only
* one channel can do alignment-free memory-memory transfer at a time
* while the channel should occupy the FIFO buffer for effective
* transfers.
*
* Instead of dynamically assign the FIFO buffer to channels, I chose
* make one dedicated channel for memory-memory transfer. The
* dedicated channel is public. Other channels are private and used
* for slave transfer. Some devices in the SoC are wired to certain
* DMA channel.
*/
#ifdef CONFIG_MACH_TX49XX
static inline bool txx9_dma_have_SMPCHN(void)
{
return true;
}
#define TXX9_DMA_USE_SIMPLE_CHAIN
#else
static inline bool txx9_dma_have_SMPCHN(void)
{
return false;
}
#endif
#ifdef __LITTLE_ENDIAN
#ifdef CONFIG_MACH_TX49XX
#define CCR_LE TXX9_DMA_CCR_LE
#define MCR_LE 0
#else
#define CCR_LE 0
#define MCR_LE TXX9_DMA_MCR_LE
#endif
#else
#define CCR_LE 0
#define MCR_LE 0
#endif
/*
* Redefine this macro to handle differences between 32- and 64-bit
* addressing, big vs. little endian, etc.
*/
#ifdef __BIG_ENDIAN
#define TXX9_DMA_REG32(name) u32 __pad_##name; u32 name
#else
#define TXX9_DMA_REG32(name) u32 name; u32 __pad_##name
#endif
/* Hardware register definitions. */
struct txx9dmac_cregs {
#if defined(CONFIG_32BIT) && !defined(CONFIG_64BIT_PHYS_ADDR)
TXX9_DMA_REG32(CHAR); /* Chain Address Register */
#else
u64 CHAR; /* Chain Address Register */
#endif
u64 SAR; /* Source Address Register */
u64 DAR; /* Destination Address Register */
TXX9_DMA_REG32(CNTR); /* Count Register */
TXX9_DMA_REG32(SAIR); /* Source Address Increment Register */
TXX9_DMA_REG32(DAIR); /* Destination Address Increment Register */
TXX9_DMA_REG32(CCR); /* Channel Control Register */
TXX9_DMA_REG32(CSR); /* Channel Status Register */
};
struct txx9dmac_cregs32 {
u32 CHAR;
u32 SAR;
u32 DAR;
u32 CNTR;
u32 SAIR;
u32 DAIR;
u32 CCR;
u32 CSR;
};
struct txx9dmac_regs {
/* per-channel registers */
struct txx9dmac_cregs CHAN[TXX9_DMA_MAX_NR_CHANNELS];
u64 __pad[9];
u64 MFDR; /* Memory Fill Data Register */
TXX9_DMA_REG32(MCR); /* Master Control Register */
};
struct txx9dmac_regs32 {
struct txx9dmac_cregs32 CHAN[TXX9_DMA_MAX_NR_CHANNELS];
u32 __pad[9];
u32 MFDR;
u32 MCR;
};
/* bits for MCR */
#define TXX9_DMA_MCR_EIS(ch) (0x10000000<<(ch))
#define TXX9_DMA_MCR_DIS(ch) (0x01000000<<(ch))
#define TXX9_DMA_MCR_RSFIF 0x00000080
#define TXX9_DMA_MCR_FIFUM(ch) (0x00000008<<(ch))
#define TXX9_DMA_MCR_LE 0x00000004
#define TXX9_DMA_MCR_RPRT 0x00000002
#define TXX9_DMA_MCR_MSTEN 0x00000001
/* bits for CCRn */
#define TXX9_DMA_CCR_IMMCHN 0x20000000
#define TXX9_DMA_CCR_USEXFSZ 0x10000000
#define TXX9_DMA_CCR_LE 0x08000000
#define TXX9_DMA_CCR_DBINH 0x04000000
#define TXX9_DMA_CCR_SBINH 0x02000000
#define TXX9_DMA_CCR_CHRST 0x01000000
#define TXX9_DMA_CCR_RVBYTE 0x00800000
#define TXX9_DMA_CCR_ACKPOL 0x00400000
#define TXX9_DMA_CCR_REQPL 0x00200000
#define TXX9_DMA_CCR_EGREQ 0x00100000
#define TXX9_DMA_CCR_CHDN 0x00080000
#define TXX9_DMA_CCR_DNCTL 0x00060000
#define TXX9_DMA_CCR_EXTRQ 0x00010000
#define TXX9_DMA_CCR_INTRQD 0x0000e000
#define TXX9_DMA_CCR_INTENE 0x00001000
#define TXX9_DMA_CCR_INTENC 0x00000800
#define TXX9_DMA_CCR_INTENT 0x00000400
#define TXX9_DMA_CCR_CHNEN 0x00000200
#define TXX9_DMA_CCR_XFACT 0x00000100
#define TXX9_DMA_CCR_SMPCHN 0x00000020
#define TXX9_DMA_CCR_XFSZ(order) (((order) << 2) & 0x0000001c)
#define TXX9_DMA_CCR_XFSZ_1 TXX9_DMA_CCR_XFSZ(0)
#define TXX9_DMA_CCR_XFSZ_2 TXX9_DMA_CCR_XFSZ(1)
#define TXX9_DMA_CCR_XFSZ_4 TXX9_DMA_CCR_XFSZ(2)
#define TXX9_DMA_CCR_XFSZ_8 TXX9_DMA_CCR_XFSZ(3)
#define TXX9_DMA_CCR_XFSZ_X4 TXX9_DMA_CCR_XFSZ(4)
#define TXX9_DMA_CCR_XFSZ_X8 TXX9_DMA_CCR_XFSZ(5)
#define TXX9_DMA_CCR_XFSZ_X16 TXX9_DMA_CCR_XFSZ(6)
#define TXX9_DMA_CCR_XFSZ_X32 TXX9_DMA_CCR_XFSZ(7)
#define TXX9_DMA_CCR_MEMIO 0x00000002
#define TXX9_DMA_CCR_SNGAD 0x00000001
/* bits for CSRn */
#define TXX9_DMA_CSR_CHNEN 0x00000400
#define TXX9_DMA_CSR_STLXFER 0x00000200
#define TXX9_DMA_CSR_XFACT 0x00000100
#define TXX9_DMA_CSR_ABCHC 0x00000080
#define TXX9_DMA_CSR_NCHNC 0x00000040
#define TXX9_DMA_CSR_NTRNFC 0x00000020
#define TXX9_DMA_CSR_EXTDN 0x00000010
#define TXX9_DMA_CSR_CFERR 0x00000008
#define TXX9_DMA_CSR_CHERR 0x00000004
#define TXX9_DMA_CSR_DESERR 0x00000002
#define TXX9_DMA_CSR_SORERR 0x00000001
struct txx9dmac_chan {
struct dma_chan chan;
struct dma_device dma;
struct txx9dmac_dev *ddev;
void __iomem *ch_regs;
struct tasklet_struct tasklet;
int irq;
u32 ccr;
spinlock_t lock;
/* these other elements are all protected by lock */
dma_cookie_t completed;
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
unsigned int descs_allocated;
};
struct txx9dmac_dev {
void __iomem *regs;
struct tasklet_struct tasklet;
int irq;
struct txx9dmac_chan *chan[TXX9_DMA_MAX_NR_CHANNELS];
bool have_64bit_regs;
unsigned int descsize;
};
static inline bool __is_dmac64(const struct txx9dmac_dev *ddev)
{
return ddev->have_64bit_regs;
}
static inline bool is_dmac64(const struct txx9dmac_chan *dc)
{
return __is_dmac64(dc->ddev);
}
#ifdef TXX9_DMA_USE_SIMPLE_CHAIN
/* Hardware descriptor definition. (for simple-chain) */
struct txx9dmac_hwdesc {
#if defined(CONFIG_32BIT) && !defined(CONFIG_64BIT_PHYS_ADDR)
TXX9_DMA_REG32(CHAR);
#else
u64 CHAR;
#endif
u64 SAR;
u64 DAR;
TXX9_DMA_REG32(CNTR);
};
struct txx9dmac_hwdesc32 {
u32 CHAR;
u32 SAR;
u32 DAR;
u32 CNTR;
};
#else
#define txx9dmac_hwdesc txx9dmac_cregs
#define txx9dmac_hwdesc32 txx9dmac_cregs32
#endif
struct txx9dmac_desc {
/* FIRST values the hardware uses */
union {
struct txx9dmac_hwdesc hwdesc;
struct txx9dmac_hwdesc32 hwdesc32;
};
/* THEN values for driver housekeeping */
struct list_head desc_node ____cacheline_aligned;
struct list_head tx_list;
struct dma_async_tx_descriptor txd;
size_t len;
};
#ifdef TXX9_DMA_USE_SIMPLE_CHAIN
static inline bool txx9dmac_chan_INTENT(struct txx9dmac_chan *dc)
{
return (dc->ccr & TXX9_DMA_CCR_INTENT) != 0;
}
static inline void txx9dmac_chan_set_INTENT(struct txx9dmac_chan *dc)
{
dc->ccr |= TXX9_DMA_CCR_INTENT;
}
static inline void txx9dmac_desc_set_INTENT(struct txx9dmac_dev *ddev,
struct txx9dmac_desc *desc)
{
}
static inline void txx9dmac_chan_set_SMPCHN(struct txx9dmac_chan *dc)
{
dc->ccr |= TXX9_DMA_CCR_SMPCHN;
}
static inline void txx9dmac_desc_set_nosimple(struct txx9dmac_dev *ddev,
struct txx9dmac_desc *desc,
u32 sair, u32 dair, u32 ccr)
{
}
#else /* TXX9_DMA_USE_SIMPLE_CHAIN */
static inline bool txx9dmac_chan_INTENT(struct txx9dmac_chan *dc)
{
return true;
}
static void txx9dmac_chan_set_INTENT(struct txx9dmac_chan *dc)
{
}
static inline void txx9dmac_desc_set_INTENT(struct txx9dmac_dev *ddev,
struct txx9dmac_desc *desc)
{
if (__is_dmac64(ddev))
desc->hwdesc.CCR |= TXX9_DMA_CCR_INTENT;
else
desc->hwdesc32.CCR |= TXX9_DMA_CCR_INTENT;
}
static inline void txx9dmac_chan_set_SMPCHN(struct txx9dmac_chan *dc)
{
}
static inline void txx9dmac_desc_set_nosimple(struct txx9dmac_dev *ddev,
struct txx9dmac_desc *desc,
u32 sai, u32 dai, u32 ccr)
{
if (__is_dmac64(ddev)) {
desc->hwdesc.SAIR = sai;
desc->hwdesc.DAIR = dai;
desc->hwdesc.CCR = ccr;
} else {
desc->hwdesc32.SAIR = sai;
desc->hwdesc32.DAIR = dai;
desc->hwdesc32.CCR = ccr;
}
}
#endif /* TXX9_DMA_USE_SIMPLE_CHAIN */
#endif /* TXX9DMAC_H */