]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/dma/ioat/dma_v3.c
ioat3: interrupt coalescing
[net-next-2.6.git] / drivers / dma / ioat / dma_v3.c
index 42f6f10fb0cc249b2b07854f00e556f8335029d7..9988f13401865628161b834349d4898bdd47a310 100644 (file)
@@ -293,17 +293,25 @@ static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete)
                }
        }
        ioat->tail += i;
-       BUG_ON(!seen_current); /* no active descs have written a completion? */
+       BUG_ON(active && !seen_current); /* no active descs have written a completion? */
        chan->last_completion = phys_complete;
-       if (ioat->head == ioat->tail) {
+
+       active = ioat2_ring_active(ioat);
+       if (active == 0) {
                dev_dbg(to_dev(chan), "%s: cancel completion timeout\n",
                        __func__);
                clear_bit(IOAT_COMPLETION_PENDING, &chan->state);
                mod_timer(&chan->timer, jiffies + IDLE_TIMEOUT);
        }
+       /* 5 microsecond delay per pending descriptor */
+       writew(min((5 * active), IOAT_INTRDELAY_MASK),
+              chan->device->reg_base + IOAT_INTRDELAY_OFFSET);
 }
 
-static void ioat3_cleanup(struct ioat2_dma_chan *ioat)
+/* try to cleanup, but yield (via spin_trylock) to incoming submissions
+ * with the expectation that we will immediately poll again shortly
+ */
+static void ioat3_cleanup_poll(struct ioat2_dma_chan *ioat)
 {
        struct ioat_chan_common *chan = &ioat->base;
        unsigned long phys_complete;
@@ -329,29 +337,41 @@ static void ioat3_cleanup(struct ioat2_dma_chan *ioat)
        spin_unlock_bh(&chan->cleanup_lock);
 }
 
+/* run cleanup now because we already delayed the interrupt via INTRDELAY */
+static void ioat3_cleanup_sync(struct ioat2_dma_chan *ioat)
+{
+       struct ioat_chan_common *chan = &ioat->base;
+       unsigned long phys_complete;
+
+       prefetch(chan->completion);
+
+       spin_lock_bh(&chan->cleanup_lock);
+       if (!ioat_cleanup_preamble(chan, &phys_complete)) {
+               spin_unlock_bh(&chan->cleanup_lock);
+               return;
+       }
+       spin_lock_bh(&ioat->ring_lock);
+
+       __cleanup(ioat, phys_complete);
+
+       spin_unlock_bh(&ioat->ring_lock);
+       spin_unlock_bh(&chan->cleanup_lock);
+}
+
 static void ioat3_cleanup_tasklet(unsigned long data)
 {
        struct ioat2_dma_chan *ioat = (void *) data;
 
-       ioat3_cleanup(ioat);
-       writew(IOAT_CHANCTRL_RUN | IOAT3_CHANCTRL_COMPL_DCA_EN,
-              ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
+       ioat3_cleanup_sync(ioat);
+       writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
 }
 
 static void ioat3_restart_channel(struct ioat2_dma_chan *ioat)
 {
        struct ioat_chan_common *chan = &ioat->base;
        unsigned long phys_complete;
-       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)) {
-               status = ioat_chansts(chan);
-               cpu_relax();
-       }
 
+       ioat2_quiesce(chan, 0);
        if (ioat_cleanup_preamble(chan, &phys_complete))
                __cleanup(ioat, phys_complete);
 
@@ -426,7 +446,7 @@ ioat3_is_complete(struct dma_chan *c, dma_cookie_t cookie,
        if (ioat_is_complete(c, cookie, done, used) == DMA_SUCCESS)
                return DMA_SUCCESS;
 
-       ioat3_cleanup(ioat);
+       ioat3_cleanup_poll(ioat);
 
        return ioat_is_complete(c, cookie, done, used);
 }
@@ -650,9 +670,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
@@ -1128,6 +1150,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;
@@ -1137,10 +1198,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;
@@ -1216,19 +1277,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;