summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-04-12 10:35:44 +0200
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-04-19 19:58:32 +0200
commite1393667be574807a13bfaf1bb471f5fd1a5287b (patch)
tree5f2084f1a5099062cb27e74765ec3cd8a69c3489
parent2608203daf5f87311c6e5d36e5de5efcb14aab24 (diff)
firewire: ohci: wait for local CSR lock access to finish
Add a loop to wait for the controller to finish a locally-initiated CSR lock operation. Google shows some occurrences of the "swap not done yet" message which might indicate that some OHCI controllers are not fast enough to do the lock/swap in the time needed for one PCI access. This also correctly handles the case where the lock operation did not finish, instead of silently returning an uninitialized value. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/ohci.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 82fb2e7e99ef..6e95f8fb56db 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -1158,7 +1158,7 @@ static void handle_local_lock(struct fw_ohci *ohci,
struct fw_packet *packet, u32 csr)
{
struct fw_packet response;
- int tcode, length, ext_tcode, sel;
+ int tcode, length, ext_tcode, sel, try;
__be32 *payload, lock_old;
u32 lock_arg, lock_data;
@@ -1185,13 +1185,19 @@ static void handle_local_lock(struct fw_ohci *ohci,
reg_write(ohci, OHCI1394_CSRCompareData, lock_arg);
reg_write(ohci, OHCI1394_CSRControl, sel);
- if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
- lock_old = cpu_to_be32(reg_read(ohci, OHCI1394_CSRData));
- else
- fw_notify("swap not done yet\n");
+ for (try = 0; try < 20; try++)
+ if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) {
+ lock_old = cpu_to_be32(reg_read(ohci,
+ OHCI1394_CSRData));
+ fw_fill_response(&response, packet->header,
+ RCODE_COMPLETE,
+ &lock_old, sizeof(lock_old));
+ goto out;
+ }
+
+ fw_error("swap not done (CSR lock timeout)\n");
+ fw_fill_response(&response, packet->header, RCODE_BUSY, NULL, 0);
- fw_fill_response(&response, packet->header,
- RCODE_COMPLETE, &lock_old, sizeof(lock_old));
out:
fw_core_handle_response(&ohci->card, &response);
}