]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
firewire: core: use mutex to coordinate concurrent calls to flush completions
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 9 Sep 2024 14:00:18 +0000 (23:00 +0900)
committerTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 9 Sep 2024 14:00:18 +0000 (23:00 +0900)
In current implementation, test_and_set_bit_lock() is used to mediate
concurrent calls of ohci_flush_iso_completions(). However, the ad-hoc
usage of atomic operations is not preferable.

This commit uses mutex_trylock() as the similar operations. The core
function is responsible for the mediation, instead of 1394 OHCI driver.

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

index 9f41c78878ade206c2060d4f53b8a3a35b55f9f8..1405d2e9cb2cab03687e04dfd4ffae079e529e38 100644 (file)
@@ -157,6 +157,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
        ctx->callback.sc = callback;
        ctx->callback_data = callback_data;
        INIT_WORK(&ctx->work, flush_completions_work);
+       mutex_init(&ctx->flushing_completions_mutex);
 
        trace_isoc_outbound_allocate(ctx, channel, speed);
        trace_isoc_inbound_single_allocate(ctx, channel, header_size);
@@ -173,6 +174,8 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx)
        trace_isoc_inbound_multiple_destroy(ctx);
 
        ctx->card->driver->free_iso_context(ctx);
+
+       mutex_destroy(&ctx->flushing_completions_mutex);
 }
 EXPORT_SYMBOL(fw_iso_context_destroy);
 
@@ -226,7 +229,7 @@ EXPORT_SYMBOL(fw_iso_context_queue_flush);
  * to process the context asynchronously, fw_iso_context_schedule_flush_completions() is available
  * instead.
  *
- * Context: Process context.
+ * Context: Process context due to mutex_trylock().
  */
 int fw_iso_context_flush_completions(struct fw_iso_context *ctx)
 {
@@ -234,7 +237,11 @@ int fw_iso_context_flush_completions(struct fw_iso_context *ctx)
        trace_isoc_inbound_single_flush_completions(ctx);
        trace_isoc_inbound_multiple_flush_completions(ctx);
 
-       return ctx->card->driver->flush_iso_completions(ctx);
+       scoped_cond_guard(mutex_try, /* nothing to do */, &ctx->flushing_completions_mutex) {
+               return ctx->card->driver->flush_iso_completions(ctx);
+       }
+
+       return 0;
 }
 EXPORT_SYMBOL(fw_iso_context_flush_completions);
 
index 02ff0363d3ad78e07527c69c97f31818cdb85f59..b182998a77f4ce55884d060aa079aa10a661362d 100644 (file)
@@ -166,7 +166,6 @@ struct iso_context {
        struct context context;
        void *header;
        size_t header_length;
-       unsigned long flushing_completions;
        u32 mc_buffer_bus;
        u16 mc_completed;
        u16 last_timestamp;
@@ -3579,31 +3578,23 @@ static void ohci_flush_queue_iso(struct fw_iso_context *base)
 static int ohci_flush_iso_completions(struct fw_iso_context *base)
 {
        struct iso_context *ctx = container_of(base, struct iso_context, base);
-       int ret = 0;
 
-       if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) {
-               // Note that tasklet softIRQ is not used to process isochronous context anymore.
-               context_tasklet((unsigned long)&ctx->context);
+       // Note that tasklet softIRQ is not used to process isochronous context anymore.
+       context_tasklet((unsigned long)&ctx->context);
 
-               switch (base->type) {
-               case FW_ISO_CONTEXT_TRANSMIT:
-               case FW_ISO_CONTEXT_RECEIVE:
-                       if (ctx->header_length != 0)
-                               flush_iso_completions(ctx, FW_ISO_CONTEXT_COMPLETIONS_CAUSE_FLUSH);
-                       break;
-               case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
-                       if (ctx->mc_completed != 0)
-                               flush_ir_buffer_fill(ctx);
-                       break;
-               default:
-                       ret = -ENOSYS;
-               }
-
-               clear_bit_unlock(0, &ctx->flushing_completions);
-               smp_mb__after_atomic();
+       switch (base->type) {
+       case FW_ISO_CONTEXT_TRANSMIT:
+       case FW_ISO_CONTEXT_RECEIVE:
+               if (ctx->header_length != 0)
+                       flush_iso_completions(ctx, FW_ISO_CONTEXT_COMPLETIONS_CAUSE_FLUSH);
+               return 0;
+       case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+               if (ctx->mc_completed != 0)
+                       flush_ir_buffer_fill(ctx);
+               return 0;
+       default:
+               return -ENOSYS;
        }
-
-       return ret;
 }
 
 static const struct fw_card_driver ohci_driver = {
index f815d12deda0315ff045f1bc58d6ef24f3bad587..19e8c5f9537c6b24eab241f9951d12991ac2a1a0 100644 (file)
@@ -512,6 +512,7 @@ union fw_iso_callback {
 struct fw_iso_context {
        struct fw_card *card;
        struct work_struct work;
+       struct mutex flushing_completions_mutex;
        int type;
        int channel;
        int speed;