From 19242d7233df7d658405d4b7ee1758d21414cfaa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 17 Apr 2008 20:17:25 -0700 Subject: async_tx: fix multiple dependency submission Shrink struct dma_async_tx_descriptor and introduce async_tx_channel_switch to properly inject a channel switch interrupt in the descriptor stream. This simplifies the locking model as drivers no longer need to handle dma_async_tx_descriptor.lock. Acked-by: Shannon Nelson Signed-off-by: Dan Williams --- include/linux/dmaengine.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 34d44069829..91252a7e4d0 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -221,11 +221,9 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param); * @callback: routine to call after this operation is complete * @callback_param: general parameter to pass to the callback routine * ---async_tx api specific fields--- - * @depend_list: at completion this list of transactions are submitted - * @depend_node: allow this transaction to be executed after another - * transaction has completed, possibly on another channel + * @next: at completion submit this descriptor * @parent: pointer to the next level up in the dependency chain - * @lock: protect the dependency list + * @lock: protect the parent and next pointers */ struct dma_async_tx_descriptor { dma_cookie_t cookie; @@ -236,8 +234,7 @@ struct dma_async_tx_descriptor { dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx); dma_async_tx_callback callback; void *callback_param; - struct list_head depend_list; - struct list_head depend_node; + struct dma_async_tx_descriptor *next; struct dma_async_tx_descriptor *parent; spinlock_t lock; }; -- cgit v1.2.3 From ce4d65a5db77e1568c82d5151a746f627c4f6ed5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 17 Apr 2008 20:17:26 -0700 Subject: async_tx: kill ->device_dependency_added DMA drivers no longer need to be notified of dependency submission events as async_tx_run_dependencies and async_tx_channel_switch will handle the scheduling and execution of dependent operations. [sfr@canb.auug.org.au: extend this for fsldma] Acked-by: Shannon Nelson Signed-off-by: Dan Williams --- include/linux/dmaengine.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 91252a7e4d0..cd34df78c6a 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -258,7 +258,6 @@ struct dma_async_tx_descriptor { * @device_prep_dma_zero_sum: prepares a zero_sum operation * @device_prep_dma_memset: prepares a memset operation * @device_prep_dma_interrupt: prepares an end of chain interrupt operation - * @device_dependency_added: async_tx notifies the channel about new deps * @device_issue_pending: push pending transactions to hardware */ struct dma_device { @@ -293,7 +292,6 @@ struct dma_device { struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( struct dma_chan *chan); - void (*device_dependency_added)(struct dma_chan *chan); enum dma_status (*device_is_tx_complete)(struct dma_chan *chan, dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used); -- cgit v1.2.3 From c4fe15541d0ef5cc8cc1ce43057663851f8fc387 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 17 Apr 2008 20:17:26 -0700 Subject: iop-adma: remove the workaround for missed interrupts on iop3xx This workaround was covering the dependency submission bug in async_tx. Signed-off-by: Dan Williams --- include/asm-arm/arch-iop13xx/adma.h | 5 ----- include/asm-arm/hardware/iop3xx-adma.h | 8 -------- include/asm-arm/hardware/iop_adma.h | 2 -- 3 files changed, 15 deletions(-) (limited to 'include') diff --git a/include/asm-arm/arch-iop13xx/adma.h b/include/asm-arm/arch-iop13xx/adma.h index efd9a5eb100..90d14ee564f 100644 --- a/include/asm-arm/arch-iop13xx/adma.h +++ b/include/asm-arm/arch-iop13xx/adma.h @@ -454,11 +454,6 @@ static inline void iop_chan_append(struct iop_adma_chan *chan) __raw_writel(adma_accr, ADMA_ACCR(chan)); } -static inline void iop_chan_idle(int busy, struct iop_adma_chan *chan) -{ - do { } while (0); -} - static inline u32 iop_chan_get_status(struct iop_adma_chan *chan) { return __raw_readl(ADMA_ACSR(chan)); diff --git a/include/asm-arm/hardware/iop3xx-adma.h b/include/asm-arm/hardware/iop3xx-adma.h index 5c529e6a5e3..84d635b0a71 100644 --- a/include/asm-arm/hardware/iop3xx-adma.h +++ b/include/asm-arm/hardware/iop3xx-adma.h @@ -767,20 +767,12 @@ static inline int iop_desc_get_zero_result(struct iop_adma_desc_slot *desc) static inline void iop_chan_append(struct iop_adma_chan *chan) { u32 dma_chan_ctrl; - /* workaround dropped interrupts on 3xx */ - mod_timer(&chan->cleanup_watchdog, jiffies + msecs_to_jiffies(3)); dma_chan_ctrl = __raw_readl(DMA_CCR(chan)); dma_chan_ctrl |= 0x2; __raw_writel(dma_chan_ctrl, DMA_CCR(chan)); } -static inline void iop_chan_idle(int busy, struct iop_adma_chan *chan) -{ - if (!busy) - del_timer(&chan->cleanup_watchdog); -} - static inline u32 iop_chan_get_status(struct iop_adma_chan *chan) { return __raw_readl(DMA_CSR(chan)); diff --git a/include/asm-arm/hardware/iop_adma.h b/include/asm-arm/hardware/iop_adma.h index ca8e71f4434..cb7e3611bcb 100644 --- a/include/asm-arm/hardware/iop_adma.h +++ b/include/asm-arm/hardware/iop_adma.h @@ -51,7 +51,6 @@ struct iop_adma_device { * @common: common dmaengine channel object members * @last_used: place holder for allocation to continue from where it left off * @all_slots: complete domain of slots usable by the channel - * @cleanup_watchdog: workaround missed interrupts on iop3xx * @slots_allocated: records the actual size of the descriptor slot pool * @irq_tasklet: bottom half where iop_adma_slot_cleanup runs */ @@ -65,7 +64,6 @@ struct iop_adma_chan { struct dma_chan common; struct iop_adma_desc_slot *last_used; struct list_head all_slots; - struct timer_list cleanup_watchdog; int slots_allocated; struct tasklet_struct irq_tasklet; }; -- cgit v1.2.3 From 636bdeaa1243327501edfd2a597ed7443eb4239a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 17 Apr 2008 20:17:26 -0700 Subject: dmaengine: ack to flags: make use of the unused bits in the 'ack' field 'ack' is currently a simple integer that flags whether or not a client is done touching fields in the given descriptor. It is effectively just a single bit of information. Converting this to a flags parameter allows the other bits to be put to use to control completion actions, like dma-unmap, and capture results, like xor-zero-sum == 0. Changes are one of: 1/ convert all open-coded ->ack manipulations to use async_tx_ack and async_tx_test_ack. 2/ set the ack bit at prep time where possible 3/ make drivers store the flags at prep time 4/ add flags to the device_prep_dma_interrupt prototype Acked-by: Maciej Sosnowski Signed-off-by: Dan Williams --- include/linux/dmaengine.h | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index cd34df78c6a..b4d84ed6187 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -95,12 +95,17 @@ enum dma_transaction_type { #define DMA_TX_TYPE_END (DMA_INTERRUPT + 1) /** - * enum dma_prep_flags - DMA flags to augment operation preparation + * enum dma_ctrl_flags - DMA flags to augment operation preparation, + * control completion, and communicate status. * @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of * this transaction + * @DMA_CTRL_ACK - the descriptor cannot be reused until the client + * acknowledges receipt, i.e. has has a chance to establish any + * dependency chains */ -enum dma_prep_flags { +enum dma_ctrl_flags { DMA_PREP_INTERRUPT = (1 << 0), + DMA_CTRL_ACK = (1 << 1), }; /** @@ -211,8 +216,8 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param); * ---dma generic offload fields--- * @cookie: tracking cookie for this transaction, set to -EBUSY if * this tx is sitting on a dependency list - * @ack: the descriptor can not be reused until the client acknowledges - * receipt, i.e. has has a chance to establish any dependency chains + * @flags: flags to augment operation preparation, control completion, and + * communicate status * @phys: physical address of the descriptor * @tx_list: driver common field for operations that require multiple * descriptors @@ -227,7 +232,7 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param); */ struct dma_async_tx_descriptor { dma_cookie_t cookie; - int ack; + enum dma_ctrl_flags flags; /* not a 'long' to pack with cookie */ dma_addr_t phys; struct list_head tx_list; struct dma_chan *chan; @@ -290,7 +295,7 @@ struct dma_device { struct dma_chan *chan, dma_addr_t dest, int value, size_t len, unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( - struct dma_chan *chan); + struct dma_chan *chan, unsigned long flags); enum dma_status (*device_is_tx_complete)(struct dma_chan *chan, dma_cookie_t cookie, dma_cookie_t *last, @@ -316,7 +321,13 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, static inline void async_tx_ack(struct dma_async_tx_descriptor *tx) { - tx->ack = 1; + tx->flags |= DMA_CTRL_ACK; +} + +static inline int +async_tx_test_ack(struct dma_async_tx_descriptor *tx) +{ + return tx->flags & DMA_CTRL_ACK; } #define first_dma_cap(mask) __first_dma_cap(&(mask)) -- cgit v1.2.3