Skip to content

Commit 6ffa9bd

Browse files
committed
Revert "firewire: core: move workqueue handler from 1394 OHCI driver to core function"
This reverts commit 767bfb9. It appears that the call of ohci_flush_iso_completions() in the work item scheduled by hardIRQ of 1394 OHCI for any isochronous context changes the timing to queue events in the view of user space application. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Sakamoto <[email protected]>
1 parent c45b9a0 commit 6ffa9bd

File tree

3 files changed

+64
-12
lines changed

3 files changed

+64
-12
lines changed

drivers/firewire/core-iso.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,6 @@ size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed)
131131
return 0;
132132
}
133133

134-
static void flush_completions_work(struct work_struct *work)
135-
{
136-
struct fw_iso_context *ctx = container_of(work, struct fw_iso_context, work);
137-
138-
fw_iso_context_flush_completions(ctx);
139-
}
140-
141134
struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
142135
int type, int channel, int speed, size_t header_size,
143136
fw_iso_callback_t callback, void *callback_data)
@@ -156,7 +149,6 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
156149
ctx->header_size = header_size;
157150
ctx->callback.sc = callback;
158151
ctx->callback_data = callback_data;
159-
INIT_WORK(&ctx->work, flush_completions_work);
160152

161153
trace_isoc_outbound_allocate(ctx, channel, speed);
162154
trace_isoc_inbound_single_allocate(ctx, channel, header_size);
@@ -226,15 +218,29 @@ EXPORT_SYMBOL(fw_iso_context_queue_flush);
226218
* to process the context asynchronously, fw_iso_context_schedule_flush_completions() is available
227219
* instead.
228220
*
229-
* Context: Process context.
221+
* Context: Process context. May sleep due to disable_work_sync().
230222
*/
231223
int fw_iso_context_flush_completions(struct fw_iso_context *ctx)
232224
{
225+
int err;
226+
233227
trace_isoc_outbound_flush_completions(ctx);
234228
trace_isoc_inbound_single_flush_completions(ctx);
235229
trace_isoc_inbound_multiple_flush_completions(ctx);
236230

237-
return ctx->card->driver->flush_iso_completions(ctx);
231+
might_sleep();
232+
233+
// Avoid dead lock due to programming mistake.
234+
if (WARN_ON_ONCE(current_work() == &ctx->work))
235+
return 0;
236+
237+
disable_work_sync(&ctx->work);
238+
239+
err = ctx->card->driver->flush_iso_completions(ctx);
240+
241+
enable_work(&ctx->work);
242+
243+
return err;
238244
}
239245
EXPORT_SYMBOL(fw_iso_context_flush_completions);
240246

drivers/firewire/core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count);
159159
int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
160160
enum dma_data_direction direction);
161161

162+
static inline void fw_iso_context_init_work(struct fw_iso_context *ctx, work_func_t func)
163+
{
164+
INIT_WORK(&ctx->work, func);
165+
}
166+
162167

163168
/* -topology */
164169

drivers/firewire/ohci.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,47 @@ static void context_tasklet(unsigned long data)
11821182
}
11831183
}
11841184

1185+
static void ohci_isoc_context_work(struct work_struct *work)
1186+
{
1187+
struct fw_iso_context *base = container_of(work, struct fw_iso_context, work);
1188+
struct iso_context *isoc_ctx = container_of(base, struct iso_context, base);
1189+
struct context *ctx = &isoc_ctx->context;
1190+
struct descriptor *d, *last;
1191+
u32 address;
1192+
int z;
1193+
struct descriptor_buffer *desc;
1194+
1195+
desc = list_entry(ctx->buffer_list.next, struct descriptor_buffer, list);
1196+
last = ctx->last;
1197+
while (last->branch_address != 0) {
1198+
struct descriptor_buffer *old_desc = desc;
1199+
1200+
address = le32_to_cpu(last->branch_address);
1201+
z = address & 0xf;
1202+
address &= ~0xf;
1203+
ctx->current_bus = address;
1204+
1205+
// If the branch address points to a buffer outside of the current buffer, advance
1206+
// to the next buffer.
1207+
if (address < desc->buffer_bus || address >= desc->buffer_bus + desc->used)
1208+
desc = list_entry(desc->list.next, struct descriptor_buffer, list);
1209+
d = desc->buffer + (address - desc->buffer_bus) / sizeof(*d);
1210+
last = find_branch_descriptor(d, z);
1211+
1212+
if (!ctx->callback(ctx, d, last))
1213+
break;
1214+
1215+
if (old_desc != desc) {
1216+
// If we've advanced to the next buffer, move the previous buffer to the
1217+
// free list.
1218+
old_desc->used = 0;
1219+
guard(spinlock_irqsave)(&ctx->ohci->lock);
1220+
list_move_tail(&old_desc->list, &ctx->buffer_list);
1221+
}
1222+
ctx->last = last;
1223+
}
1224+
}
1225+
11851226
/*
11861227
* Allocate a new buffer and add it to the list of free buffers for this
11871228
* context. Must be called with ohci->lock held.
@@ -3128,6 +3169,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
31283169
ret = context_init(&ctx->context, ohci, regs, callback);
31293170
if (ret < 0)
31303171
goto out_with_header;
3172+
fw_iso_context_init_work(&ctx->base, ohci_isoc_context_work);
31313173

31323174
if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) {
31333175
set_multichannel_mask(ohci, 0);
@@ -3582,8 +3624,7 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base)
35823624
int ret = 0;
35833625

35843626
if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) {
3585-
// Note that tasklet softIRQ is not used to process isochronous context anymore.
3586-
context_tasklet((unsigned long)&ctx->context);
3627+
ohci_isoc_context_work(&base->work);
35873628

35883629
switch (base->type) {
35893630
case FW_ISO_CONTEXT_TRANSMIT:

0 commit comments

Comments
 (0)