Skip to content

Commit 5a43dc9

Browse files
committed
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>
1 parent 3a86608 commit 5a43dc9

3 files changed

Lines changed: 41 additions & 16 deletions

File tree

drivers/firewire/core-card.c

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
8686
*/
8787
#define DEFAULT_SPLIT_TIMEOUT (2 * 8000)
8888

89-
#define CANON_OUI 0x000085
90-
9189
static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
9290
{
9391
struct fw_descriptor *desc;
@@ -308,11 +306,9 @@ __must_hold(&card->lock)
308306
cpu_to_be32(local_id),
309307
};
310308
bool grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125));
311-
bool irm_is_1394_1995_only = false;
312-
bool keep_this_irm = false;
313309
struct fw_node *irm_node;
314310
struct fw_device *irm_device;
315-
int irm_node_id;
311+
int irm_node_id, irm_device_quirks = 0;
316312
int rcode;
317313

318314
lockdep_assert_held(&card->lock);
@@ -328,15 +324,12 @@ __must_hold(&card->lock)
328324
return BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF;
329325
}
330326

327+
// NOTE: It is likely that the quirk detection for IRM device has not done yet.
331328
irm_device = fw_node_get_device(irm_node);
332-
if (irm_device && irm_device->config_rom) {
333-
irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0;
334-
335-
// Canon MV5i works unreliably if it is not root node.
336-
keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI;
337-
}
338-
339-
if (irm_is_1394_1995_only && !keep_this_irm) {
329+
if (irm_device)
330+
irm_device_quirks = READ_ONCE(irm_device->quirks);
331+
if ((irm_device_quirks & FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY) &&
332+
!(irm_device_quirks & FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER)) {
340333
fw_notice(card, "IRM is not 1394a compliant, making local node (%02x) root\n",
341334
local_id);
342335
return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY;
@@ -373,7 +366,7 @@ __must_hold(&card->lock)
373366
return BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM;
374367
}
375368
default:
376-
if (!keep_this_irm) {
369+
if (!(irm_device_quirks & FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER)) {
377370
fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n",
378371
fw_rcode_string(rcode), local_id);
379372
return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY;

drivers/firewire/core-device.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,21 @@ static struct device_attribute fw_device_attributes[] = {
542542
__ATTR_NULL,
543543
};
544544

545+
#define CANON_OUI 0x000085
546+
547+
static int detect_quirks_by_bus_information_block(const u32 *bus_information_block)
548+
{
549+
int quirks = 0;
550+
551+
if ((bus_information_block[2] & 0x000000f0) == 0)
552+
quirks |= FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY;
553+
554+
if ((bus_information_block[3] >> 8) == CANON_OUI)
555+
quirks |= FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER;
556+
557+
return quirks;
558+
}
559+
545560
static int read_rom(struct fw_device *device,
546561
int generation, int index, u32 *data)
547562
{
@@ -582,6 +597,7 @@ static int read_config_rom(struct fw_device *device, int generation)
582597
u32 *rom, *stack;
583598
u32 sp, key;
584599
int i, end, length, ret;
600+
int quirks;
585601

586602
rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
587603
sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL);
@@ -612,6 +628,11 @@ static int read_config_rom(struct fw_device *device, int generation)
612628
}
613629
}
614630

631+
quirks = detect_quirks_by_bus_information_block(rom);
632+
633+
// Just prevent from torn writing/reading.
634+
WRITE_ONCE(device->quirks, quirks);
635+
615636
device->max_speed = device->node->max_speed;
616637

617638
/*
@@ -1122,10 +1143,10 @@ static void fw_device_init(struct work_struct *work)
11221143
device->workfn = fw_device_shutdown;
11231144
fw_schedule_device_work(device, SHUTDOWN_DELAY);
11241145
} else {
1125-
fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
1146+
fw_notice(card, "created device %s: GUID %08x%08x, S%d00, quirks %08x\n",
11261147
dev_name(&device->device),
11271148
device->config_rom[3], device->config_rom[4],
1128-
1 << device->max_speed);
1149+
1 << device->max_speed, device->quirks);
11291150
device->config_rom_retries = 0;
11301151

11311152
set_broadcast_channel(device, device->generation);

include/linux/firewire.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ struct fw_attribute_group {
170170
struct attribute *attrs[13];
171171
};
172172

173+
enum fw_device_quirk {
174+
// See afa1282a35d3 ("firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder").
175+
FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY = BIT(0),
176+
177+
// See a509e43ff338 ("firewire: core: fix unstable I/O with Canon camcorder").
178+
FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER = BIT(1),
179+
};
180+
173181
enum fw_device_state {
174182
FW_DEVICE_INITIALIZING,
175183
FW_DEVICE_RUNNING,
@@ -203,6 +211,9 @@ struct fw_device {
203211
struct fw_card *card;
204212
struct device device;
205213

214+
// A set of enum fw_device_quirk.
215+
int quirks;
216+
206217
struct mutex client_list_mutex;
207218
struct list_head client_list;
208219

0 commit comments

Comments
 (0)