Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Dec 2009 23:22:27 +0000 (15:22 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Dec 2009 23:22:27 +0000 (15:22 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6:
  firewire: ohci: handle receive packets with a data length of zero

1  2 
drivers/firewire/ohci.c

diff --combined drivers/firewire/ohci.c
index ae4556f0c0c14aac573610566764230d77333321,553c74e1e4e3f876155d8511ef86b04d9ebb7c67..96768e160866a55ac4e2a1a5ef1fdd412c2133f2
@@@ -275,7 -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"            : "",
            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 |
                    OHCI1394_respTxComplete | OHCI1394_isochRx |
                    OHCI1394_isochTx | OHCI1394_postedWriteErr |
                    OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
 +                  OHCI1394_cycleInconsistent |
                    OHCI1394_regAccessFail | OHCI1394_busReset)
                                                ? " ?"                  : "");
  }
@@@ -1443,17 -1441,6 +1443,17 @@@ static irqreturn_t irq_handler(int irq
                          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)
@@@ -1553,7 -1540,6 +1553,7 @@@ static int ohci_enable(struct fw_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)
@@@ -1913,30 -1899,15 +1913,30 @@@ static int handle_it_packet(struct cont
  {
        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;
  }
  
@@@ -2218,6 -2189,13 +2218,13 @@@ static int ohci_queue_iso_receive_dualb
        page     = payload >> PAGE_SHIFT;
        offset   = payload & ~PAGE_MASK;
        rest     = p->payload_length;
+       /*
+        * The controllers I've tested have not worked correctly when
+        * second_req_count is zero.  Rather than do something we know won't
+        * work, return an error
+        */
+       if (rest == 0)
+               return -EINVAL;
  
        /* FIXME: make packet-per-buffer/dual-buffer a context option */
        while (rest > 0) {
@@@ -2271,7 -2249,7 +2278,7 @@@ static int ohci_queue_iso_receive_packe
                                        unsigned long payload)
  {
        struct iso_context *ctx = container_of(base, struct iso_context, base);
-       struct descriptor *d = NULL, *pd = NULL;
+       struct descriptor *d, *pd;
        struct fw_iso_packet *p = packet;
        dma_addr_t d_bus, page_bus;
        u32 z, header_z, rest;
                d->data_address = cpu_to_le32(d_bus + (z * sizeof(*d)));
  
                rest = payload_per_buffer;
+               pd = d;
                for (j = 1; j < z; j++) {
-                       pd = d + j;
+                       pd++;
                        pd->control = cpu_to_le16(DESCRIPTOR_STATUS |
                                                  DESCRIPTOR_INPUT_MORE);