diff options
Diffstat (limited to 'drivers/dma/ioat/dma.c')
| -rw-r--r-- | drivers/dma/ioat/dma.c | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 87529181efcc..4e3549a16132 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c | |||
| @@ -77,7 +77,8 @@ static irqreturn_t ioat_dma_do_interrupt(int irq, void *data) | |||
| 77 | attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET); | 77 | attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET); |
| 78 | for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) { | 78 | for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) { |
| 79 | chan = ioat_chan_by_index(instance, bit); | 79 | chan = ioat_chan_by_index(instance, bit); |
| 80 | tasklet_schedule(&chan->cleanup_task); | 80 | if (test_bit(IOAT_RUN, &chan->state)) |
| 81 | tasklet_schedule(&chan->cleanup_task); | ||
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); | 84 | writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); |
| @@ -93,7 +94,8 @@ static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data) | |||
| 93 | { | 94 | { |
| 94 | struct ioat_chan_common *chan = data; | 95 | struct ioat_chan_common *chan = data; |
| 95 | 96 | ||
| 96 | tasklet_schedule(&chan->cleanup_task); | 97 | if (test_bit(IOAT_RUN, &chan->state)) |
| 98 | tasklet_schedule(&chan->cleanup_task); | ||
| 97 | 99 | ||
| 98 | return IRQ_HANDLED; | 100 | return IRQ_HANDLED; |
| 99 | } | 101 | } |
| @@ -116,7 +118,6 @@ void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *c | |||
| 116 | chan->timer.function = device->timer_fn; | 118 | chan->timer.function = device->timer_fn; |
| 117 | chan->timer.data = data; | 119 | chan->timer.data = data; |
| 118 | tasklet_init(&chan->cleanup_task, device->cleanup_fn, data); | 120 | tasklet_init(&chan->cleanup_task, device->cleanup_fn, data); |
| 119 | tasklet_disable(&chan->cleanup_task); | ||
| 120 | } | 121 | } |
| 121 | 122 | ||
| 122 | /** | 123 | /** |
| @@ -354,13 +355,49 @@ static int ioat1_dma_alloc_chan_resources(struct dma_chan *c) | |||
| 354 | writel(((u64) chan->completion_dma) >> 32, | 355 | writel(((u64) chan->completion_dma) >> 32, |
| 355 | chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH); | 356 | chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH); |
| 356 | 357 | ||
| 357 | tasklet_enable(&chan->cleanup_task); | 358 | set_bit(IOAT_RUN, &chan->state); |
| 358 | ioat1_dma_start_null_desc(ioat); /* give chain to dma device */ | 359 | ioat1_dma_start_null_desc(ioat); /* give chain to dma device */ |
| 359 | dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n", | 360 | dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n", |
| 360 | __func__, ioat->desccount); | 361 | __func__, ioat->desccount); |
| 361 | return ioat->desccount; | 362 | return ioat->desccount; |
| 362 | } | 363 | } |
| 363 | 364 | ||
| 365 | void ioat_stop(struct ioat_chan_common *chan) | ||
| 366 | { | ||
| 367 | struct ioatdma_device *device = chan->device; | ||
| 368 | struct pci_dev *pdev = device->pdev; | ||
| 369 | int chan_id = chan_num(chan); | ||
| 370 | struct msix_entry *msix; | ||
| 371 | |||
| 372 | /* 1/ stop irq from firing tasklets | ||
| 373 | * 2/ stop the tasklet from re-arming irqs | ||
| 374 | */ | ||
| 375 | clear_bit(IOAT_RUN, &chan->state); | ||
| 376 | |||
| 377 | /* flush inflight interrupts */ | ||
| 378 | switch (device->irq_mode) { | ||
| 379 | case IOAT_MSIX: | ||
| 380 | msix = &device->msix_entries[chan_id]; | ||
| 381 | synchronize_irq(msix->vector); | ||
| 382 | break; | ||
| 383 | case IOAT_MSI: | ||
| 384 | case IOAT_INTX: | ||
| 385 | synchronize_irq(pdev->irq); | ||
| 386 | break; | ||
| 387 | default: | ||
| 388 | break; | ||
| 389 | } | ||
| 390 | |||
| 391 | /* flush inflight timers */ | ||
| 392 | del_timer_sync(&chan->timer); | ||
| 393 | |||
| 394 | /* flush inflight tasklet runs */ | ||
| 395 | tasklet_kill(&chan->cleanup_task); | ||
| 396 | |||
| 397 | /* final cleanup now that everything is quiesced and can't re-arm */ | ||
| 398 | device->cleanup_fn((unsigned long) &chan->common); | ||
| 399 | } | ||
| 400 | |||
| 364 | /** | 401 | /** |
| 365 | * ioat1_dma_free_chan_resources - release all the descriptors | 402 | * ioat1_dma_free_chan_resources - release all the descriptors |
| 366 | * @chan: the channel to be cleaned | 403 | * @chan: the channel to be cleaned |
| @@ -379,9 +416,7 @@ static void ioat1_dma_free_chan_resources(struct dma_chan *c) | |||
| 379 | if (ioat->desccount == 0) | 416 | if (ioat->desccount == 0) |
| 380 | return; | 417 | return; |
| 381 | 418 | ||
| 382 | tasklet_disable(&chan->cleanup_task); | 419 | ioat_stop(chan); |
| 383 | del_timer_sync(&chan->timer); | ||
| 384 | ioat1_cleanup(ioat); | ||
| 385 | 420 | ||
| 386 | /* Delay 100ms after reset to allow internal DMA logic to quiesce | 421 | /* Delay 100ms after reset to allow internal DMA logic to quiesce |
| 387 | * before removing DMA descriptor resources. | 422 | * before removing DMA descriptor resources. |
| @@ -526,8 +561,11 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest, | |||
| 526 | static void ioat1_cleanup_event(unsigned long data) | 561 | static void ioat1_cleanup_event(unsigned long data) |
| 527 | { | 562 | { |
| 528 | struct ioat_dma_chan *ioat = to_ioat_chan((void *) data); | 563 | struct ioat_dma_chan *ioat = to_ioat_chan((void *) data); |
| 564 | struct ioat_chan_common *chan = &ioat->base; | ||
| 529 | 565 | ||
| 530 | ioat1_cleanup(ioat); | 566 | ioat1_cleanup(ioat); |
| 567 | if (!test_bit(IOAT_RUN, &chan->state)) | ||
| 568 | return; | ||
| 531 | writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET); | 569 | writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET); |
| 532 | } | 570 | } |
| 533 | 571 | ||
