|
@@ -77,7 +77,8 @@ static irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
|
|
|
attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
|
|
|
for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) {
|
|
|
chan = ioat_chan_by_index(instance, bit);
|
|
|
- tasklet_schedule(&chan->cleanup_task);
|
|
|
+ if (test_bit(IOAT_RUN, &chan->state))
|
|
|
+ tasklet_schedule(&chan->cleanup_task);
|
|
|
}
|
|
|
|
|
|
writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
|
|
@@ -93,7 +94,8 @@ static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
|
|
|
{
|
|
|
struct ioat_chan_common *chan = data;
|
|
|
|
|
|
- tasklet_schedule(&chan->cleanup_task);
|
|
|
+ if (test_bit(IOAT_RUN, &chan->state))
|
|
|
+ tasklet_schedule(&chan->cleanup_task);
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
@@ -116,7 +118,6 @@ void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *c
|
|
|
chan->timer.function = device->timer_fn;
|
|
|
chan->timer.data = data;
|
|
|
tasklet_init(&chan->cleanup_task, device->cleanup_fn, data);
|
|
|
- tasklet_disable(&chan->cleanup_task);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -354,13 +355,49 @@ static int ioat1_dma_alloc_chan_resources(struct dma_chan *c)
|
|
|
writel(((u64) chan->completion_dma) >> 32,
|
|
|
chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
|
|
|
|
|
|
- tasklet_enable(&chan->cleanup_task);
|
|
|
+ set_bit(IOAT_RUN, &chan->state);
|
|
|
ioat1_dma_start_null_desc(ioat); /* give chain to dma device */
|
|
|
dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n",
|
|
|
__func__, ioat->desccount);
|
|
|
return ioat->desccount;
|
|
|
}
|
|
|
|
|
|
+void ioat_stop(struct ioat_chan_common *chan)
|
|
|
+{
|
|
|
+ struct ioatdma_device *device = chan->device;
|
|
|
+ struct pci_dev *pdev = device->pdev;
|
|
|
+ int chan_id = chan_num(chan);
|
|
|
+ struct msix_entry *msix;
|
|
|
+
|
|
|
+ /* 1/ stop irq from firing tasklets
|
|
|
+ * 2/ stop the tasklet from re-arming irqs
|
|
|
+ */
|
|
|
+ clear_bit(IOAT_RUN, &chan->state);
|
|
|
+
|
|
|
+ /* flush inflight interrupts */
|
|
|
+ switch (device->irq_mode) {
|
|
|
+ case IOAT_MSIX:
|
|
|
+ msix = &device->msix_entries[chan_id];
|
|
|
+ synchronize_irq(msix->vector);
|
|
|
+ break;
|
|
|
+ case IOAT_MSI:
|
|
|
+ case IOAT_INTX:
|
|
|
+ synchronize_irq(pdev->irq);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* flush inflight timers */
|
|
|
+ del_timer_sync(&chan->timer);
|
|
|
+
|
|
|
+ /* flush inflight tasklet runs */
|
|
|
+ tasklet_kill(&chan->cleanup_task);
|
|
|
+
|
|
|
+ /* final cleanup now that everything is quiesced and can't re-arm */
|
|
|
+ device->cleanup_fn((unsigned long) &chan->common);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ioat1_dma_free_chan_resources - release all the descriptors
|
|
|
* @chan: the channel to be cleaned
|
|
@@ -379,9 +416,7 @@ static void ioat1_dma_free_chan_resources(struct dma_chan *c)
|
|
|
if (ioat->desccount == 0)
|
|
|
return;
|
|
|
|
|
|
- tasklet_disable(&chan->cleanup_task);
|
|
|
- del_timer_sync(&chan->timer);
|
|
|
- ioat1_cleanup(ioat);
|
|
|
+ ioat_stop(chan);
|
|
|
|
|
|
/* Delay 100ms after reset to allow internal DMA logic to quiesce
|
|
|
* before removing DMA descriptor resources.
|
|
@@ -526,8 +561,11 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest,
|
|
|
static void ioat1_cleanup_event(unsigned long data)
|
|
|
{
|
|
|
struct ioat_dma_chan *ioat = to_ioat_chan((void *) data);
|
|
|
+ struct ioat_chan_common *chan = &ioat->base;
|
|
|
|
|
|
ioat1_cleanup(ioat);
|
|
|
+ if (!test_bit(IOAT_RUN, &chan->state))
|
|
|
+ return;
|
|
|
writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
|
|
|
}
|
|
|
|