[PATCH 2/5] firewire: ohci: use workqueue to handle local AT request/response packets
From: Takashi Sakamoto
Date: Sat Sep 19 2026 - 07:50:37 EST
Local-to-local asynchronous transactions are currently handled in the
initiator's context. This requires the request handlers to support any
context in which the initiator may run.
Use workqueue to handle the AT request and response packets targeting
local address offsets, so that the request handler always runs in process
context.
Signed-off-by: Takashi Sakamoto <o-takashi@xxxxxxxxxxxxx>
---
drivers/firewire/ohci.c | 21 +++++++++------------
include/linux/firewire.h | 2 +-
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 45f03095a196..dddb08dbb45f 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -1546,7 +1546,7 @@ static bool in_bus_management_csr_registers(u64 offset)
return in_range(offset, CSR_BUS_MANAGER_ID, 0x22c - CSR_BUS_MANAGER_ID);
}
-static void handle_local_at_request_packet(struct fw_ohci *ohci, struct fw_packet *packet)
+static void handle_at_request_local_packet(struct fw_ohci *ohci, struct fw_packet *packet)
{
// Emulate split transaction.
packet->ack = ACK_PENDING;
@@ -1574,7 +1574,7 @@ static void handle_local_at_request_packet(struct fw_ohci *ohci, struct fw_packe
}
}
-static void handle_local_at_response_packet(struct fw_ohci *ohci, struct fw_packet *packet)
+static void handle_at_response_local_packet(struct fw_ohci *ohci, struct fw_packet *packet)
{
u64 csr_offset = async_header_get_offset(packet->header) - CSR_REGISTER_BASE;
@@ -1589,7 +1589,8 @@ static void handle_local_at_response_packet(struct fw_ohci *ohci, struct fw_pack
packet->callback(packet, &ohci->card, packet->ack);
}
-static void handle_at_local_packets(struct at_local *local, struct fw_ohci *ohci)
+static void handle_at_local_packets(struct at_local *local, struct fw_ohci *ohci,
+ void (*handle_at_local_packet)(struct fw_ohci *, struct fw_packet *))
{
struct fw_packet *packet;
@@ -1603,6 +1604,8 @@ static void handle_at_local_packets(struct at_local *local, struct fw_ohci *ohci
// This case is active when the call of at_context_queue_packet() returns
// error in at_context_transmit().
packet->callback(packet, &ohci->card, packet->ack);
+ } else {
+ handle_at_local_packet(ohci, packet);
}
spin_lock(&local->lock);
@@ -1616,7 +1619,7 @@ static void at_request_local_work(struct work_struct *work)
struct at_local *local = from_work(local, work, work);
struct fw_ohci *ohci = container_of(local, struct fw_ohci, at_request_local);
- handle_at_local_packets(local, ohci);
+ handle_at_local_packets(local, ohci, handle_at_request_local_packet);
}
static void at_response_local_work(struct work_struct *work)
@@ -1624,7 +1627,7 @@ static void at_response_local_work(struct work_struct *work)
struct at_local *local = from_work(local, work, work);
struct fw_ohci *ohci = container_of(local, struct fw_ohci, at_response_local);
- handle_at_local_packets(local, ohci);
+ handle_at_local_packets(local, ohci, handle_at_response_local_packet);
}
static void at_local_init(struct at_local *local, work_func_t func)
@@ -1672,13 +1675,7 @@ static void at_context_transmit(struct at_context *ctx, struct fw_packet *packet
if (destination_is_local(packet, ohci)) {
spin_unlock_irqrestore(&ohci->lock, flags);
- // Timestamping on behalf of the hardware.
- packet->timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ohci));
-
- if (ctx == &ohci->at_request_ctx)
- handle_local_at_request_packet(ohci, packet);
- else
- handle_local_at_response_packet(ohci, packet);
+ queue_work_for_at_local_packet(ctx, packet, ohci);
return;
}
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 1c71ff69c42f..2b065f03565d 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -337,7 +337,7 @@ struct fw_packet {
* For successful transmission, the status code is the ack received
* from the destination. Otherwise it is one of the juju-specific
* rcodes: RCODE_SEND_ERROR, _CANCELLED, _BUSY, _GENERATION, _NO_ACK.
- * The callback can be called from workqueue and thus must never block.
+ * The callback is called from a workqueue. It is not preferable to block it so long.
*/
fw_packet_callback_t callback;
int ack;
--
2.53.0