diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-03-20 18:48:23 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-04-18 11:55:36 -0400 |
commit | 2a0a2590498be7b92e3e76409c9b8ee722e23c8f (patch) | |
tree | 4e98255596b8f7bdbd2fc200e5a72a3866544583 /drivers | |
parent | e09770db0fa33baf8df21fbc18aa24a080330c3f (diff) |
firewire: wait until PHY configuration packet was transmitted (fix bus reset loop)
We now exit fw_send_phy_config /after/ the PHY config packet has been
transmitted, instead of before. A subsequent fw_core_initiate_bus_reset
will therefore not overlap with the transmission. This is meant to make
the send PHY config packet + reset bus routine more deterministic.
Fixes bus reset loop and eventual panic with
- VIA VT6307 + IOGEAR hub + Unibrain Fire-i camera
http://bugzilla.kernel.org/show_bug.cgi?id=10128
- JMicron card
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/fw-transaction.c | 51 |
1 files changed, 25 insertions, 26 deletions
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 3682e75a09e1..051be78deaba 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/completion.h> | ||
21 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
23 | #include <linux/init.h> | 24 | #include <linux/init.h> |
@@ -294,42 +295,40 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
294 | } | 295 | } |
295 | EXPORT_SYMBOL(fw_send_request); | 296 | EXPORT_SYMBOL(fw_send_request); |
296 | 297 | ||
298 | struct fw_phy_packet { | ||
299 | struct fw_packet packet; | ||
300 | struct completion done; | ||
301 | }; | ||
302 | |||
297 | static void | 303 | static void |
298 | transmit_phy_packet_callback(struct fw_packet *packet, | 304 | transmit_phy_packet_callback(struct fw_packet *packet, |
299 | struct fw_card *card, int status) | 305 | struct fw_card *card, int status) |
300 | { | 306 | { |
301 | kfree(packet); | 307 | struct fw_phy_packet *p = |
302 | } | 308 | container_of(packet, struct fw_phy_packet, packet); |
303 | |||
304 | static void send_phy_packet(struct fw_card *card, u32 data, int generation) | ||
305 | { | ||
306 | struct fw_packet *packet; | ||
307 | 309 | ||
308 | packet = kzalloc(sizeof(*packet), GFP_ATOMIC); | 310 | complete(&p->done); |
309 | if (packet == NULL) | ||
310 | return; | ||
311 | |||
312 | packet->header[0] = data; | ||
313 | packet->header[1] = ~data; | ||
314 | packet->header_length = 8; | ||
315 | packet->payload_length = 0; | ||
316 | packet->speed = SCODE_100; | ||
317 | packet->generation = generation; | ||
318 | packet->callback = transmit_phy_packet_callback; | ||
319 | |||
320 | card->driver->send_request(card, packet); | ||
321 | } | 311 | } |
322 | 312 | ||
323 | void fw_send_phy_config(struct fw_card *card, | 313 | void fw_send_phy_config(struct fw_card *card, |
324 | int node_id, int generation, int gap_count) | 314 | int node_id, int generation, int gap_count) |
325 | { | 315 | { |
326 | u32 q; | 316 | struct fw_phy_packet p; |
327 | 317 | u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | | |
328 | q = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | | 318 | PHY_CONFIG_ROOT_ID(node_id) | |
329 | PHY_CONFIG_ROOT_ID(node_id) | | 319 | PHY_CONFIG_GAP_COUNT(gap_count); |
330 | PHY_CONFIG_GAP_COUNT(gap_count); | 320 | |
331 | 321 | p.packet.header[0] = data; | |
332 | send_phy_packet(card, q, generation); | 322 | p.packet.header[1] = ~data; |
323 | p.packet.header_length = 8; | ||
324 | p.packet.payload_length = 0; | ||
325 | p.packet.speed = SCODE_100; | ||
326 | p.packet.generation = generation; | ||
327 | p.packet.callback = transmit_phy_packet_callback; | ||
328 | init_completion(&p.done); | ||
329 | |||
330 | card->driver->send_request(card, &p.packet); | ||
331 | wait_for_completion(&p.done); | ||
333 | } | 332 | } |
334 | 333 | ||
335 | void fw_flush_transactions(struct fw_card *card) | 334 | void fw_flush_transactions(struct fw_card *card) |