Skip to content

Commit aef6bcc

Browse files
committed
firewire: ohci: use workqueue to handle events of AT request/response contexts
This commit adds a work item to handle events of 1394 OHCI AT request/response contexts, and queues the item to the specific workqueue. The call of struct fw_packet.callbaqck() is done in the workqueue when receiving acknowledgement to the asynchronous packet transferred to remote node. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Sakamoto <[email protected]>
1 parent 57e6d9f commit aef6bcc

File tree

3 files changed

+35
-20
lines changed

3 files changed

+35
-20
lines changed

drivers/firewire/net.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
10071007

10081008
spin_lock_irqsave(&dev->lock, flags);
10091009

1010-
/* If the AT tasklet already ran, we may be last user. */
1010+
/* If the AT work item already ran, we may be last user. */
10111011
free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
10121012
if (!free)
10131013
ptask->enqueued = true;
@@ -1026,7 +1026,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
10261026

10271027
spin_lock_irqsave(&dev->lock, flags);
10281028

1029-
/* If the AT tasklet already ran, we may be last user. */
1029+
/* If the AT work item already ran, we may be last user. */
10301030
free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
10311031
if (!free)
10321032
ptask->enqueued = true;

drivers/firewire/ohci.c

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ struct context {
158158

159159
descriptor_callback_t callback;
160160

161-
struct tasklet_struct tasklet;
161+
struct work_struct work;
162162
};
163163

164164
struct iso_context {
@@ -1176,9 +1176,9 @@ static void context_retire_descriptors(struct context *ctx)
11761176
}
11771177
}
11781178

1179-
static void context_tasklet(unsigned long data)
1179+
static void ohci_at_context_work(struct work_struct *work)
11801180
{
1181-
struct context *ctx = (struct context *) data;
1181+
struct context *ctx = from_work(ctx, work, work);
11821182

11831183
context_retire_descriptors(ctx);
11841184
}
@@ -1243,7 +1243,6 @@ static int context_init(struct context *ctx, struct fw_ohci *ohci,
12431243
ctx->buffer_tail = list_entry(ctx->buffer_list.next,
12441244
struct descriptor_buffer, list);
12451245

1246-
tasklet_init(&ctx->tasklet, context_tasklet, (unsigned long)ctx);
12471246
ctx->callback = callback;
12481247

12491248
/*
@@ -1524,13 +1523,17 @@ static int at_context_queue_packet(struct context *ctx,
15241523

15251524
static void at_context_flush(struct context *ctx)
15261525
{
1527-
tasklet_disable(&ctx->tasklet);
1526+
// Avoid dead lock due to programming mistake.
1527+
if (WARN_ON_ONCE(current_work() == &ctx->work))
1528+
return;
15281529

1529-
ctx->flushing = true;
1530-
context_tasklet((unsigned long)ctx);
1531-
ctx->flushing = false;
1530+
disable_work_sync(&ctx->work);
15321531

1533-
tasklet_enable(&ctx->tasklet);
1532+
WRITE_ONCE(ctx->flushing, true);
1533+
ohci_at_context_work(&ctx->work);
1534+
WRITE_ONCE(ctx->flushing, false);
1535+
1536+
enable_work(&ctx->work);
15341537
}
15351538

15361539
static int handle_at_packet(struct context *context,
@@ -1542,7 +1545,7 @@ static int handle_at_packet(struct context *context,
15421545
struct fw_ohci *ohci = context->ohci;
15431546
int evt;
15441547

1545-
if (last->transfer_status == 0 && !context->flushing)
1548+
if (last->transfer_status == 0 && !READ_ONCE(context->flushing))
15461549
/* This descriptor isn't done yet, stop iteration. */
15471550
return 0;
15481551

@@ -1576,7 +1579,7 @@ static int handle_at_packet(struct context *context,
15761579
break;
15771580

15781581
case OHCI1394_evt_missing_ack:
1579-
if (context->flushing)
1582+
if (READ_ONCE(context->flushing))
15801583
packet->ack = RCODE_GENERATION;
15811584
else {
15821585
/*
@@ -1598,7 +1601,7 @@ static int handle_at_packet(struct context *context,
15981601
break;
15991602

16001603
case OHCI1394_evt_no_status:
1601-
if (context->flushing) {
1604+
if (READ_ONCE(context->flushing)) {
16021605
packet->ack = RCODE_GENERATION;
16031606
break;
16041607
}
@@ -2239,10 +2242,10 @@ static irqreturn_t irq_handler(int irq, void *data)
22392242
queue_work(ohci->card.async_wq, &ohci->ar_response_ctx.work);
22402243

22412244
if (event & OHCI1394_reqTxComplete)
2242-
tasklet_schedule(&ohci->at_request_ctx.tasklet);
2245+
queue_work(ohci->card.async_wq, &ohci->at_request_ctx.work);
22432246

22442247
if (event & OHCI1394_respTxComplete)
2245-
tasklet_schedule(&ohci->at_response_ctx.tasklet);
2248+
queue_work(ohci->card.async_wq, &ohci->at_response_ctx.work);
22462249

22472250
if (event & OHCI1394_isochRx) {
22482251
iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
@@ -2684,7 +2687,10 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
26842687
struct driver_data *driver_data = packet->driver_data;
26852688
int ret = -ENOENT;
26862689

2687-
tasklet_disable_in_atomic(&ctx->tasklet);
2690+
// Avoid dead lock due to programming mistake.
2691+
if (WARN_ON_ONCE(current_work() == &ctx->work))
2692+
return 0;
2693+
disable_work_sync(&ctx->work);
26882694

26892695
if (packet->ack != 0)
26902696
goto out;
@@ -2703,7 +2709,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
27032709
packet->callback(packet, &ohci->card, packet->ack);
27042710
ret = 0;
27052711
out:
2706-
tasklet_enable(&ctx->tasklet);
2712+
enable_work(&ctx->work);
27072713

27082714
return ret;
27092715
}
@@ -3765,11 +3771,13 @@ static int pci_probe(struct pci_dev *dev,
37653771
OHCI1394_AsReqTrContextControlSet, handle_at_packet);
37663772
if (err < 0)
37673773
return err;
3774+
INIT_WORK(&ohci->at_request_ctx.work, ohci_at_context_work);
37683775

37693776
err = context_init(&ohci->at_response_ctx, ohci,
37703777
OHCI1394_AsRspTrContextControlSet, handle_at_packet);
37713778
if (err < 0)
37723779
return err;
3780+
INIT_WORK(&ohci->at_response_ctx.work, ohci_at_context_work);
37733781

37743782
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
37753783
ohci->ir_context_channels = ~0ULL;

include/linux/firewire.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,7 @@ struct fw_packet {
308308
* For successful transmission, the status code is the ack received
309309
* from the destination. Otherwise it is one of the juju-specific
310310
* rcodes: RCODE_SEND_ERROR, _CANCELLED, _BUSY, _GENERATION, _NO_ACK.
311-
* The callback can be called from tasklet context and thus
312-
* must never block.
311+
* The callback can be called from workqueue and thus must never block.
313312
*/
314313
fw_packet_callback_t callback;
315314
int ack;
@@ -382,6 +381,10 @@ void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode
382381
*
383382
* A variation of __fw_send_request() to generate callback for response subaction without time
384383
* stamp.
384+
*
385+
* The callback is invoked in the workqueue context in most cases. However, if an error is detected
386+
* before queueing or the destination address refers to the local node, it is invoked in the
387+
* current context instead.
385388
*/
386389
static inline void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
387390
int destination_id, int generation, int speed,
@@ -411,6 +414,10 @@ static inline void fw_send_request(struct fw_card *card, struct fw_transaction *
411414
* @callback_data: data to be passed to the transaction completion callback
412415
*
413416
* A variation of __fw_send_request() to generate callback for response subaction with time stamp.
417+
*
418+
* The callback is invoked in the workqueue context in most cases. However, if an error is detected
419+
* before queueing or the destination address refers to the local node, it is invoked in the current
420+
* context instead.
414421
*/
415422
static inline void fw_send_request_with_tstamp(struct fw_card *card, struct fw_transaction *t,
416423
int tcode, int destination_id, int generation, int speed, unsigned long long offset,

0 commit comments

Comments
 (0)