Posts
127
Following
28
Followers
27
A maintainer of Linux FireWire subsystem and ALSA firewire stack.
http://ieee1394.docs.kernel.org/
https://github.com/takaswie/linux-firewire-dkms/

Takashi Sakamoto (坂本 貴史)

Or retrieve buffer from descriptor list?
0
0
0

Takashi Sakamoto (坂本 貴史)

Hm.

$ git show
commit ba003f0c08ead39934425cb3a70e0e8f83ed7a5b (HEAD -> topic/cdev/iso-resource-once-rework)
Author: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Date:   Mon Aug 24 23:12:18 2026 +0900

    firewire: ohci: don't handle AT request/response packets in caller's context
    
    It is inconvenient to handle AT request/response packets in the context of
    __fw_send_request() call, since it could be any type of IRQ contexts. In
    the case, the address handler implementation should take care of the lock
    type.

diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index e947227e..1195eab1 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -1535,11 +1535,23 @@ static void handle_local_lock(struct fw_ohci *ohci,
        fw_core_handle_response(&ohci->card, &response);
 }
 
-static void handle_local_request(struct at_context *ctx, struct fw_packet *packet)
+struct local_at_packet {
+       struct work_struct work;
+       struct at_context *ctx;
+       struct fw_packet *p;
+};
+
+static void local_at_run(struct work_struct *work)
 {
+       struct local_at_packet *local_packet = from_work(local_packet, work, work);
+       struct fw_packet *packet = local_packet->p;
+       struct at_context *ctx = local_packet->ctx;
        struct fw_ohci *ohci = ctx->context.ohci;
        u64 offset, csr;
 
+       // Timestamping on behalf of the hardware.
+       packet->timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ohci));
+
        if (ctx == &ohci->at_request_ctx) {
                packet->ack = ACK_PENDING;
                packet->callback(packet, &ohci->card, packet->ack);
@@ -1570,6 +1582,8 @@ static void handle_local_request(struct at_context *ctx, struct fw_packet *packe
                packet->ack = ACK_COMPLETE;
                packet->callback(packet, &ohci->card, packet->ack);
        }
+
+       kfree(local_packet);
 }
 
 static void at_context_transmit(struct at_context *ctx, struct fw_packet *packet)
@@ -1584,10 +1598,18 @@ static void at_context_transmit(struct at_context *ctx, struct fw_packet *packet
            ohci->generation == packet->generation) {
                spin_unlock_irqrestore(&ohci->lock, flags);
 
-               // Timestamping on behalf of the hardware.
-               packet->timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ohci));
+               struct local_at_packet *local_packet = kmalloc_obj(*local_packet);
+
+               // TODO:
+               if (!local_packet)
+                       return;
+
+               INIT_WORK(&local_packet->work, local_at_run);
+               local_packet->ctx = ctx;
+               local_packet->p = packet;
+
+               queue_work(ohci->card.async_wq, &local_packet->work);
 
-               handle_local_request(ctx, packet);
                return;
        }
 
0
0
0

Takashi Sakamoto (坂本 貴史)

I sent:

[GIT PULL] firewire updates for v7.3
https://lore.kernel.org/lkml/20260822051606.GA299935@sakamocchi.jp
0
0
0

Takashi Sakamoto (坂本 貴史)

I realized to write stub functions for KUnit tests. Great!

diff --git a/drivers/firewire/.kunitconfig b/drivers/firewire/.kunitconfig
index 7406acb00478..4f58bbb2ac5a 100644
--- a/drivers/firewire/.kunitconfig
+++ b/drivers/firewire/.kunitconfig
@@ -7,3 +7,4 @@ CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST=y
 CONFIG_FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST=y
 CONFIG_FIREWIRE_KUNIT_OHCI_SERDES_TEST=y
 CONFIG_FIREWIRE_KUNIT_NODE_TREE_TEST=y
+CONFIG_FIREWIRE_KUNIT_CONFIG_ROM_READER_TEST=y
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index b5abe00accc9..ccdaa0920bf6 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -96,6 +96,21 @@ config FIREWIRE_KUNIT_NODE_TREE_TEST
 	  For more information on KUnit and unit tests in general, refer
 	  to the KUnit documentation in Documentation/dev-tools/kunit/.
 
+config FIREWIRE_KUNIT_CONFIG_ROM_READER_TEST
+	tristate "KUnit tests for node tree" if !KUNIT_ALL_TESTS
+	depends on FIREWIRE && KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  This builds the KUnit tests for configuration ROM reader.
+
+	  KUnit tests run during boot and output the results to the debug
+	  log in TAP format (https://testanything.org/). Only useful for
+	  kernel devs running KUnit test harness and are not for inclusion
+	  into a production build.
+
+	  For more information on KUnit and unit tests in general, refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
 config FIREWIRE_OHCI
 	tristate "OHCI-1394 controllers"
 	depends on PCI && FIREWIRE
diff --git a/drivers/firewire/configuration-rom-reader-test.c b/drivers/firewire/configuration-rom-reader-test.c
new file mode 100644
index 000000000000..953d65edd717
--- /dev/null
+++ b/drivers/firewire/configuration-rom-reader-test.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// configuration-rom-reader-test.c - An application of Kunit to test configuration ROM reader.
+//
+// Copyright (c) 2026 Takashi Sakamoto
+//
+// This file can not be built independently since it is intentionally included in core-device.c.
+
+#include <kunit/test.h>
+#include <kunit/static_stub.h>
+
+static int stub_fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
+				   int generation, int speed, unsigned long long offset,
+				   void *payload, size_t length)
+{
+	return RCODE_CONFLICT_ERROR;
+}
+
+static void config_rom_reader_test(struct kunit *test)
+{
+	kunit_activate_static_stub(test, fw_run_transaction, stub_fw_run_transaction);
+
+	struct fw_device device;
+	int generation = 0;
+	int speed = SCODE_100;
+	int index = 0;
+	u32 data;
+	int err;
+
+	err = read_rom(&device, generation, speed, index, &data);
+	KUNIT_EXPECT_EQ(test, err, RCODE_CONFLICT_ERROR);
+
+	kunit_deactivate_static_stub(test, fw_run_transaction);
+}
+
+static struct kunit_case config_rom_reader_test_cases[] = {
+	{}
+};
+
+static struct kunit_suite config_rom_reader_test_suite = {
+	.name = "firewire-configuration-rom-reader",
+	.test_cases = config_rom_reader_test_cases,
+};
+kunit_test_suite(config_rom_reader_test_suite);
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index cbac66916240..3472b44a8501 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -1442,3 +1442,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
 #ifdef CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST
 #include "device-attribute-test.c"
 #endif
+
+#ifdef CONFIG_FIREWIRE_KUNIT_CONFIG_ROM_READER_TEST
+#include "configuration-rom-reader-test.c"
+#endif
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 22ae387ae03c..2162e1daa447 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -24,6 +24,7 @@
 #include <linux/timer.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <kunit/static_stub.h>
 
 #include <asm/byteorder.h>
 
@@ -481,6 +482,9 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
 		       int generation, int speed, unsigned long long offset,
 		       void *payload, size_t length)
 {
+        KUNIT_STATIC_STUB_REDIRECT(fw_run_transaction, card, tcode, destination_id, generation,
+				   speed, offset, payload, length);
+
 	struct transaction_callback_data d;
 	struct fw_transaction t;
 
0
0
1

Takashi Sakamoto (坂本 貴史)

Edited 11 days ago
He found the way to operate with BeBoB console for M-Audio FW 1814, surprising!

https://bsky.app/profile/mrmidi.bsky.social/post/3mtc23zcaj222
1
0
0

Takashi Sakamoto (坂本 貴史)

I'm waiting for v3 patchset. It would be posted after -rc1 release:

[PATCH v2 00/17] mod_devicetable.h: Split into per subsystem headers
https://lore.kernel.org/lkml/cover.1782490566.git.u.kleine-koenig@baylibre.com/
1
0
1

Takashi Sakamoto (坂本 貴史)

Edited 3 months ago
Re: [PATCH] list: Add safe entry iterators without an explicit n cursor
https://lore.kernel.org/lkml/2B3BFA1E-08B8-42AB-87D6-A28BF15E5C58@linux.dev/

I've realized but not fix yet...:
https://social.kernel.org/notice/AyDqvLkpwUvI5eyokK
0
0
0

Takashi Sakamoto (坂本 貴史)

Edited 4 months ago
The pair of client_get() and queue_delayed_work() is called in queue_bus_reset_event() just for iso_resource_auto, so it is a simple solution to split iso_resource_once, then take care of the workqueue cancellation.
0
0
0

Takashi Sakamoto (坂本 貴史)

Edited 4 months ago
static void iso_resource_auto_work(struct work_struct *work)
{
        struct iso_resource_auto *r = from_work(r, work, work.work);
        struct client *client = r->client;
        unsigned long index = r->resource.handle;
        u64 reset_jiffies;
        struct iso_resource_event *e;
        int resource_generation, current_generation;
        int channel, bandwidth, todo;
        bool free = false;

        scoped_guard(spinlock_irq, &client->device->card->lock) {
                reset_jiffies = client->device->card->reset_jiffies;
                current_generation = client->device->generation;
        }

        scoped_guard(spinlock_irq, &client->lock) {
                resource_generation = r->generation;
                r->generation = current_generation;
                todo = r->todo;
        }

        switch (todo) {
        case ISO_RES_AUTO_ALLOC:
                // Allow 1000ms grace period for other reallocations.
                if (time_is_after_jiffies64(reset_jiffies + secs_to_jiffies(1))) {
                        scoped_guard(spinlock_irq, &client->lock)
                                schedule_iso_resource_auto(r, msecs_to_jiffies(333));
                        goto out;
                }
                break;
        case ISO_RES_AUTO_REALLOC:
                // We could be called twice within the same generation.
                if (resource_generation == current_generation)
                        goto out;
                break;
        case ISO_RES_AUTO_DEALLOC:
        default:
                break;
        }

        bandwidth = r->bandwidth;

        fw_iso_resource_manage(client->device->card, current_generation,
                        r->channels, &channel, &bandwidth,
                        todo == ISO_RES_AUTO_ALLOC ||
                        todo == ISO_RES_AUTO_REALLOC);

        if (todo == ISO_RES_AUTO_DEALLOC) {
                e = no_free_ptr(r->e_dealloc);
        } else {
                // Is this generation outdated already?  As long as this resource sticks in the
                // xarray, it will be scheduled again for a newer generation or at shutdown.
                if (channel == -EAGAIN)
                        goto out;

                // Finishes successfully.
                if (channel >= 0 || bandwidth > 0) {
                        // Generate no event at reallocation.
                        if (todo == ISO_RES_AUTO_REALLOC)
                                goto out;

                        scoped_guard(spinlock_irq, &client->lock) {
                                // Transit from allocation to reallocation, except if the client
                                // requested deallocation in the meantime.
                                r->todo = ISO_RES_AUTO_REALLOC;
                                r->channels = 1ULL << channel;
                        }
                } else {
                        // Allocation or reallocation failure?  Pull this resource out of the
                        // xarray and prepare for deletion, unless the client is shutting down.
                        scoped_guard(spinlock_irq, &client->lock) {
                                if (!client->in_shutdown && xa_erase(&client->resource_xa, index)) {
                                        client_put(client);
                                        free = true;
                                }
                        }
                }

                e = no_free_ptr(r->e_alloc);
        }

        e->iso_resource.handle    = r->resource.handle;
        e->iso_resource.channel   = channel;
        e->iso_resource.bandwidth = bandwidth;

        queue_event(client, &e->event,
                    &e->iso_resource, sizeof(e->iso_resource), NULL, 0);

        if (free) {
                cancel_delayed_work(&r->work);
                kfree(r->e_alloc);
                kfree(r->e_dealloc);
                kfree(r);
        }
 out:
        client_put(client);
}

static void iso_resource_once_work(struct work_struct *work)
{
        struct iso_resource_once *r = from_work(r, work, work.work);
        struct client *client = r->client;
        struct iso_resource_event *e;
        int generation, channel, bandwidth;

        generation = client->device->generation;

        bandwidth = r->bandwidth;
        r->generation = generation;

        fw_iso_resource_manage(client->device->card, generation, r->channels, &channel, &bandwidth,
                               r->todo == ISO_RES_ONCE_ALLOC);

        e = no_free_ptr(r->event);
        e->iso_resource.channel   = channel;
        e->iso_resource.bandwidth = bandwidth;

        queue_event(client, &e->event, &e->iso_resource, sizeof(e->iso_resource), NULL, 0);

        cancel_delayed_work(&r->work);
        client_put(r->client);
        kfree(r);
}
0
0
0

Takashi Sakamoto (坂本 貴史)

Oops, being uninitialized...

Re: firewire-ohci: 7.0.0-rc1 warnings+crash
https://lore.kernel.org/lkml/20260228031255.GA832746@workstation.local/
1
0
0

Takashi Sakamoto (坂本 貴史)

0
0
0

Takashi Sakamoto (坂本 貴史)

Re: Bug#1126090: Firewire-ohci module crashes: firewire_ohci 0000:02:00.0: failed to read phy reg 2
https://lore.kernel.org/lkml/20260205123722.GA303762@workstation.local/

Being messed up...
0
0
0

Takashi Sakamoto (坂本 貴史)

I sent:
[GIT PULL] firewire fixes for v6.19-rc8:
https://lore.kernel.org/lkml/20260130225427.GA88593@workstation.local/T/#u

firewire fixes for 6.19-rc8

Fix a race condition introduced in v6.18. Andreas Persson discovered this
issue while working with Focusrite Saffire Pro 40 (TCD33070). The fw_card
instance maintains a linked list of pending transactions, which must be
protected against concurrent access. However, a commit b5725cfa4120
("firewire: core: use spin lock specific to timer for split transaction")
unintentionally allowed concurrent accesses to this list. Fix this by
adjusting the relevant critical sections to properly serialize access.
0
0
0

Takashi Sakamoto (坂本 貴史)

I made an apparent regression, sigh...

[PATCH] firewire: core: fix race condition against transaction list
https://lore.kernel.org/lkml/20260127223413.22265-1-o-takashi@sakamocchi.jp/
0
0
0

Takashi Sakamoto (坂本 貴史)

I posted:

0
0
0

Takashi Sakamoto (坂本 貴史)

Hm:

An end to high memory?
https://lwn.net/Articles/813201/
0
0
0

Takashi Sakamoto (坂本 貴史)

0
0
0
Show older