Skip to content

Commit

Permalink
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git…
Browse files Browse the repository at this point in the history
…/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'
  • Loading branch information
torvalds committed Dec 30, 2009
2 parents 1f11abc + f80ca16 commit 05a6254
Show file tree
Hide file tree
Showing 12 changed files with 341 additions and 159 deletions.
7 changes: 7 additions & 0 deletions crypto/async_tx/raid6test.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,13 @@ static int raid6_test(void)
err += test(4, &tests);
if (NDISKS > 5)
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);

pr("\n");
Expand Down
4 changes: 2 additions & 2 deletions drivers/dma/at_hdmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
cookie, done ? *done : 0, used ? *used : 0);

spin_lock_bh(atchan->lock);
spin_lock_bh(&atchan->lock);

last_complete = atchan->completed_cookie;
last_used = chan->cookie;
Expand All @@ -830,7 +830,7 @@ atc_is_tx_complete(struct dma_chan *chan,
ret = dma_async_is_complete(cookie, last_complete, last_used);
}

spin_unlock_bh(atchan->lock);
spin_unlock_bh(&atchan->lock);

if (done)
*done = last_complete;
Expand Down
2 changes: 1 addition & 1 deletion drivers/dma/coh901318.c
Original file line number Diff line number Diff line change
Expand Up @@ -1294,8 +1294,8 @@ static int __exit coh901318_remove(struct platform_device *pdev)
dma_async_device_unregister(&base->dma_slave);
coh901318_pool_destroy(&base->pool);
free_irq(platform_get_irq(pdev, 0), base);
kfree(base);
iounmap(base->virtbase);
kfree(base);
release_mem_region(pdev->resource->start,
resource_size(pdev->resource));
return 0;
Expand Down
2 changes: 0 additions & 2 deletions drivers/dma/dw_dmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -1270,8 +1270,6 @@ static int __init dw_probe(struct platform_device *pdev)
goto err_kfree;
}

memset(dw, 0, sizeof *dw);

dw->regs = ioremap(io->start, DW_REGLEN);
if (!dw->regs) {
err = -ENOMEM;
Expand Down
2 changes: 1 addition & 1 deletion drivers/dma/ioat/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,7 @@ int __devinit ioat_probe(struct ioatdma_device *device)
dma->dev = &pdev->dev;

if (!dma->chancnt) {
dev_err(dev, "zero channels detected\n");
dev_err(dev, "channel enumeration error\n");
goto err_setup_interrupts;
}

Expand Down
18 changes: 18 additions & 0 deletions drivers/dma/ioat/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
* @dca: direct cache access context
* @intr_quirk: interrupt setup quirk (for ioat_v1 devices)
* @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
* @timer_fn: select between the v2 and v3 timer watchdog routines
* @self_test: hardware version specific self test for each supported op type
Expand All @@ -78,6 +79,7 @@ struct ioatdma_device {
struct dca_provider *dca;
void (*intr_quirk)(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 (*timer_fn)(unsigned long data);
int (*self_test)(struct ioatdma_device *device);
Expand Down Expand Up @@ -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));
}

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)
{
struct ioat_chan_common *chan = &ioat->base;
Expand Down
69 changes: 52 additions & 17 deletions drivers/dma/ioat/dma_v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,20 +239,50 @@ void __ioat2_restart_chan(struct ioat2_dma_chan *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 phys_complete;
unsigned long end = jiffies + tmo;
int err = 0;
u32 status;

status = ioat_chansts(chan);
if (is_ioat_active(status) || is_ioat_idle(status))
ioat_suspend(chan);
while (is_ioat_active(status) || is_ioat_idle(status)) {
if (end && time_after(jiffies, end)) {
err = -ETIMEDOUT;
break;
}
status = ioat_chansts(chan);
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))
__cleanup(ioat, phys_complete);

Expand Down Expand Up @@ -318,6 +348,19 @@ void ioat2_timer_event(unsigned long data)
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
* @device: the device to be enumerated
Expand Down Expand Up @@ -360,6 +403,10 @@ int ioat2_enumerate_channels(struct ioatdma_device *device)
(unsigned long) ioat);
ioat->xfercap_log = xfercap_log;
spin_lock_init(&ioat->ring_lock);
if (device->reset_hw(&ioat->base)) {
i = 0;
break;
}
}
dma->chancnt = i;
return i;
Expand Down Expand Up @@ -467,7 +514,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
struct ioat_chan_common *chan = &ioat->base;
struct ioat_ring_ent **ring;
u32 chanerr;
int order;

/* have we already been set up? */
Expand All @@ -477,12 +523,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
/* Setup register to interrupt and write completion status on error */
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 */
/* doing 2 32bit writes to mmio since 1 64b write doesn't work */
chan->completion = pci_pool_alloc(chan->device->completion_pool,
Expand Down Expand Up @@ -746,13 +786,7 @@ void ioat2_free_chan_resources(struct dma_chan *c)
tasklet_disable(&chan->cleanup_task);
del_timer_sync(&chan->timer);
device->cleanup_tasklet((unsigned long) ioat);

/* 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);
device->reset_hw(chan);

spin_lock_bh(&ioat->ring_lock);
descs = ioat2_ring_space(ioat);
Expand Down Expand Up @@ -839,6 +873,7 @@ int __devinit ioat2_dma_probe(struct ioatdma_device *device, int dca)
int err;

device->enumerate_channels = ioat2_enumerate_channels;
device->reset_hw = ioat2_reset_hw;
device->cleanup_tasklet = ioat2_cleanup_tasklet;
device->timer_fn = ioat2_timer_event;
device->self_test = ioat_dma_self_test;
Expand Down
2 changes: 2 additions & 0 deletions drivers/dma/ioat/dma_v2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_cleanup_tasklet(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 kmem_cache *ioat2_cache;
#endif /* IOATDMA_V2_H */
60 changes: 44 additions & 16 deletions drivers/dma/ioat/dma_v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
/* 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;
num_descs *= 2;
} else
Expand Down Expand Up @@ -1128,6 +1130,45 @@ static int __devinit ioat3_dma_self_test(struct ioatdma_device *device)
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)
{
struct pci_dev *pdev = device->pdev;
Expand All @@ -1137,10 +1178,10 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca)
struct ioat_chan_common *chan;
bool is_raid_device = false;
int err;
u16 dev_id;
u32 cap;

device->enumerate_channels = ioat2_enumerate_channels;
device->reset_hw = ioat3_reset_hw;
device->self_test = ioat3_dma_self_test;
dma = &device->common;
dma->device_prep_dma_memcpy = ioat2_dma_prep_memcpy_lock;
Expand Down Expand Up @@ -1216,19 +1257,6 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca)
dma->device_prep_dma_xor_val = NULL;
#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);
if (err)
return err;
Expand Down
1 change: 1 addition & 0 deletions drivers/dma/ioat/registers.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#define IOAT_PCI_DEVICE_ID_OFFSET 0x02
#define IOAT_PCI_DMAUNCERRSTS_OFFSET 0x148
#define IOAT_PCI_CHANERR_INT_OFFSET 0x180
#define IOAT_PCI_CHANERRMASK_INT_OFFSET 0x184

/* MMIO Device Registers */
Expand Down
Loading

0 comments on commit 05a6254

Please sign in to comment.