Commit 10389536742cefbedecb67a5b2906f155cf3a1c3

Authored by Stefan Richter
1 parent 67a3e12b05

firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder

Per IEEE 1394 clause 8.4.2.3, a contender for the IRM role shall check
whether the current IRM complies to 1394a-2000 or later.  If not force a
compliant node (e.g. itself) to become IRM.  This was implemented in the
older ieee1394 driver but not yet in firewire-core.

An older Sony camcorder (Sony DCR-TRV25) which implements 1394-1995 IRM
but neither 1394a-2000 IRM nor BM was now found to cause an
interoperability bug:
  - Camcorder becomes root node when plugged in, hence gets IRM role.
  - firewire-core successfully contends for BM role, proceeds to perform
    gap count optimization and resets the bus.
  - Sony camcorder ignores presence of a BM (against the spec, this is
    a firmware bug), performs its idea of gap count optimization and
    resets the bus.
  - Preceding two steps are repeated endlessly, bus never settles,
    regular I/O is practically impossible.
http://thread.gmane.org/gmane.linux.kernel.firewire.user/3913

This is an interoperability regression from the old to the new drivers.
Fix it indirectly by adding the 1394a IRM check.  The spec suggests
three and a half methods to determine 1394a compliance of a remote IRM;
we choose the method of testing the Config_ROM.Bus_Info.generation
field.  This is data that firewire-core should have readily available at
this point, i.e. does not require extra I/O.

Reported-by: Clemens Ladisch <clemens@ladisch.de> (missing 1394a check)
Reported-by: H. S. <hs.samix@gmail.com> (issue with Sony DCR-TRV25)
Tested-by: H. S. <hs.samix@gmail.com>

Cc: <stable@kernel.org> # .32.x and newer

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

Showing 1 changed file with 19 additions and 5 deletions Side-by-side Diff

drivers/firewire/core-card.c
... ... @@ -231,7 +231,7 @@
231 231 static void fw_card_bm_work(struct work_struct *work)
232 232 {
233 233 struct fw_card *card = container_of(work, struct fw_card, work.work);
234   - struct fw_device *root_device;
  234 + struct fw_device *root_device, *irm_device;
235 235 struct fw_node *root_node;
236 236 unsigned long flags;
237 237 int root_id, new_root_id, irm_id, local_id;
... ... @@ -239,6 +239,7 @@
239 239 bool do_reset = false;
240 240 bool root_device_is_running;
241 241 bool root_device_is_cmc;
  242 + bool irm_is_1394_1995_only;
242 243  
243 244 spin_lock_irqsave(&card->lock, flags);
244 245  
245 246  
... ... @@ -248,12 +249,18 @@
248 249 }
249 250  
250 251 generation = card->generation;
  252 +
251 253 root_node = card->root_node;
252 254 fw_node_get(root_node);
253 255 root_device = root_node->data;
254 256 root_device_is_running = root_device &&
255 257 atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
256 258 root_device_is_cmc = root_device && root_device->cmc;
  259 +
  260 + irm_device = card->irm_node->data;
  261 + irm_is_1394_1995_only = irm_device && irm_device->config_rom &&
  262 + (irm_device->config_rom[2] & 0x000000f0) == 0;
  263 +
257 264 root_id = root_node->node_id;
258 265 irm_id = card->irm_node->node_id;
259 266 local_id = card->local_node->node_id;
260 267  
... ... @@ -276,11 +283,18 @@
276 283  
277 284 if (!card->irm_node->link_on) {
278 285 new_root_id = local_id;
279   - fw_notify("IRM has link off, making local node (%02x) root.\n",
280   - new_root_id);
  286 + fw_notify("%s, making local node (%02x) root.\n",
  287 + "IRM has link off", new_root_id);
281 288 goto pick_me;
282 289 }
283 290  
  291 + if (irm_is_1394_1995_only) {
  292 + new_root_id = local_id;
  293 + fw_notify("%s, making local node (%02x) root.\n",
  294 + "IRM is not 1394a compliant", new_root_id);
  295 + goto pick_me;
  296 + }
  297 +
284 298 card->bm_transaction_data[0] = cpu_to_be32(0x3f);
285 299 card->bm_transaction_data[1] = cpu_to_be32(local_id);
286 300  
... ... @@ -316,8 +330,8 @@
316 330 * root, and thus, IRM.
317 331 */
318 332 new_root_id = local_id;
319   - fw_notify("BM lock failed, making local node (%02x) root.\n",
320   - new_root_id);
  333 + fw_notify("%s, making local node (%02x) root.\n",
  334 + "BM lock failed", new_root_id);
321 335 goto pick_me;
322 336 }
323 337 } else if (card->bm_generation != generation) {