firewire: Make sure we wait for DMA to stop before we reprogram it.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index 58bc85d..29285f2 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -170,6 +170,8 @@
 #define OHCI1394_PCI_HCI_Control	0x40
 #define SELF_ID_BUF_SIZE		0x800
 
+#define MAX_STOP_CONTEXT_LOOPS		1000
+
 static char ohci_driver_name[] = KBUILD_MODNAME;
 
 static inline void reg_write(const struct fw_ohci *ohci, int offset, u32 data)
@@ -224,6 +226,13 @@
 	struct fw_ohci *ohci = ctx->ohci;
 	struct fw_packet p;
 	u32 status, length, tcode;
+	int i;
+
+	/* FIXME: We stop and restart the ar context here, what if we
+	 * stop while a receive is in progress? Maybe we could just
+	 * loop the context back to itself and use it in buffer fill
+	 * mode as intended... */
+	reg_write(ctx->ohci, ctx->control_clear, CONTEXT_RUN);
 
 	/* FIXME: What to do about evt_* errors? */
 	length    = le16_to_cpu(ctx->descriptor.req_count) -
@@ -287,12 +296,14 @@
 	dma_sync_single_for_device(ohci->card.device, ctx->descriptor_bus,
 				   sizeof ctx->descriptor_bus, DMA_TO_DEVICE);
 
-	/* FIXME: We stop and restart the ar context here, what if we
-	 * stop while a receive is in progress? Maybe we could just
-	 * loop the context back to itself and use it in buffer fill
-	 * mode as intended... */
+	/* Make sure the active bit is 0 before we reprogram the DMA. */
+	for (i = 0; i < MAX_STOP_CONTEXT_LOOPS; i++)
+		if (!(reg_read(ctx->ohci,
+			       ctx->control_clear) & CONTEXT_ACTIVE))
+			break;
+	if (i == MAX_STOP_CONTEXT_LOOPS)
+		fw_error("Failed to stop ar context\n");
 
-	reg_write(ctx->ohci, ctx->control_clear, CONTEXT_RUN);
 	ar_context_run(ctx);
 }