]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
firewire: ohci: use workqueue to handle events of AR request/response contexts
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Sun, 15 Jun 2025 13:32:52 +0000 (22:32 +0900)
committerTakashi Sakamoto <o-takashi@sakamocchi.jp>
Sun, 15 Jun 2025 13:40:29 +0000 (22:40 +0900)
This commit adds a work item to handle events of 1394 OHCI AR
request/response contexts, and queues the item to the specific workqueue.
The call of struct fw_address_handler.address_callback() is done in the
workqueue when receiving any requests from the remove nodes. Additionally,
the call of struct fw_packet.callback() is done in the workqueue too when
receiving acknowledge to the asynchronous packet for the response
subaction of split transaction to the remote nodes.

Link: https://lore.kernel.org/r/20250615133253.433057-3-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
drivers/firewire/core-transaction.c
drivers/firewire/ohci.c

index 2bd5deb9054ed3d148ed09650821ee4def29b8d6..d28477d84697c2152017966fab3f70cb3f8d7e66 100644 (file)
@@ -557,9 +557,10 @@ const struct fw_address_region fw_unit_space_region =
  *
  * region->start, ->end, and handler->length have to be quadlet-aligned.
  *
- * When a request is received that falls within the specified address range,
- * the specified callback is invoked.  The parameters passed to the callback
- * give the details of the particular request.
+ * When a request is received that falls within the specified address range, the specified callback
+ * is invoked.  The parameters passed to the callback give the details of the particular request.
+ * The callback is invoked in the workqueue context in most cases. However, if the request is
+ * initiated by the local node, the callback is invoked in the initiator's context.
  *
  * To be called in process context.
  * Return value:  0 on success, non-zero otherwise.
index 40313a3ec63eba59d5d133afeeb85ba424797c89..68317b5a64a745fbacc9e2f24468cb6e5df2e9b8 100644 (file)
@@ -101,7 +101,7 @@ struct ar_context {
        void *pointer;
        unsigned int last_buffer_index;
        u32 regs;
-       struct tasklet_struct tasklet;
+       struct work_struct work;
 };
 
 struct context;
@@ -1016,9 +1016,9 @@ static void ar_recycle_buffers(struct ar_context *ctx, unsigned int end_buffer)
        }
 }
 
-static void ar_context_tasklet(unsigned long data)
+static void ohci_ar_context_work(struct work_struct *work)
 {
-       struct ar_context *ctx = (struct ar_context *)data;
+       struct ar_context *ctx = from_work(ctx, work, work);
        unsigned int end_buffer_index, end_buffer_offset;
        void *p, *end;
 
@@ -1026,23 +1026,19 @@ static void ar_context_tasklet(unsigned long data)
        if (!p)
                return;
 
-       end_buffer_index = ar_search_last_active_buffer(ctx,
-                                                       &end_buffer_offset);
+       end_buffer_index = ar_search_last_active_buffer(ctx, &end_buffer_offset);
        ar_sync_buffers_for_cpu(ctx, end_buffer_index, end_buffer_offset);
        end = ctx->buffer + end_buffer_index * PAGE_SIZE + end_buffer_offset;
 
        if (end_buffer_index < ar_first_buffer_index(ctx)) {
-               /*
-                * The filled part of the overall buffer wraps around; handle
-                * all packets up to the buffer end here.  If the last packet
-                * wraps around, its tail will be visible after the buffer end
-                * because the buffer start pages are mapped there again.
-                */
+               // The filled part of the overall buffer wraps around; handle all packets up to the
+               // buffer end here.  If the last packet wraps around, its tail will be visible after
+               // the buffer end because the buffer start pages are mapped there again.
                void *buffer_end = ctx->buffer + AR_BUFFERS * PAGE_SIZE;
                p = handle_ar_packets(ctx, p, buffer_end);
                if (p < buffer_end)
                        goto error;
-               /* adjust p to point back into the actual buffer */
+               // adjust p to point back into the actual buffer
                p -= AR_BUFFERS * PAGE_SIZE;
        }
 
@@ -1057,7 +1053,6 @@ static void ar_context_tasklet(unsigned long data)
        ar_recycle_buffers(ctx, end_buffer_index);
 
        return;
-
 error:
        ctx->pointer = NULL;
 }
@@ -1073,7 +1068,7 @@ static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci,
 
        ctx->regs        = regs;
        ctx->ohci        = ohci;
-       tasklet_init(&ctx->tasklet, ar_context_tasklet, (unsigned long)ctx);
+       INIT_WORK(&ctx->work, ohci_ar_context_work);
 
        for (i = 0; i < AR_BUFFERS; i++) {
                ctx->pages[i] = dma_alloc_pages(dev, PAGE_SIZE, &dma_addr,
@@ -2238,10 +2233,10 @@ static irqreturn_t irq_handler(int irq, void *data)
        }
 
        if (event & OHCI1394_RQPkt)
-               tasklet_schedule(&ohci->ar_request_ctx.tasklet);
+               queue_work(ohci->card.async_wq, &ohci->ar_request_ctx.work);
 
        if (event & OHCI1394_RSPkt)
-               tasklet_schedule(&ohci->ar_response_ctx.tasklet);
+               queue_work(ohci->card.async_wq, &ohci->ar_response_ctx.work);
 
        if (event & OHCI1394_reqTxComplete)
                tasklet_schedule(&ohci->at_request_ctx.tasklet);