diff options
| -rw-r--r-- | drivers/firewire/core-card.c | 21 | ||||
| -rw-r--r-- | drivers/firewire/core-device.c | 25 | ||||
| -rw-r--r-- | include/linux/firewire.h | 11 |
3 files changed, 41 insertions, 16 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index e5e0174a0335..6979d6a88ae2 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -86,8 +86,6 @@ static size_t config_rom_length = 1 + 4 + 1 + 1; */ #define DEFAULT_SPLIT_TIMEOUT (2 * 8000) -#define CANON_OUI 0x000085 - static void generate_config_rom(struct fw_card *card, __be32 *config_rom) { struct fw_descriptor *desc; @@ -308,11 +306,9 @@ __must_hold(&card->lock) cpu_to_be32(local_id), }; bool grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125)); - bool irm_is_1394_1995_only = false; - bool keep_this_irm = false; struct fw_node *irm_node; struct fw_device *irm_device; - int irm_node_id; + int irm_node_id, irm_device_quirks = 0; int rcode; lockdep_assert_held(&card->lock); @@ -328,15 +324,12 @@ __must_hold(&card->lock) return BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF; } + // NOTE: It is likely that the quirk detection for IRM device has not done yet. irm_device = fw_node_get_device(irm_node); - if (irm_device && irm_device->config_rom) { - irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0; - - // Canon MV5i works unreliably if it is not root node. - keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI; - } - - if (irm_is_1394_1995_only && !keep_this_irm) { + if (irm_device) + irm_device_quirks = READ_ONCE(irm_device->quirks); + if ((irm_device_quirks & FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY) && + !(irm_device_quirks & FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER)) { fw_notice(card, "IRM is not 1394a compliant, making local node (%02x) root\n", local_id); return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY; @@ -373,7 +366,7 @@ __must_hold(&card->lock) return BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM; } default: - if (!keep_this_irm) { + if (!(irm_device_quirks & FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER)) { fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n", fw_rcode_string(rcode), local_id); return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY; 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); diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 6d208769d456..161829cfcc00 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -170,6 +170,14 @@ struct fw_attribute_group { struct attribute *attrs[13]; }; +enum fw_device_quirk { + // See afa1282a35d3 ("firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder"). + FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY = BIT(0), + + // See a509e43ff338 ("firewire: core: fix unstable I/O with Canon camcorder"). + FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER = BIT(1), +}; + enum fw_device_state { FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING, @@ -203,6 +211,9 @@ struct fw_device { struct fw_card *card; struct device device; + // A set of enum fw_device_quirk. + int quirks; + struct mutex client_list_mutex; struct list_head client_list; |
