* [PATCH] firewire: core: use release/acquire pair when replacing underlying driver on card removal
@ 2026-10-17 8:17 Takashi Sakamoto
2026-10-18 0:39 ` Takashi Sakamoto
0 siblings, 1 reply; 2+ messages in thread
From: Takashi Sakamoto @ 2026-10-17 8:17 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel
When removing a card instance, the underlying driver is replaced to handle
closing operations. Without proper memory reordering, other CPUs may
observe the driver before it is fully initialized.
Use a release/acquire pair to ensure that the driver's initialization is
visible before the driver is accessed for close operations.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-card.c | 16 ++++++++-------
drivers/firewire/core-cdev.c | 2 +-
drivers/firewire/core-device.c | 8 ++++----
drivers/firewire/core-iso.c | 32 +++++++++++++++++++++--------
drivers/firewire/core-transaction.c | 20 +++++++++---------
5 files changed, 47 insertions(+), 31 deletions(-)
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index be6f18d67ece..83c29a487d86 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -153,8 +153,8 @@ static void update_config_roms(void)
list_for_each_entry (card, &card_list, link) {
generate_config_rom(card, tmp_config_rom);
- card->driver->set_config_rom(card, tmp_config_rom,
- config_rom_length);
+ smp_load_acquire(&card->driver)->set_config_rom(card, tmp_config_rom,
+ config_rom_length);
}
}
@@ -231,7 +231,7 @@ static int reset_bus(struct fw_card *card, bool short_reset)
trace_bus_reset_initiate(card->index, card->generation, short_reset);
- return card->driver->update_phy_reg(card, reg, 0, bit);
+ return smp_load_acquire(&card->driver)->update_phy_reg(card, reg, 0, bit);
}
void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset)
@@ -660,7 +660,8 @@ int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid,
scoped_guard(mutex, &card_mutex) {
generate_config_rom(card, tmp_config_rom);
- ret = card->driver->enable(card, tmp_config_rom, config_rom_length);
+ ret = smp_load_acquire(&card->driver)->enable(card, tmp_config_rom,
+ config_rom_length);
if (ret < 0) {
card->isoc_wq = NULL;
card->async_wq = NULL;
@@ -804,7 +805,8 @@ void fw_core_remove_card(struct fw_card *card)
dummy_driver.free_iso_context = card->driver->free_iso_context;
dummy_driver.stop_iso = card->driver->stop_iso;
dummy_driver.disable = card->driver->disable;
- card->driver = &dummy_driver;
+ // Ensure the entire contents of the driver are visible to other CPUs.
+ smp_store_release(&card->driver, &dummy_driver);
drain_workqueue(card->isoc_wq);
drain_workqueue(card->async_wq);
@@ -843,12 +845,12 @@ EXPORT_SYMBOL(fw_core_remove_card);
*/
int fw_card_read_cycle_time(struct fw_card *card, u32 *cycle_time)
{
- if (card->driver->read_csr == dummy_read_csr)
+ if (smp_load_acquire(&card->driver)->read_csr == dummy_read_csr)
return -ENODEV;
// It's possible to switch to dummy driver between the above and the below. This is the best
// effort to return -ENODEV.
- *cycle_time = card->driver->read_csr(card, CSR_CYCLE_TIME);
+ *cycle_time = smp_load_acquire(&card->driver)->read_csr(card, CSR_CYCLE_TIME);
return 0;
}
EXPORT_SYMBOL_GPL(fw_card_read_cycle_time);
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 60067c5b1973..87efd65e6b00 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -1731,7 +1731,7 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
trace_async_phy_outbound_initiate((uintptr_t)&e->p, card->index, e->p.generation,
e->p.header[1], e->p.header[2]);
- card->driver->send_request(card, &e->p);
+ smp_load_acquire(&card->driver)->send_request(card, &e->p);
return 0;
}
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 4e79c57263ff..a68100d3da0b 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -261,14 +261,14 @@ EXPORT_SYMBOL(fw_bus_type);
int fw_device_enable_phys_dma(struct fw_device *device)
{
- int generation = device->generation;
+ struct fw_card *card = device->card;
/* device->node_id, accessed below, must not be older than generation */
+ int generation = device->generation;
smp_rmb();
+ int node_id = device->node_id;
- return device->card->driver->enable_phys_dma(device->card,
- device->node_id,
- generation);
+ return smp_load_acquire(&card->driver)->enable_phys_dma(device->card, node_id, generation);
}
EXPORT_SYMBOL(fw_device_enable_phys_dma);
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c
index d2b40a1a565e..fd6cbbf79d0b 100644
--- a/drivers/firewire/core-iso.c
+++ b/drivers/firewire/core-iso.c
@@ -144,8 +144,8 @@ struct fw_iso_context *__fw_iso_context_create(struct fw_card *card, int type, i
{
struct fw_iso_context *ctx;
- ctx = card->driver->allocate_iso_context(card, type, channel, header_size,
- header_storage_size);
+ ctx = smp_load_acquire(&card->driver)->allocate_iso_context(card, type, channel,
+ header_size, header_storage_size);
if (IS_ERR(ctx))
return ctx;
@@ -173,7 +173,9 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx)
trace_isoc_inbound_single_destroy(ctx);
trace_isoc_inbound_multiple_destroy(ctx);
- ctx->card->driver->free_iso_context(ctx);
+ struct fw_card *card = ctx->card;
+
+ smp_load_acquire(&card->driver)->free_iso_context(ctx);
}
EXPORT_SYMBOL(fw_iso_context_destroy);
@@ -184,7 +186,9 @@ int fw_iso_context_start(struct fw_iso_context *ctx,
trace_isoc_inbound_single_start(ctx, cycle, sync, tags);
trace_isoc_inbound_multiple_start(ctx, cycle, sync, tags);
- return ctx->card->driver->start_iso(ctx, cycle, sync, tags);
+ struct fw_card *card = ctx->card;
+
+ return smp_load_acquire(&card->driver)->start_iso(ctx, cycle, sync, tags);
}
EXPORT_SYMBOL(fw_iso_context_start);
@@ -192,7 +196,9 @@ int fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels)
{
trace_isoc_inbound_multiple_channels(ctx, *channels);
- return ctx->card->driver->set_iso_channels(ctx, channels);
+ struct fw_card *card = ctx->card;
+
+ return smp_load_acquire(&card->driver)->set_iso_channels(ctx, channels);
}
int fw_iso_context_queue(struct fw_iso_context *ctx,
@@ -204,7 +210,9 @@ int fw_iso_context_queue(struct fw_iso_context *ctx,
trace_isoc_inbound_single_queue(ctx, payload, packet);
trace_isoc_inbound_multiple_queue(ctx, payload, packet);
- return ctx->card->driver->queue_iso(ctx, packet, buffer, payload);
+ struct fw_card *card = ctx->card;
+
+ return smp_load_acquire(&card->driver)->queue_iso(ctx, packet, buffer, payload);
}
EXPORT_SYMBOL(fw_iso_context_queue);
@@ -214,7 +222,9 @@ void fw_iso_context_queue_flush(struct fw_iso_context *ctx)
trace_isoc_inbound_single_flush(ctx);
trace_isoc_inbound_multiple_flush(ctx);
- ctx->card->driver->flush_queue_iso(ctx);
+ struct fw_card *card = ctx->card;
+
+ smp_load_acquire(&card->driver)->flush_queue_iso(ctx);
}
EXPORT_SYMBOL(fw_iso_context_queue_flush);
@@ -248,7 +258,9 @@ int fw_iso_context_flush_completions(struct fw_iso_context *ctx)
disable_work_sync(&ctx->work);
- err = ctx->card->driver->flush_iso_completions(ctx);
+ struct fw_card *card = ctx->card;
+
+ err = smp_load_acquire(&card->driver)->flush_iso_completions(ctx);
enable_work(&ctx->work);
@@ -270,7 +282,9 @@ int fw_iso_context_stop(struct fw_iso_context *ctx)
if (WARN_ON_ONCE(current_work() == &ctx->work))
return 0;
- err = ctx->card->driver->stop_iso(ctx);
+ struct fw_card *card = ctx->card;
+
+ err = smp_load_acquire(&card->driver)->stop_iso(ctx);
cancel_work_sync(&ctx->work);
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 48558857e726..c2050b23b7eb 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -129,7 +129,7 @@ __must_not_hold(&card->transactions.lock)
// Cancel the packet transmission if it's still queued. That will schedule the packet
// transmission callback which cancels the transaction.
- if (card->driver->cancel_packet(card, &transaction->packet) == 0)
+ if (smp_load_acquire(&card->driver)->cancel_packet(card, &transaction->packet) == 0)
return 0;
// If the request packet has already been sent, we need to see if the transaction is still
@@ -458,7 +458,7 @@ __must_not_hold(&card->transactions.lock)
t->packet.header, payload,
tcode_is_read_request(tcode) ? 0 : length / 4);
- card->driver->send_request(card, &t->packet);
+ smp_load_acquire(&card->driver)->send_request(card, &t->packet);
}
EXPORT_SYMBOL_GPL(__fw_send_request);
@@ -555,7 +555,7 @@ void fw_send_phy_config(struct fw_card *card,
}
if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) {
- gap_count = card->driver->read_phy_reg(card, 1);
+ gap_count = smp_load_acquire(&card->driver)->read_phy_reg(card, 1);
if (gap_count < 0)
return;
@@ -578,7 +578,7 @@ void fw_send_phy_config(struct fw_card *card,
phy_config_packet.generation, phy_config_packet.header[1],
phy_config_packet.header[2]);
- card->driver->send_request(card, &phy_config_packet);
+ smp_load_acquire(&card->driver)->send_request(card, &phy_config_packet);
wait_for_completion_timeout(&phy_config_done, timeout);
}
@@ -987,7 +987,7 @@ void fw_send_response(struct fw_card *card,
request->response.header, data,
data ? data_length / 4 : 0);
- card->driver->send_response(card, &request->response);
+ smp_load_acquire(&card->driver)->send_response(card, &request->response);
}
EXPORT_SYMBOL(fw_send_response);
@@ -1238,7 +1238,7 @@ __must_not_hold(&card->transactions.lock)
* The response handler may be executed while the request handler
* is still pending. Cancel the request handler.
*/
- card->driver->cancel_packet(card, &t->packet);
+ smp_load_acquire(&card->driver)->cancel_packet(card, &t->packet);
invoke_callback(t, rcode, p->timestamp, data, data_length);
}
@@ -1357,17 +1357,17 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
case CSR_BUS_TIME:
case CSR_BUSY_TIMEOUT:
if (tcode == TCODE_READ_QUADLET_REQUEST)
- *data = cpu_to_be32(card->driver->read_csr(card, reg));
+ *data = cpu_to_be32(smp_load_acquire(&card->driver)->read_csr(card, reg));
else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
- card->driver->write_csr(card, reg, be32_to_cpu(*data));
+ smp_load_acquire(&card->driver)->write_csr(card, reg, be32_to_cpu(*data));
else
rcode = RCODE_TYPE_ERROR;
break;
case CSR_RESET_START:
if (tcode == TCODE_WRITE_QUADLET_REQUEST)
- card->driver->write_csr(card, CSR_STATE_CLEAR,
- CSR_STATE_BIT_ABDICATE);
+ smp_load_acquire(&card->driver)->write_csr(card, CSR_STATE_CLEAR,
+ CSR_STATE_BIT_ABDICATE);
else
rcode = RCODE_TYPE_ERROR;
break;
base-commit: 82d59eb7f5431771cfc6fb074b74f466cd4e3353
--
2.53.0
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] firewire: core: use release/acquire pair when replacing underlying driver on card removal
2026-10-17 8:17 [PATCH] firewire: core: use release/acquire pair when replacing underlying driver on card removal Takashi Sakamoto
@ 2026-10-18 0:39 ` Takashi Sakamoto
0 siblings, 0 replies; 2+ messages in thread
From: Takashi Sakamoto @ 2026-10-18 0:39 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel
On Sat, Oct 17, 2026 at 05:17:20PM +0900, Takashi Sakamoto wrote:
> When removing a card instance, the underlying driver is replaced to handle
> closing operations. Without proper memory reordering, other CPUs may
> observe the driver before it is fully initialized.
>
> Use a release/acquire pair to ensure that the driver's initialization is
> visible before the driver is accessed for close operations.
>
> Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
> ---
> drivers/firewire/core-card.c | 16 ++++++++-------
> drivers/firewire/core-cdev.c | 2 +-
> drivers/firewire/core-device.c | 8 ++++----
> drivers/firewire/core-iso.c | 32 +++++++++++++++++++++--------
> drivers/firewire/core-transaction.c | 20 +++++++++---------
> 5 files changed, 47 insertions(+), 31 deletions(-)
Applied to for-next branch.
Regards
Takashi Sakamoto
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-18 0:39 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-17 8:17 [PATCH] firewire: core: use release/acquire pair when replacing underlying driver on card removal Takashi Sakamoto
2026-10-18 0:39 ` Takashi Sakamoto
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®