Skip to content

Commit d803c8b

Browse files
davejiangvinodkoul
authored andcommitted
dmaengine: idxd: make I/O interrupt handler one shot
The interrupt thread handler currently loops forever to process outstanding completions. This causes either an "irq X: nobody cared" kernel splat or the NMI watchdog kicks in due to running too long in the function. The irq thread handler is expected to run again after exiting if there are interrupts fired while the thread handler is running. So the handler code can process all the completed I/O in a single pass and exit without losing the follow on completed I/O. Reviewed-by: Dan Williams <[email protected]> Signed-off-by: Dave Jiang <[email protected]> Link: https://lore.kernel.org/r/162802977005.3084234.11836261157026497585.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul <[email protected]>
1 parent bd2f4ae commit d803c8b

File tree

1 file changed

+8
-51
lines changed

1 file changed

+8
-51
lines changed

drivers/dma/idxd/irq.c

Lines changed: 8 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ struct idxd_fault {
2222
struct idxd_device *idxd;
2323
};
2424

25-
static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
26-
int *processed, u64 data);
27-
static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry,
28-
int *processed, u64 data);
29-
3025
static void idxd_device_reinit(struct work_struct *work)
3126
{
3227
struct idxd_device *idxd = container_of(work, struct idxd_device, work);
@@ -177,18 +172,15 @@ irqreturn_t idxd_misc_thread(int vec, void *data)
177172
return IRQ_HANDLED;
178173
}
179174

180-
static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry,
181-
int *processed, u64 data)
175+
static void irq_process_pending_llist(struct idxd_irq_entry *irq_entry)
182176
{
183177
struct idxd_desc *desc, *t;
184178
struct llist_node *head;
185-
int queued = 0;
186179
unsigned long flags;
187180

188-
*processed = 0;
189181
head = llist_del_all(&irq_entry->pending_llist);
190182
if (!head)
191-
goto out;
183+
return;
192184

193185
llist_for_each_entry_safe(desc, t, head, llnode) {
194186
u8 status = desc->completion->status & DSA_COMP_STATUS_MASK;
@@ -200,52 +192,39 @@ static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry,
200192
*/
201193
if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) {
202194
complete_desc(desc, IDXD_COMPLETE_ABORT);
203-
(*processed)++;
204195
continue;
205196
}
206197

207198
complete_desc(desc, IDXD_COMPLETE_NORMAL);
208-
(*processed)++;
209199
} else {
210200
spin_lock_irqsave(&irq_entry->list_lock, flags);
211201
list_add_tail(&desc->list,
212202
&irq_entry->work_list);
213203
spin_unlock_irqrestore(&irq_entry->list_lock, flags);
214-
queued++;
215204
}
216205
}
217-
218-
out:
219-
return queued;
220206
}
221207

222-
static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
223-
int *processed, u64 data)
208+
static void irq_process_work_list(struct idxd_irq_entry *irq_entry)
224209
{
225-
int queued = 0;
226210
unsigned long flags;
227211
LIST_HEAD(flist);
228212
struct idxd_desc *desc, *n;
229213

230-
*processed = 0;
231-
232214
/*
233215
* This lock protects list corruption from access of list outside of the irq handler
234216
* thread.
235217
*/
236218
spin_lock_irqsave(&irq_entry->list_lock, flags);
237219
if (list_empty(&irq_entry->work_list)) {
238220
spin_unlock_irqrestore(&irq_entry->list_lock, flags);
239-
return 0;
221+
return;
240222
}
241223

242224
list_for_each_entry_safe(desc, n, &irq_entry->work_list, list) {
243225
if (desc->completion->status) {
244226
list_del(&desc->list);
245-
(*processed)++;
246227
list_add_tail(&desc->list, &flist);
247-
} else {
248-
queued++;
249228
}
250229
}
251230

@@ -263,13 +242,11 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
263242

264243
complete_desc(desc, IDXD_COMPLETE_NORMAL);
265244
}
266-
267-
return queued;
268245
}
269246

270-
static int idxd_desc_process(struct idxd_irq_entry *irq_entry)
247+
irqreturn_t idxd_wq_thread(int irq, void *data)
271248
{
272-
int rc, processed, total = 0;
249+
struct idxd_irq_entry *irq_entry = data;
273250

274251
/*
275252
* There are two lists we are processing. The pending_llist is where
@@ -288,29 +265,9 @@ static int idxd_desc_process(struct idxd_irq_entry *irq_entry)
288265
* and process the completed entries.
289266
* 4. If the entry is still waiting on hardware, list_add_tail() to
290267
* the work_list.
291-
* 5. Repeat until no more descriptors.
292268
*/
293-
do {
294-
rc = irq_process_work_list(irq_entry, &processed, 0);
295-
total += processed;
296-
if (rc != 0)
297-
continue;
298-
299-
rc = irq_process_pending_llist(irq_entry, &processed, 0);
300-
total += processed;
301-
} while (rc != 0);
302-
303-
return total;
304-
}
305-
306-
irqreturn_t idxd_wq_thread(int irq, void *data)
307-
{
308-
struct idxd_irq_entry *irq_entry = data;
309-
int processed;
310-
311-
processed = idxd_desc_process(irq_entry);
312-
if (processed == 0)
313-
return IRQ_NONE;
269+
irq_process_work_list(irq_entry);
270+
irq_process_pending_llist(irq_entry);
314271

315272
return IRQ_HANDLED;
316273
}

0 commit comments

Comments
 (0)