lkml.org 
[lkml]   [2020]   [Jun]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 5.6 159/606] dmaengine: idxd: fix interrupt completion after unmasking
    Date
    From: Dave Jiang <dave.jiang@intel.com>

    commit 4f302642b70c1348773fe7e3ded9fc315fa92990 upstream.

    The current implementation may miss completions after we unmask the
    interrupt. In order to make sure we process all competions, we need to:
    1. Do an MMIO read from the device as a barrier to ensure that all PCI
    writes for completions have arrived.
    2. Check for any additional completions that we missed.

    Fixes: 8f47d1a5e545 ("dmaengine: idxd: connect idxd to dmaengine subsystem")

    Reported-by: Sanjay Kumar <sanjay.k.kumar@intel.com>
    Signed-off-by: Dave Jiang <dave.jiang@intel.com>
    Link: https://lore.kernel.org/r/158834641769.35613.1341160109892008587.stgit@djiang5-desk3.ch.intel.com
    Signed-off-by: Vinod Koul <vkoul@kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/dma/idxd/device.c | 7 +++++++
    drivers/dma/idxd/irq.c | 26 +++++++++++++++++++-------
    2 files changed, 26 insertions(+), 7 deletions(-)

    diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
    index f6f49f0f6fae..8d79a8787104 100644
    --- a/drivers/dma/idxd/device.c
    +++ b/drivers/dma/idxd/device.c
    @@ -62,6 +62,13 @@ int idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id)
    perm.ignore = 0;
    iowrite32(perm.bits, idxd->reg_base + offset);

    + /*
    + * A readback from the device ensures that any previously generated
    + * completion record writes are visible to software based on PCI
    + * ordering rules.
    + */
    + perm.bits = ioread32(idxd->reg_base + offset);
    +
    return 0;
    }

    diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c
    index d6fcd2e60103..6510791b9921 100644
    --- a/drivers/dma/idxd/irq.c
    +++ b/drivers/dma/idxd/irq.c
    @@ -173,6 +173,7 @@ static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry,
    struct llist_node *head;
    int queued = 0;

    + *processed = 0;
    head = llist_del_all(&irq_entry->pending_llist);
    if (!head)
    return 0;
    @@ -197,6 +198,7 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
    struct list_head *node, *next;
    int queued = 0;

    + *processed = 0;
    if (list_empty(&irq_entry->work_list))
    return 0;

    @@ -218,10 +220,9 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
    return queued;
    }

    -irqreturn_t idxd_wq_thread(int irq, void *data)
    +static int idxd_desc_process(struct idxd_irq_entry *irq_entry)
    {
    - struct idxd_irq_entry *irq_entry = data;
    - int rc, processed = 0, retry = 0;
    + int rc, processed, total = 0;

    /*
    * There are two lists we are processing. The pending_llist is where
    @@ -244,15 +245,26 @@ irqreturn_t idxd_wq_thread(int irq, void *data)
    */
    do {
    rc = irq_process_work_list(irq_entry, &processed);
    - if (rc != 0) {
    - retry++;
    + total += processed;
    + if (rc != 0)
    continue;
    - }

    rc = irq_process_pending_llist(irq_entry, &processed);
    - } while (rc != 0 && retry != 10);
    + total += processed;
    + } while (rc != 0);
    +
    + return total;
    +}
    +
    +irqreturn_t idxd_wq_thread(int irq, void *data)
    +{
    + struct idxd_irq_entry *irq_entry = data;
    + int processed;

    + processed = idxd_desc_process(irq_entry);
    idxd_unmask_msix_vector(irq_entry->idxd, irq_entry->id);
    + /* catch anything unprocessed after unmasking */
    + processed += idxd_desc_process(irq_entry);

    if (processed == 0)
    return IRQ_NONE;
    --
    2.25.1
    \
     
     \ /
      Last update: 2020-06-09 02:32    [W:4.270 / U:0.124 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site