Merge branch 'misc.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / drivers / dma / idxd / irq.c
index 4e3a719..ca88fa7 100644 (file)
@@ -22,13 +22,6 @@ struct idxd_fault {
        struct idxd_device *idxd;
 };
 
-static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
-                                enum irq_work_type wtype,
-                                int *processed, u64 data);
-static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry,
-                                    enum irq_work_type wtype,
-                                    int *processed, u64 data);
-
 static void idxd_device_reinit(struct work_struct *work)
 {
        struct idxd_device *idxd = container_of(work, struct idxd_device, work);
@@ -51,7 +44,7 @@ static void idxd_device_reinit(struct work_struct *work)
                        rc = idxd_wq_enable(wq);
                        if (rc < 0) {
                                dev_warn(dev, "Unable to re-enable wq %s\n",
-                                        dev_name(&wq->conf_dev));
+                                        dev_name(wq_confdev(wq)));
                        }
                }
        }
@@ -59,47 +52,7 @@ static void idxd_device_reinit(struct work_struct *work)
        return;
 
  out:
-       idxd_device_wqs_clear_state(idxd);
-}
-
-static void idxd_device_fault_work(struct work_struct *work)
-{
-       struct idxd_fault *fault = container_of(work, struct idxd_fault, work);
-       struct idxd_irq_entry *ie;
-       int i;
-       int processed;
-       int irqcnt = fault->idxd->num_wq_irqs + 1;
-
-       for (i = 1; i < irqcnt; i++) {
-               ie = &fault->idxd->irq_entries[i];
-               irq_process_work_list(ie, IRQ_WORK_PROCESS_FAULT,
-                                     &processed, fault->addr);
-               if (processed)
-                       break;
-
-               irq_process_pending_llist(ie, IRQ_WORK_PROCESS_FAULT,
-                                         &processed, fault->addr);
-               if (processed)
-                       break;
-       }
-
-       kfree(fault);
-}
-
-static int idxd_device_schedule_fault_process(struct idxd_device *idxd,
-                                             u64 fault_addr)
-{
-       struct idxd_fault *fault;
-
-       fault = kmalloc(sizeof(*fault), GFP_ATOMIC);
-       if (!fault)
-               return -ENOMEM;
-
-       fault->addr = fault_addr;
-       fault->idxd = idxd;
-       INIT_WORK(&fault->work, idxd_device_fault_work);
-       queue_work(idxd->wq, &fault->work);
-       return 0;
+       idxd_device_clear_state(idxd);
 }
 
 static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
@@ -111,7 +64,7 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
        bool err = false;
 
        if (cause & IDXD_INTC_ERR) {
-               spin_lock_bh(&idxd->dev_lock);
+               spin_lock(&idxd->dev_lock);
                for (i = 0; i < 4; i++)
                        idxd->sw_err.bits[i] = ioread64(idxd->reg_base +
                                        IDXD_SWERR_OFFSET + i * sizeof(u64));
@@ -136,7 +89,7 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
                        }
                }
 
-               spin_unlock_bh(&idxd->dev_lock);
+               spin_unlock(&idxd->dev_lock);
                val |= IDXD_INTC_ERR;
 
                for (i = 0; i < 4; i++)
@@ -168,15 +121,6 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
        if (!err)
                return 0;
 
-       /*
-        * This case should rarely happen and typically is due to software
-        * programming error by the driver.
-        */
-       if (idxd->sw_err.valid &&
-           idxd->sw_err.desc_valid &&
-           idxd->sw_err.fault_addr)
-               idxd_device_schedule_fault_process(idxd, idxd->sw_err.fault_addr);
-
        gensts.bits = ioread32(idxd->reg_base + IDXD_GENSTATS_OFFSET);
        if (gensts.state == IDXD_DEVICE_STATE_HALT) {
                idxd->state = IDXD_DEV_HALTED;
@@ -189,15 +133,15 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
                        INIT_WORK(&idxd->work, idxd_device_reinit);
                        queue_work(idxd->wq, &idxd->work);
                } else {
-                       spin_lock_bh(&idxd->dev_lock);
+                       spin_lock(&idxd->dev_lock);
                        idxd_wqs_quiesce(idxd);
                        idxd_wqs_unmap_portal(idxd);
-                       idxd_device_wqs_clear_state(idxd);
+                       idxd_device_clear_state(idxd);
                        dev_err(&idxd->pdev->dev,
                                "idxd halted, need %s.\n",
                                gensts.reset_type == IDXD_DEVICE_RESET_FLR ?
                                "FLR" : "system reset");
-                       spin_unlock_bh(&idxd->dev_lock);
+                       spin_unlock(&idxd->dev_lock);
                        return -ENXIO;
                }
        }
@@ -228,127 +172,79 @@ irqreturn_t idxd_misc_thread(int vec, void *data)
        return IRQ_HANDLED;
 }
 
-static inline bool match_fault(struct idxd_desc *desc, u64 fault_addr)
-{
-       /*
-        * Completion address can be bad as well. Check fault address match for descriptor
-        * and completion address.
-        */
-       if ((u64)desc->hw == fault_addr || (u64)desc->completion == fault_addr) {
-               struct idxd_device *idxd = desc->wq->idxd;
-               struct device *dev = &idxd->pdev->dev;
-
-               dev_warn(dev, "desc with fault address: %#llx\n", fault_addr);
-               return true;
-       }
-
-       return false;
-}
-
-static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry,
-                                    enum irq_work_type wtype,
-                                    int *processed, u64 data)
+static void irq_process_pending_llist(struct idxd_irq_entry *irq_entry)
 {
        struct idxd_desc *desc, *t;
        struct llist_node *head;
-       int queued = 0;
-       unsigned long flags;
-       enum idxd_complete_type reason;
 
-       *processed = 0;
        head = llist_del_all(&irq_entry->pending_llist);
        if (!head)
-               goto out;
-
-       if (wtype == IRQ_WORK_NORMAL)
-               reason = IDXD_COMPLETE_NORMAL;
-       else
-               reason = IDXD_COMPLETE_DEV_FAIL;
+               return;
 
        llist_for_each_entry_safe(desc, t, head, llnode) {
                u8 status = desc->completion->status & DSA_COMP_STATUS_MASK;
 
                if (status) {
-                       if (unlikely(status == IDXD_COMP_DESC_ABORT)) {
+                       /*
+                        * Check against the original status as ABORT is software defined
+                        * and 0xff, which DSA_COMP_STATUS_MASK can mask out.
+                        */
+                       if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) {
                                complete_desc(desc, IDXD_COMPLETE_ABORT);
-                               (*processed)++;
                                continue;
                        }
 
-                       if (unlikely(status != DSA_COMP_SUCCESS))
-                               match_fault(desc, data);
-                       complete_desc(desc, reason);
-                       (*processed)++;
+                       complete_desc(desc, IDXD_COMPLETE_NORMAL);
                } else {
-                       spin_lock_irqsave(&irq_entry->list_lock, flags);
+                       spin_lock(&irq_entry->list_lock);
                        list_add_tail(&desc->list,
                                      &irq_entry->work_list);
-                       spin_unlock_irqrestore(&irq_entry->list_lock, flags);
-                       queued++;
+                       spin_unlock(&irq_entry->list_lock);
                }
        }
-
- out:
-       return queued;
 }
 
-static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
-                                enum irq_work_type wtype,
-                                int *processed, u64 data)
+static void irq_process_work_list(struct idxd_irq_entry *irq_entry)
 {
-       int queued = 0;
-       unsigned long flags;
        LIST_HEAD(flist);
        struct idxd_desc *desc, *n;
-       enum idxd_complete_type reason;
-
-       *processed = 0;
-       if (wtype == IRQ_WORK_NORMAL)
-               reason = IDXD_COMPLETE_NORMAL;
-       else
-               reason = IDXD_COMPLETE_DEV_FAIL;
 
        /*
         * This lock protects list corruption from access of list outside of the irq handler
         * thread.
         */
-       spin_lock_irqsave(&irq_entry->list_lock, flags);
+       spin_lock(&irq_entry->list_lock);
        if (list_empty(&irq_entry->work_list)) {
-               spin_unlock_irqrestore(&irq_entry->list_lock, flags);
-               return 0;
+               spin_unlock(&irq_entry->list_lock);
+               return;
        }
 
        list_for_each_entry_safe(desc, n, &irq_entry->work_list, list) {
                if (desc->completion->status) {
                        list_del(&desc->list);
-                       (*processed)++;
                        list_add_tail(&desc->list, &flist);
-               } else {
-                       queued++;
                }
        }
 
-       spin_unlock_irqrestore(&irq_entry->list_lock, flags);
+       spin_unlock(&irq_entry->list_lock);
 
        list_for_each_entry(desc, &flist, list) {
-               u8 status = desc->completion->status & DSA_COMP_STATUS_MASK;
-
-               if (unlikely(status == IDXD_COMP_DESC_ABORT)) {
+               /*
+                * Check against the original status as ABORT is software defined
+                * and 0xff, which DSA_COMP_STATUS_MASK can mask out.
+                */
+               if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) {
                        complete_desc(desc, IDXD_COMPLETE_ABORT);
                        continue;
                }
 
-               if (unlikely(status != DSA_COMP_SUCCESS))
-                       match_fault(desc, data);
-               complete_desc(desc, reason);
+               complete_desc(desc, IDXD_COMPLETE_NORMAL);
        }
-
-       return queued;
 }
 
-static int idxd_desc_process(struct idxd_irq_entry *irq_entry)
+irqreturn_t idxd_wq_thread(int irq, void *data)
 {
-       int rc, processed, total = 0;
+       struct idxd_irq_entry *irq_entry = data;
 
        /*
         * There are two lists we are processing. The pending_llist is where
@@ -367,31 +263,9 @@ static int idxd_desc_process(struct idxd_irq_entry *irq_entry)
         *    and process the completed entries.
         * 4. If the entry is still waiting on hardware, list_add_tail() to
         *    the work_list.
-        * 5. Repeat until no more descriptors.
         */
-       do {
-               rc = irq_process_work_list(irq_entry, IRQ_WORK_NORMAL,
-                                          &processed, 0);
-               total += processed;
-               if (rc != 0)
-                       continue;
-
-               rc = irq_process_pending_llist(irq_entry, IRQ_WORK_NORMAL,
-                                              &processed, 0);
-               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);
-       if (processed == 0)
-               return IRQ_NONE;
+       irq_process_work_list(irq_entry);
+       irq_process_pending_llist(irq_entry);
 
        return IRQ_HANDLED;
 }