Commit 10389536742cefbedecb67a5b2906f155cf3a1c3
1 parent
67a3e12b05
Exists in
master
and in
7 other branches
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) { |