summaryrefslogtreecommitdiff
path: root/drivers/firewire/core-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/core-device.c')
-rw-r--r--drivers/firewire/core-device.c194
1 files changed, 135 insertions, 59 deletions
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 457a0da024a7..9b0080397154 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -542,8 +542,83 @@ static struct device_attribute fw_device_attributes[] = {
__ATTR_NULL,
};
-static int read_rom(struct fw_device *device,
- int generation, int index, u32 *data)
+#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;
+}
+
+struct entry_match {
+ unsigned int index;
+ u32 value;
+};
+
+static const struct entry_match motu_audio_express_matches[] = {
+ { 1, 0x030001f2 },
+ { 3, 0xd1000002 },
+ { 4, 0x8d000005 },
+ { 6, 0x120001f2 },
+ { 7, 0x13000033 },
+ { 8, 0x17104800 },
+};
+
+static const struct entry_match tascam_fw_series_matches[] = {
+ { 1, 0x0300022e },
+ { 3, 0x8d000006 },
+ { 4, 0xd1000001 },
+ { 6, 0x1200022e },
+ { 8, 0xd4000004 },
+};
+
+static int detect_quirks_by_root_directory(const u32 *root_directory, unsigned int length)
+{
+ static const struct {
+ enum fw_device_quirk quirk;
+ const struct entry_match *matches;
+ unsigned int match_count;
+ } *entry, entries[] = {
+ {
+ .quirk = FW_DEVICE_QUIRK_ACK_PACKET_WITH_INVALID_PENDING_CODE,
+ .matches = motu_audio_express_matches,
+ .match_count = ARRAY_SIZE(motu_audio_express_matches),
+ },
+ {
+ .quirk = FW_DEVICE_QUIRK_UNSTABLE_AT_S400,
+ .matches = tascam_fw_series_matches,
+ .match_count = ARRAY_SIZE(tascam_fw_series_matches),
+ },
+ };
+ int quirks = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(entries); ++i) {
+ int j;
+
+ entry = entries + i;
+ for (j = 0; j < entry->match_count; ++j) {
+ unsigned int index = entry->matches[j].index;
+ unsigned int value = entry->matches[j].value;
+
+ if ((length < index) || (root_directory[index] != value))
+ break;
+ }
+ if (j == entry->match_count)
+ quirks |= entry->quirk;
+ }
+
+ return quirks;
+}
+
+static int read_rom(struct fw_device *device, int generation, int speed, int index, u32 *data)
{
u64 offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4;
int i, rcode;
@@ -554,7 +629,7 @@ static int read_rom(struct fw_device *device,
for (i = 10; i < 100; i += 10) {
rcode = fw_run_transaction(device->card,
TCODE_READ_QUADLET_REQUEST, device->node_id,
- generation, device->max_speed, offset, data, 4);
+ generation, speed, offset, data, 4);
if (rcode != RCODE_BUSY)
break;
msleep(i);
@@ -578,10 +653,11 @@ static int read_rom(struct fw_device *device,
static int read_config_rom(struct fw_device *device, int generation)
{
struct fw_card *card = device->card;
- const u32 *old_rom, *new_rom;
- u32 *rom, *stack;
+ const u32 *new_rom, *old_rom __free(kfree) = NULL;
+ u32 *stack, *rom __free(kfree) = NULL;
u32 sp, key;
- int i, end, length, ret;
+ int i, end, length, ret, speed;
+ int quirks;
rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL);
@@ -591,13 +667,13 @@ static int read_config_rom(struct fw_device *device, int generation)
stack = &rom[MAX_CONFIG_ROM_SIZE];
memset(rom, 0, sizeof(*rom) * MAX_CONFIG_ROM_SIZE);
- device->max_speed = SCODE_100;
+ speed = SCODE_100;
/* First read the bus info block. */
for (i = 0; i < 5; i++) {
- ret = read_rom(device, generation, i, &rom[i]);
+ ret = read_rom(device, generation, speed, i, &rom[i]);
if (ret != RCODE_COMPLETE)
- goto out;
+ return ret;
/*
* As per IEEE1212 7.2, during initialization, devices can
* reply with a 0 for the first quadlet of the config
@@ -606,39 +682,14 @@ static int read_config_rom(struct fw_device *device, int generation)
* harddisk). In that case we just fail, and the
* retry mechanism will try again later.
*/
- if (i == 0 && rom[i] == 0) {
- ret = RCODE_BUSY;
- goto out;
- }
+ if (i == 0 && rom[i] == 0)
+ return RCODE_BUSY;
}
- device->max_speed = device->node->max_speed;
-
- /*
- * Determine the speed of
- * - devices with link speed less than PHY speed,
- * - devices with 1394b PHY (unless only connected to 1394a PHYs),
- * - all devices if there are 1394b repeaters.
- * Note, we cannot use the bus info block's link_spd as starting point
- * because some buggy firmwares set it lower than necessary and because
- * 1394-1995 nodes do not have the field.
- */
- if ((rom[2] & 0x7) < device->max_speed ||
- device->max_speed == SCODE_BETA ||
- card->beta_repeaters_present) {
- u32 dummy;
-
- /* for S1600 and S3200 */
- if (device->max_speed == SCODE_BETA)
- device->max_speed = card->link_speed;
+ quirks = detect_quirks_by_bus_information_block(rom);
- while (device->max_speed > SCODE_100) {
- if (read_rom(device, generation, 0, &dummy) ==
- RCODE_COMPLETE)
- break;
- device->max_speed--;
- }
- }
+ // Just prevent from torn writing/reading.
+ WRITE_ONCE(device->quirks, quirks);
/*
* Now parse the config rom. The config rom is a recursive
@@ -659,15 +710,13 @@ static int read_config_rom(struct fw_device *device, int generation)
*/
key = stack[--sp];
i = key & 0xffffff;
- if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE)) {
- ret = -ENXIO;
- goto out;
- }
+ if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE))
+ return -ENXIO;
/* Read header quadlet for the block to get the length. */
- ret = read_rom(device, generation, i, &rom[i]);
+ ret = read_rom(device, generation, speed, i, &rom[i]);
if (ret != RCODE_COMPLETE)
- goto out;
+ return ret;
end = i + (rom[i] >> 16) + 1;
if (end > MAX_CONFIG_ROM_SIZE) {
/*
@@ -689,9 +738,9 @@ static int read_config_rom(struct fw_device *device, int generation)
* it references another block, and push it in that case.
*/
for (; i < end; i++) {
- ret = read_rom(device, generation, i, &rom[i]);
+ ret = read_rom(device, generation, speed, i, &rom[i]);
if (ret != RCODE_COMPLETE)
- goto out;
+ return ret;
if ((key >> 30) != 3 || (rom[i] >> 30) < 2)
continue;
@@ -716,27 +765,54 @@ static int read_config_rom(struct fw_device *device, int generation)
length = i;
}
+ quirks |= detect_quirks_by_root_directory(rom + ROOT_DIR_OFFSET, length - ROOT_DIR_OFFSET);
+
+ // Just prevent from torn writing/reading.
+ WRITE_ONCE(device->quirks, quirks);
+
+ if (unlikely(quirks & FW_DEVICE_QUIRK_UNSTABLE_AT_S400))
+ speed = SCODE_200;
+ else
+ speed = device->node->max_speed;
+
+ // Determine the speed of
+ // - devices with link speed less than PHY speed,
+ // - devices with 1394b PHY (unless only connected to 1394a PHYs),
+ // - all devices if there are 1394b repeaters.
+ // Note, we cannot use the bus info block's link_spd as starting point because some buggy
+ // firmwares set it lower than necessary and because 1394-1995 nodes do not have the field.
+ if ((rom[2] & 0x7) < speed || speed == SCODE_BETA || card->beta_repeaters_present) {
+ u32 dummy;
+
+ // for S1600 and S3200.
+ if (speed == SCODE_BETA)
+ speed = card->link_speed;
+
+ while (speed > SCODE_100) {
+ if (read_rom(device, generation, speed, 0, &dummy) ==
+ RCODE_COMPLETE)
+ break;
+ --speed;
+ }
+ }
+
+ device->max_speed = speed;
+
old_rom = device->config_rom;
new_rom = kmemdup(rom, length * 4, GFP_KERNEL);
- if (new_rom == NULL) {
- ret = -ENOMEM;
- goto out;
- }
+ if (new_rom == NULL)
+ return -ENOMEM;
scoped_guard(rwsem_write, &fw_device_rwsem) {
device->config_rom = new_rom;
device->config_rom_length = length;
}
- kfree(old_rom);
- ret = RCODE_COMPLETE;
device->max_rec = rom[2] >> 12 & 0xf;
device->cmc = rom[2] >> 30 & 1;
device->irmc = rom[2] >> 31 & 1;
- out:
- kfree(rom);
- return ret;
+ return RCODE_COMPLETE;
}
static void fw_unit_release(struct device *dev)
@@ -1122,10 +1198,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);
@@ -1160,7 +1236,7 @@ static int reread_config_rom(struct fw_device *device, int generation,
int i, rcode;
for (i = 0; i < 6; i++) {
- rcode = read_rom(device, generation, i, &q);
+ rcode = read_rom(device, generation, device->max_speed, i, &q);
if (rcode != RCODE_COMPLETE)
return rcode;