Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[linux-3.10.git] / drivers / firewire / ohci.c
index a71477541dc7e300d40a9e40e667eb57dbbb5551..ae4556f0c0c14aac573610566764230d77333321 100644 (file)
@@ -275,7 +275,7 @@ static void log_irqs(u32 evt)
            !(evt & OHCI1394_busReset))
                return;
 
-       fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
+       fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
            evt & OHCI1394_selfIDComplete       ? " selfID"             : "",
            evt & OHCI1394_RQPkt                ? " AR_req"             : "",
            evt & OHCI1394_RSPkt                ? " AR_resp"            : "",
@@ -286,6 +286,7 @@ static void log_irqs(u32 evt)
            evt & OHCI1394_postedWriteErr       ? " postedWriteErr"     : "",
            evt & OHCI1394_cycleTooLong         ? " cycleTooLong"       : "",
            evt & OHCI1394_cycle64Seconds       ? " cycle64Seconds"     : "",
+           evt & OHCI1394_cycleInconsistent    ? " cycleInconsistent"  : "",
            evt & OHCI1394_regAccessFail        ? " regAccessFail"      : "",
            evt & OHCI1394_busReset             ? " busReset"           : "",
            evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
@@ -293,6 +294,7 @@ static void log_irqs(u32 evt)
                    OHCI1394_respTxComplete | OHCI1394_isochRx |
                    OHCI1394_isochTx | OHCI1394_postedWriteErr |
                    OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
+                   OHCI1394_cycleInconsistent |
                    OHCI1394_regAccessFail | OHCI1394_busReset)
                                                ? " ?"                  : "");
 }
@@ -1441,6 +1443,17 @@ static irqreturn_t irq_handler(int irq, void *data)
                          OHCI1394_LinkControl_cycleMaster);
        }
 
+       if (unlikely(event & OHCI1394_cycleInconsistent)) {
+               /*
+                * We need to clear this event bit in order to make
+                * cycleMatch isochronous I/O work.  In theory we should
+                * stop active cycleMatch iso contexts now and restart
+                * them at least two cycles later.  (FIXME?)
+                */
+               if (printk_ratelimit())
+                       fw_notify("isochronous cycle inconsistent\n");
+       }
+
        if (event & OHCI1394_cycle64Seconds) {
                cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
                if ((cycle_time & 0x80000000) == 0)
@@ -1540,6 +1553,7 @@ static int ohci_enable(struct fw_card *card,
                  OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
                  OHCI1394_isochRx | OHCI1394_isochTx |
                  OHCI1394_postedWriteErr | OHCI1394_cycleTooLong |
+                 OHCI1394_cycleInconsistent |
                  OHCI1394_cycle64Seconds | OHCI1394_regAccessFail |
                  OHCI1394_masterIntEnable);
        if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
@@ -1899,15 +1913,30 @@ static int handle_it_packet(struct context *context,
 {
        struct iso_context *ctx =
                container_of(context, struct iso_context, context);
+       int i;
+       struct descriptor *pd;
 
-       if (last->transfer_status == 0)
-               /* This descriptor isn't done yet, stop iteration. */
+       for (pd = d; pd <= last; pd++)
+               if (pd->transfer_status)
+                       break;
+       if (pd > last)
+               /* Descriptor(s) not done yet, stop iteration */
                return 0;
 
-       if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS)
+       i = ctx->header_length;
+       if (i + 4 < PAGE_SIZE) {
+               /* Present this value as big-endian to match the receive code */
+               *(__be32 *)(ctx->header + i) = cpu_to_be32(
+                               ((u32)le16_to_cpu(pd->transfer_status) << 16) |
+                               le16_to_cpu(pd->res_count));
+               ctx->header_length += 4;
+       }
+       if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {
                ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count),
-                                  0, NULL, ctx->base.callback_data);
-
+                                  ctx->header_length, ctx->header,
+                                  ctx->base.callback_data);
+               ctx->header_length = 0;
+       }
        return 1;
 }