diff options
| author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2025-10-13 23:03:10 +0900 |
|---|---|---|
| committer | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2025-10-13 23:07:24 +0900 |
| commit | 5a43dc9f4ee0a3624d0598ee14e8ef8468914525 (patch) | |
| tree | 50e392be886ed5946c5f904cb3020a25c3e162bb /drivers/firewire/core-device.c | |
| parent | 3a8660878839faadb4f1a6dd72c3179c1df56787 (diff) | |
firewire: core: detect device quirk when reading configuration ROM
Every time the bus manager runs, the cached configuration ROM content of
the IRM device is investigated to detect device-specific quirks. This
detection can be performed in advance when reading the configuration ROM.
This commit adds device quirk flags to the fw_device structure, and
initializes them after reading the bus information block of the
configuration ROM. The quirk flags are immutable once the configuration
ROM has been read. Although they are likely accessed concurrently only by
the bus manager, this commit ensures safe access by preventing torn writes
and reads using the WRITE_ONCE()/READ_ONCE() macros.
Link: https://lore.kernel.org/r/20251013140311.97159-2-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Diffstat (limited to 'drivers/firewire/core-device.c')
| -rw-r--r-- | drivers/firewire/core-device.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 457a0da024a7..9bab2d594b89 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -542,6 +542,21 @@ static struct device_attribute fw_device_attributes[] = { __ATTR_NULL, }; +#define CANON_OUI 0x000085 + +static int detect_quirks_by_bus_information_block(const u32 *bus_information_block) +{ + int quirks = 0; + + if ((bus_information_block[2] & 0x000000f0) == 0) + quirks |= FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY; + + if ((bus_information_block[3] >> 8) == CANON_OUI) + quirks |= FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER; + + return quirks; +} + static int read_rom(struct fw_device *device, int generation, int index, u32 *data) { @@ -582,6 +597,7 @@ static int read_config_rom(struct fw_device *device, int generation) u32 *rom, *stack; u32 sp, key; int i, end, length, ret; + int quirks; rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE + sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL); @@ -612,6 +628,11 @@ static int read_config_rom(struct fw_device *device, int generation) } } + quirks = detect_quirks_by_bus_information_block(rom); + + // Just prevent from torn writing/reading. + WRITE_ONCE(device->quirks, quirks); + device->max_speed = device->node->max_speed; /* @@ -1122,10 +1143,10 @@ static void fw_device_init(struct work_struct *work) device->workfn = fw_device_shutdown; fw_schedule_device_work(device, SHUTDOWN_DELAY); } else { - fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n", + fw_notice(card, "created device %s: GUID %08x%08x, S%d00, quirks %08x\n", dev_name(&device->device), device->config_rom[3], device->config_rom[4], - 1 << device->max_speed); + 1 << device->max_speed, device->quirks); device->config_rom_retries = 0; set_broadcast_channel(device, device->generation); |