diff mbox

[2/5] firewire: ohci: restart ISO channels on resume

Message ID 1290906936-14472-3-git-send-email-maximlevitsky@gmail.com
State Not Applicable, archived
Delegated to: David Miller
Headers show

Commit Message

Maxim Levitsky Nov. 28, 2010, 1:15 a.m. UTC
ISO streams are supposed to be not interrupted
on bus resets, and suspend resume can be though
as one big bus reset.

Of course users must as soon as they notice the
bus reset, revalidate the ISO channel with IRM.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/firewire/ohci.c |   49 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 48 insertions(+), 1 deletions(-)
diff mbox

Patch

diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index cadd6af..9704b34 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -40,6 +40,7 @@ 
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/time.h>
+#include <linux/bitops.h>
 
 #include <asm/byteorder.h>
 #include <asm/page.h>
@@ -167,6 +168,9 @@  struct iso_context {
 	int excess_bytes;
 	void *header;
 	size_t header_length;
+
+	u8 sync;
+	u8 tags;
 };
 
 #define CONFIG_ROM_SIZE 1024
@@ -199,8 +203,11 @@  struct fw_ohci {
 
 	u32 it_context_mask;     /* unoccupied IT contexts */
 	struct iso_context *it_context_list;
+	u32 it_active_mask;
+
 	u64 ir_context_channels; /* unoccupied channels */
 	u32 ir_context_mask;     /* unoccupied IR contexts */
+	u32 ir_active_mask;	/*running IR contexts */
 	struct iso_context *ir_context_list;
 	u64 mc_channels; /* channels in use by the multichannel IR context */
 	bool mc_allocated;
@@ -2596,6 +2603,7 @@  static int ohci_start_iso(struct fw_iso_context *base,
 
 		reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index);
 		reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index);
+		ohci->it_active_mask |= (1 << index);
 		context_run(&ctx->context, match);
 		break;
 
@@ -2613,7 +2621,12 @@  static int ohci_start_iso(struct fw_iso_context *base,
 		reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 1 << index);
 		reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index);
 		reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match);
+		ohci->ir_active_mask |= (1 << index);
 		context_run(&ctx->context, control);
+
+		ctx->sync = sync;
+		ctx->tags = tags;
+
 		break;
 	}
 
@@ -2630,12 +2643,14 @@  static int ohci_stop_iso(struct fw_iso_context *base)
 	case FW_ISO_CONTEXT_TRANSMIT:
 		index = ctx - ohci->it_context_list;
 		reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index);
+		ohci->it_active_mask &= ~(1 << index);
 		break;
 
 	case FW_ISO_CONTEXT_RECEIVE:
 	case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
 		index = ctx - ohci->ir_context_list;
 		reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index);
+		ohci->ir_active_mask &= ~(1 << index);
 		break;
 	}
 	flush_writes(ohci);
@@ -2711,6 +2726,33 @@  static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels)
 	return ret;
 }
 
+static int ohci_resume_iso(struct fw_ohci *ohci)
+{
+	int i, err;
+	struct iso_context *ctx;
+
+	for_each_set_bit(i, (unsigned long *)&ohci->ir_active_mask,
+					sizeof(ohci->ir_active_mask)) {
+		ctx = &ohci->ir_context_list[i];
+		err = ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags);
+
+		if (err)
+			return err;
+	}
+
+	for_each_set_bit(i, (unsigned long *)&ohci->it_active_mask,
+					sizeof(ohci->it_active_mask)) {
+		ctx = &ohci->it_context_list[i];
+		err = ohci_start_iso(&ctx->base, 0, 0, 0);
+
+		if (err)
+			return err;
+	}
+
+
+	return 0;
+}
+
 static int queue_iso_transmit(struct iso_context *ctx,
 			      struct fw_iso_packet *packet,
 			      struct fw_iso_buffer *buffer,
@@ -3244,7 +3286,12 @@  static int pci_resume(struct pci_dev *dev)
 	reg_write(ohci, OHCI1394_GUIDLo, ohci->card.guid & 0xFFFFFFFF);
 	reg_write(ohci, OHCI1394_GUIDHi, (ohci->card.guid >> 32) & 0xFFFFFFFF);
 
-	return ohci_enable(&ohci->card, NULL, 0);
+	err = ohci_enable(&ohci->card, NULL, 0);
+
+	if (err)
+		return err;
+
+	return ohci_resume_iso(ohci);
 }
 #endif