Commit 05a62548 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx

* 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx:
  drivers/dma: Correct use after free
  drivers/dma: drop unnecesary memset
  ioat2,3: put channel hardware in known state at init
  async_tx: expand async raid6 test to cover ioatdma corner case
  ioat3: fix p-disabled q-continuation
  sh: fix DMA driver's descriptor chaining and cookie assignment
  dma: at_hdmac: correct incompatible type for argument 1 of 'spin_lock_bh'
parents 1f11abc9 f80ca163
...@@ -214,6 +214,13 @@ static int raid6_test(void) ...@@ -214,6 +214,13 @@ static int raid6_test(void)
err += test(4, &tests); err += test(4, &tests);
if (NDISKS > 5) if (NDISKS > 5)
err += test(5, &tests); err += test(5, &tests);
/* the 11 and 12 disk cases are special for ioatdma (p-disabled
* q-continuation without extended descriptor)
*/
if (NDISKS > 12) {
err += test(11, &tests);
err += test(12, &tests);
}
err += test(NDISKS, &tests); err += test(NDISKS, &tests);
pr("\n"); pr("\n");
......
...@@ -815,7 +815,7 @@ atc_is_tx_complete(struct dma_chan *chan, ...@@ -815,7 +815,7 @@ atc_is_tx_complete(struct dma_chan *chan,
dev_vdbg(chan2dev(chan), "is_tx_complete: %d (d%d, u%d)\n", dev_vdbg(chan2dev(chan), "is_tx_complete: %d (d%d, u%d)\n",
cookie, done ? *done : 0, used ? *used : 0); cookie, done ? *done : 0, used ? *used : 0);
spin_lock_bh(atchan->lock); spin_lock_bh(&atchan->lock);
last_complete = atchan->completed_cookie; last_complete = atchan->completed_cookie;
last_used = chan->cookie; last_used = chan->cookie;
...@@ -830,7 +830,7 @@ atc_is_tx_complete(struct dma_chan *chan, ...@@ -830,7 +830,7 @@ atc_is_tx_complete(struct dma_chan *chan,
ret = dma_async_is_complete(cookie, last_complete, last_used); ret = dma_async_is_complete(cookie, last_complete, last_used);
} }
spin_unlock_bh(atchan->lock); spin_unlock_bh(&atchan->lock);
if (done) if (done)
*done = last_complete; *done = last_complete;
......
...@@ -1294,8 +1294,8 @@ static int __exit coh901318_remove(struct platform_device *pdev) ...@@ -1294,8 +1294,8 @@ static int __exit coh901318_remove(struct platform_device *pdev)
dma_async_device_unregister(&base->dma_slave); dma_async_device_unregister(&base->dma_slave);
coh901318_pool_destroy(&base->pool); coh901318_pool_destroy(&base->pool);
free_irq(platform_get_irq(pdev, 0), base); free_irq(platform_get_irq(pdev, 0), base);
kfree(base);
iounmap(base->virtbase); iounmap(base->virtbase);
kfree(base);
release_mem_region(pdev->resource->start, release_mem_region(pdev->resource->start,
resource_size(pdev->resource)); resource_size(pdev->resource));
return 0; return 0;
......
...@@ -1270,8 +1270,6 @@ static int __init dw_probe(struct platform_device *pdev) ...@@ -1270,8 +1270,6 @@ static int __init dw_probe(struct platform_device *pdev)
goto err_kfree; goto err_kfree;
} }
memset(dw, 0, sizeof *dw);
dw->regs = ioremap(io->start, DW_REGLEN); dw->regs = ioremap(io->start, DW_REGLEN);
if (!dw->regs) { if (!dw->regs) {
err = -ENOMEM; err = -ENOMEM;
......
...@@ -1032,7 +1032,7 @@ int __devinit ioat_probe(struct ioatdma_device *device) ...@@ -1032,7 +1032,7 @@ int __devinit ioat_probe(struct ioatdma_device *device)
dma->dev = &pdev->dev; dma->dev = &pdev->dev;
if (!dma->chancnt) { if (!dma->chancnt) {
dev_err(dev, "zero channels detected\n"); dev_err(dev, "channel enumeration error\n");
goto err_setup_interrupts; goto err_setup_interrupts;
} }
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
* @dca: direct cache access context * @dca: direct cache access context
* @intr_quirk: interrupt setup quirk (for ioat_v1 devices) * @intr_quirk: interrupt setup quirk (for ioat_v1 devices)
* @enumerate_channels: hw version specific channel enumeration * @enumerate_channels: hw version specific channel enumeration
* @reset_hw: hw version specific channel (re)initialization
* @cleanup_tasklet: select between the v2 and v3 cleanup routines * @cleanup_tasklet: select between the v2 and v3 cleanup routines
* @timer_fn: select between the v2 and v3 timer watchdog routines * @timer_fn: select between the v2 and v3 timer watchdog routines
* @self_test: hardware version specific self test for each supported op type * @self_test: hardware version specific self test for each supported op type
...@@ -78,6 +79,7 @@ struct ioatdma_device { ...@@ -78,6 +79,7 @@ struct ioatdma_device {
struct dca_provider *dca; struct dca_provider *dca;
void (*intr_quirk)(struct ioatdma_device *device); void (*intr_quirk)(struct ioatdma_device *device);
int (*enumerate_channels)(struct ioatdma_device *device); int (*enumerate_channels)(struct ioatdma_device *device);
int (*reset_hw)(struct ioat_chan_common *chan);
void (*cleanup_tasklet)(unsigned long data); void (*cleanup_tasklet)(unsigned long data);
void (*timer_fn)(unsigned long data); void (*timer_fn)(unsigned long data);
int (*self_test)(struct ioatdma_device *device); int (*self_test)(struct ioatdma_device *device);
...@@ -264,6 +266,22 @@ static inline void ioat_suspend(struct ioat_chan_common *chan) ...@@ -264,6 +266,22 @@ static inline void ioat_suspend(struct ioat_chan_common *chan)
writeb(IOAT_CHANCMD_SUSPEND, chan->reg_base + IOAT_CHANCMD_OFFSET(ver)); writeb(IOAT_CHANCMD_SUSPEND, chan->reg_base + IOAT_CHANCMD_OFFSET(ver));
} }
static inline void ioat_reset(struct ioat_chan_common *chan)
{
u8 ver = chan->device->version;
writeb(IOAT_CHANCMD_RESET, chan->reg_base + IOAT_CHANCMD_OFFSET(ver));
}
static inline bool ioat_reset_pending(struct ioat_chan_common *chan)
{
u8 ver = chan->device->version;
u8 cmd;
cmd = readb(chan->reg_base + IOAT_CHANCMD_OFFSET(ver));
return (cmd & IOAT_CHANCMD_RESET) == IOAT_CHANCMD_RESET;
}
static inline void ioat_set_chainaddr(struct ioat_dma_chan *ioat, u64 addr) static inline void ioat_set_chainaddr(struct ioat_dma_chan *ioat, u64 addr)
{ {
struct ioat_chan_common *chan = &ioat->base; struct ioat_chan_common *chan = &ioat->base;
......
...@@ -239,20 +239,50 @@ void __ioat2_restart_chan(struct ioat2_dma_chan *ioat) ...@@ -239,20 +239,50 @@ void __ioat2_restart_chan(struct ioat2_dma_chan *ioat)
__ioat2_start_null_desc(ioat); __ioat2_start_null_desc(ioat);
} }
static void ioat2_restart_channel(struct ioat2_dma_chan *ioat) int ioat2_quiesce(struct ioat_chan_common *chan, unsigned long tmo)
{ {
struct ioat_chan_common *chan = &ioat->base; unsigned long end = jiffies + tmo;
unsigned long phys_complete; int err = 0;
u32 status; u32 status;
status = ioat_chansts(chan); status = ioat_chansts(chan);
if (is_ioat_active(status) || is_ioat_idle(status)) if (is_ioat_active(status) || is_ioat_idle(status))
ioat_suspend(chan); ioat_suspend(chan);
while (is_ioat_active(status) || is_ioat_idle(status)) { while (is_ioat_active(status) || is_ioat_idle(status)) {
if (end && time_after(jiffies, end)) {
err = -ETIMEDOUT;
break;
}
status = ioat_chansts(chan); status = ioat_chansts(chan);
cpu_relax(); cpu_relax();
} }
return err;
}
int ioat2_reset_sync(struct ioat_chan_common *chan, unsigned long tmo)
{
unsigned long end = jiffies + tmo;
int err = 0;
ioat_reset(chan);
while (ioat_reset_pending(chan)) {
if (end && time_after(jiffies, end)) {
err = -ETIMEDOUT;
break;
}
cpu_relax();
}
return err;
}
static void ioat2_restart_channel(struct ioat2_dma_chan *ioat)
{
struct ioat_chan_common *chan = &ioat->base;
unsigned long phys_complete;
ioat2_quiesce(chan, 0);
if (ioat_cleanup_preamble(chan, &phys_complete)) if (ioat_cleanup_preamble(chan, &phys_complete))
__cleanup(ioat, phys_complete); __cleanup(ioat, phys_complete);
...@@ -318,6 +348,19 @@ void ioat2_timer_event(unsigned long data) ...@@ -318,6 +348,19 @@ void ioat2_timer_event(unsigned long data)
spin_unlock_bh(&chan->cleanup_lock); spin_unlock_bh(&chan->cleanup_lock);
} }
static int ioat2_reset_hw(struct ioat_chan_common *chan)
{
/* throw away whatever the channel was doing and get it initialized */
u32 chanerr;
ioat2_quiesce(chan, msecs_to_jiffies(100));
chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET);
return ioat2_reset_sync(chan, msecs_to_jiffies(200));
}
/** /**
* ioat2_enumerate_channels - find and initialize the device's channels * ioat2_enumerate_channels - find and initialize the device's channels
* @device: the device to be enumerated * @device: the device to be enumerated
...@@ -360,6 +403,10 @@ int ioat2_enumerate_channels(struct ioatdma_device *device) ...@@ -360,6 +403,10 @@ int ioat2_enumerate_channels(struct ioatdma_device *device)
(unsigned long) ioat); (unsigned long) ioat);
ioat->xfercap_log = xfercap_log; ioat->xfercap_log = xfercap_log;
spin_lock_init(&ioat->ring_lock); spin_lock_init(&ioat->ring_lock);
if (device->reset_hw(&ioat->base)) {
i = 0;
break;
}
} }
dma->chancnt = i; dma->chancnt = i;
return i; return i;
...@@ -467,7 +514,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c) ...@@ -467,7 +514,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
struct ioat2_dma_chan *ioat = to_ioat2_chan(c); struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
struct ioat_chan_common *chan = &ioat->base; struct ioat_chan_common *chan = &ioat->base;
struct ioat_ring_ent **ring; struct ioat_ring_ent **ring;
u32 chanerr;
int order; int order;
/* have we already been set up? */ /* have we already been set up? */
...@@ -477,12 +523,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c) ...@@ -477,12 +523,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
/* Setup register to interrupt and write completion status on error */ /* Setup register to interrupt and write completion status on error */
writew(IOAT_CHANCTRL_RUN, chan->reg_base + IOAT_CHANCTRL_OFFSET); writew(IOAT_CHANCTRL_RUN, chan->reg_base + IOAT_CHANCTRL_OFFSET);
chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
if (chanerr) {
dev_err(to_dev(chan), "CHANERR = %x, clearing\n", chanerr);
writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET);
}
/* allocate a completion writeback area */ /* allocate a completion writeback area */
/* doing 2 32bit writes to mmio since 1 64b write doesn't work */ /* doing 2 32bit writes to mmio since 1 64b write doesn't work */
chan->completion = pci_pool_alloc(chan->device->completion_pool, chan->completion = pci_pool_alloc(chan->device->completion_pool,
...@@ -746,13 +786,7 @@ void ioat2_free_chan_resources(struct dma_chan *c) ...@@ -746,13 +786,7 @@ void ioat2_free_chan_resources(struct dma_chan *c)
tasklet_disable(&chan->cleanup_task); tasklet_disable(&chan->cleanup_task);
del_timer_sync(&chan->timer); del_timer_sync(&chan->timer);
device->cleanup_tasklet((unsigned long) ioat); device->cleanup_tasklet((unsigned long) ioat);
device->reset_hw(chan);
/* Delay 100ms after reset to allow internal DMA logic to quiesce
* before removing DMA descriptor resources.
*/
writeb(IOAT_CHANCMD_RESET,
chan->reg_base + IOAT_CHANCMD_OFFSET(chan->device->version));
mdelay(100);
spin_lock_bh(&ioat->ring_lock); spin_lock_bh(&ioat->ring_lock);
descs = ioat2_ring_space(ioat); descs = ioat2_ring_space(ioat);
...@@ -839,6 +873,7 @@ int __devinit ioat2_dma_probe(struct ioatdma_device *device, int dca) ...@@ -839,6 +873,7 @@ int __devinit ioat2_dma_probe(struct ioatdma_device *device, int dca)
int err; int err;
device->enumerate_channels = ioat2_enumerate_channels; device->enumerate_channels = ioat2_enumerate_channels;
device->reset_hw = ioat2_reset_hw;
device->cleanup_tasklet = ioat2_cleanup_tasklet; device->cleanup_tasklet = ioat2_cleanup_tasklet;
device->timer_fn = ioat2_timer_event; device->timer_fn = ioat2_timer_event;
device->self_test = ioat_dma_self_test; device->self_test = ioat_dma_self_test;
......
...@@ -185,6 +185,8 @@ bool reshape_ring(struct ioat2_dma_chan *ioat, int order); ...@@ -185,6 +185,8 @@ bool reshape_ring(struct ioat2_dma_chan *ioat, int order);
void __ioat2_issue_pending(struct ioat2_dma_chan *ioat); void __ioat2_issue_pending(struct ioat2_dma_chan *ioat);
void ioat2_cleanup_tasklet(unsigned long data); void ioat2_cleanup_tasklet(unsigned long data);
void ioat2_timer_event(unsigned long data); void ioat2_timer_event(unsigned long data);
int ioat2_quiesce(struct ioat_chan_common *chan, unsigned long tmo);
int ioat2_reset_sync(struct ioat_chan_common *chan, unsigned long tmo);
extern struct kobj_type ioat2_ktype; extern struct kobj_type ioat2_ktype;
extern struct kmem_cache *ioat2_cache; extern struct kmem_cache *ioat2_cache;
#endif /* IOATDMA_V2_H */ #endif /* IOATDMA_V2_H */
...@@ -650,9 +650,11 @@ __ioat3_prep_pq_lock(struct dma_chan *c, enum sum_check_flags *result, ...@@ -650,9 +650,11 @@ __ioat3_prep_pq_lock(struct dma_chan *c, enum sum_check_flags *result,
num_descs = ioat2_xferlen_to_descs(ioat, len); num_descs = ioat2_xferlen_to_descs(ioat, len);
/* we need 2x the number of descriptors to cover greater than 3 /* we need 2x the number of descriptors to cover greater than 3
* sources * sources (we need 1 extra source in the q-only continuation
* case and 3 extra sources in the p+q continuation case.
*/ */
if (src_cnt > 3 || flags & DMA_PREP_CONTINUE) { if (src_cnt + dmaf_p_disabled_continue(flags) > 3 ||
(dmaf_continue(flags) && !dmaf_p_disabled_continue(flags))) {
with_ext = 1; with_ext = 1;
num_descs *= 2; num_descs *= 2;
} else } else
...@@ -1128,6 +1130,45 @@ static int __devinit ioat3_dma_self_test(struct ioatdma_device *device) ...@@ -1128,6 +1130,45 @@ static int __devinit ioat3_dma_self_test(struct ioatdma_device *device)
return 0; return 0;
} }
static int ioat3_reset_hw(struct ioat_chan_common *chan)
{
/* throw away whatever the channel was doing and get it
* initialized, with ioat3 specific workarounds
*/
struct ioatdma_device *device = chan->device;
struct pci_dev *pdev = device->pdev;
u32 chanerr;
u16 dev_id;
int err;
ioat2_quiesce(chan, msecs_to_jiffies(100));
chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET);
/* -= IOAT ver.3 workarounds =- */
/* Write CHANERRMSK_INT with 3E07h to mask out the errors
* that can cause stability issues for IOAT ver.3, and clear any
* pending errors
*/
pci_write_config_dword(pdev, IOAT_PCI_CHANERRMASK_INT_OFFSET, 0x3e07);
err = pci_read_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, &chanerr);
if (err) {
dev_err(&pdev->dev, "channel error register unreachable\n");
return err;
}
pci_write_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, chanerr);
/* Clear DMAUNCERRSTS Cfg-Reg Parity Error status bit
* (workaround for spurious config parity error after restart)
*/
pci_read_config_word(pdev, IOAT_PCI_DEVICE_ID_OFFSET, &dev_id);
if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0)
pci_write_config_dword(pdev, IOAT_PCI_DMAUNCERRSTS_OFFSET, 0x10);
return ioat2_reset_sync(chan, msecs_to_jiffies(200));
}
int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca) int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca)
{ {
struct pci_dev *pdev = device->pdev; struct pci_dev *pdev = device->pdev;
...@@ -1137,10 +1178,10 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca) ...@@ -1137,10 +1178,10 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca)
struct ioat_chan_common *chan; struct ioat_chan_common *chan;
bool is_raid_device = false; bool is_raid_device = false;
int err; int err;
u16 dev_id;
u32 cap; u32 cap;
device->enumerate_channels = ioat2_enumerate_channels; device->enumerate_channels = ioat2_enumerate_channels;
device->reset_hw = ioat3_reset_hw;
device->self_test = ioat3_dma_self_test; device->self_test = ioat3_dma_self_test;
dma = &device->common; dma = &device->common;
dma->device_prep_dma_memcpy = ioat2_dma_prep_memcpy_lock; dma->device_prep_dma_memcpy = ioat2_dma_prep_memcpy_lock;
...@@ -1216,19 +1257,6 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca) ...@@ -1216,19 +1257,6 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca)
dma->device_prep_dma_xor_val = NULL; dma->device_prep_dma_xor_val = NULL;
#endif #endif
/* -= IOAT ver.3 workarounds =- */
/* Write CHANERRMSK_INT with 3E07h to mask out the errors
* that can cause stability issues for IOAT ver.3
*/
pci_write_config_dword(pdev, IOAT_PCI_CHANERRMASK_INT_OFFSET, 0x3e07);
/* Clear DMAUNCERRSTS Cfg-Reg Parity Error status bit
* (workaround for spurious config parity error after restart)
*/
pci_read_config_word(pdev, IOAT_PCI_DEVICE_ID_OFFSET, &dev_id);
if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0)
pci_write_config_dword(pdev, IOAT_PCI_DMAUNCERRSTS_OFFSET, 0x10);
err = ioat_probe(device); err = ioat_probe(device);
if (err) if (err)
return err; return err;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define IOAT_PCI_DEVICE_ID_OFFSET 0x02 #define IOAT_PCI_DEVICE_ID_OFFSET 0x02
#define IOAT_PCI_DMAUNCERRSTS_OFFSET 0x148 #define IOAT_PCI_DMAUNCERRSTS_OFFSET 0x148
#define IOAT_PCI_CHANERR_INT_OFFSET 0x180
#define IOAT_PCI_CHANERRMASK_INT_OFFSET 0x184 #define IOAT_PCI_CHANERRMASK_INT_OFFSET 0x184
/* MMIO Device Registers */ /* MMIO Device Registers */
......
This diff is collapsed.
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
#ifndef __DMA_SHDMA_H #ifndef __DMA_SHDMA_H
#define __DMA_SHDMA_H #define __DMA_SHDMA_H
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */ #define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */
...@@ -26,13 +26,16 @@ struct sh_dmae_regs { ...@@ -26,13 +26,16 @@ struct sh_dmae_regs {
}; };
struct sh_desc { struct sh_desc {
struct list_head tx_list;
struct sh_dmae_regs hw; struct sh_dmae_regs hw;
struct list_head node; struct list_head node;
struct dma_async_tx_descriptor async_tx; struct dma_async_tx_descriptor async_tx;
dma_cookie_t cookie;
int chunks;
int mark; int mark;
}; };
struct device;
struct sh_dmae_chan { struct sh_dmae_chan {
dma_cookie_t completed_cookie; /* The maximum cookie completed */ dma_cookie_t completed_cookie; /* The maximum cookie completed */
spinlock_t desc_lock; /* Descriptor operation lock */ spinlock_t desc_lock; /* Descriptor operation lock */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment