]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
firewire: core: maintain phy packet receivers locally in cdev layer
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 15 Sep 2025 23:47:43 +0000 (08:47 +0900)
committerTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 15 Sep 2025 23:52:18 +0000 (08:52 +0900)
The list of receivers for phy packet is used only by cdev layer, while it
is maintained as a member of fw_card structure.

This commit maintains the list locally in cdev layer.

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

index b5e01a71114571913a152ae944df30c4878bc310..616abb836ef3dd25e6c66a847a243130989fe988 100644 (file)
@@ -556,7 +556,6 @@ void fw_card_initialize(struct fw_card *card,
        kref_init(&card->kref);
        init_completion(&card->done);
        INIT_LIST_HEAD(&card->transaction_list);
-       INIT_LIST_HEAD(&card->phy_receiver_list);
        spin_lock_init(&card->lock);
 
        card->local_node = NULL;
index 1be8f5eb3e17dc23f4e3f0031deb88eae2d695d5..112b33099610cf0f7d2aa583eca53f2a3fd59416 100644 (file)
@@ -47,6 +47,9 @@
 #define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW        5
 #define FW_CDEV_VERSION_EVENT_ASYNC_TSTAMP     6
 
+static DEFINE_SPINLOCK(phy_receiver_list_lock);
+static LIST_HEAD(phy_receiver_list);
+
 struct client {
        u32 version;
        struct fw_device *device;
@@ -1669,15 +1672,16 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
 static int ioctl_receive_phy_packets(struct client *client, union ioctl_arg *arg)
 {
        struct fw_cdev_receive_phy_packets *a = &arg->receive_phy_packets;
-       struct fw_card *card = client->device->card;
 
        /* Access policy: Allow this ioctl only on local nodes' device files. */
        if (!client->device->is_local)
                return -ENOSYS;
 
-       guard(spinlock_irq)(&card->lock);
+       // NOTE: This can be without irq when we can guarantee that __fw_send_request() for local
+       // destination never runs in any type of IRQ context.
+       scoped_guard(spinlock_irq, &phy_receiver_list_lock)
+               list_move_tail(&client->phy_receiver_link, &phy_receiver_list);
 
-       list_move_tail(&client->phy_receiver_link, &card->phy_receiver_list);
        client->phy_receiver_closure = a->closure;
 
        return 0;
@@ -1687,10 +1691,17 @@ void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p)
 {
        struct client *client;
 
-       guard(spinlock_irqsave)(&card->lock);
+       // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for local
+       // destination never runs in any type of IRQ context.
+       guard(spinlock_irqsave)(&phy_receiver_list_lock);
+
+       list_for_each_entry(client, &phy_receiver_list, phy_receiver_link) {
+               struct inbound_phy_packet_event *e;
+
+               if (client->device->card != card)
+                       continue;
 
-       list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) {
-               struct inbound_phy_packet_event *e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC);
+               e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC);
                if (e == NULL)
                        break;
 
@@ -1857,7 +1868,9 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
        struct client_resource *resource;
        unsigned long index;
 
-       scoped_guard(spinlock_irq, &client->device->card->lock)
+       // NOTE: This can be without irq when we can guarantee that __fw_send_request() for local
+       // destination never runs in any type of IRQ context.
+       scoped_guard(spinlock_irq, &phy_receiver_list_lock)
                list_del(&client->phy_receiver_link);
 
        scoped_guard(mutex, &client->device->client_list_mutex)
index d38c6e538e5c15f0f83e61bc324ad9db1b709732..f3260aacf730ea55c8e5645db79091bd82bb7cd7 100644 (file)
@@ -115,8 +115,6 @@ struct fw_card {
        int index;
        struct list_head link;
 
-       struct list_head phy_receiver_list;
-
        struct delayed_work br_work; /* bus reset job */
        bool br_short;