]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge tag 'v2.6.33' for its firewire changes since last branch point
authorStefan Richter <stefanr@s5r6.in-berlin.de>
Wed, 24 Feb 2010 19:31:04 +0000 (20:31 +0100)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Wed, 24 Feb 2010 19:33:45 +0000 (20:33 +0100)
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
1  2 
drivers/firewire/core-cdev.c
drivers/firewire/ohci.c

index 5538d5130f7b8a349b22c2c28324a79828851d43,4eeaed57e2197a0dd5f0cab7cffa4713eaf2ec96..3c1ac0933d24eb83c81cb3fabab9fbe0021ff38d
@@@ -25,7 -25,6 +25,7 @@@
  #include <linux/firewire.h>
  #include <linux/firewire-cdev.h>
  #include <linux/idr.h>
 +#include <linux/irqflags.h>
  #include <linux/jiffies.h>
  #include <linux/kernel.h>
  #include <linux/kref.h>
  #include <linux/module.h>
  #include <linux/mutex.h>
  #include <linux/poll.h>
 -#include <linux/preempt.h>
  #include <linux/sched.h>
  #include <linux/spinlock.h>
+ #include <linux/string.h>
  #include <linux/time.h>
  #include <linux/uaccess.h>
  #include <linux/vmalloc.h>
@@@ -595,13 -596,20 +596,20 @@@ static int ioctl_send_request(struct cl
                            client->device->max_speed);
  }
  
+ static inline bool is_fcp_request(struct fw_request *request)
+ {
+       return request == NULL;
+ }
  static void release_request(struct client *client,
                            struct client_resource *resource)
  {
        struct inbound_transaction_resource *r = container_of(resource,
                        struct inbound_transaction_resource, resource);
  
-       if (r->request)
+       if (is_fcp_request(r->request))
+               kfree(r->data);
+       else
                fw_send_response(client->device->card, r->request,
                                 RCODE_CONFLICT_ERROR);
        kfree(r);
@@@ -616,6 -624,7 +624,7 @@@ static void handle_request(struct fw_ca
        struct address_handler_resource *handler = callback_data;
        struct inbound_transaction_resource *r;
        struct inbound_transaction_event *e;
+       void *fcp_frame = NULL;
        int ret;
  
        r = kmalloc(sizeof(*r), GFP_ATOMIC);
        r->data    = payload;
        r->length  = length;
  
+       if (is_fcp_request(request)) {
+               /*
+                * FIXME: Let core-transaction.c manage a
+                * single reference-counted copy?
+                */
+               fcp_frame = kmemdup(payload, length, GFP_ATOMIC);
+               if (fcp_frame == NULL)
+                       goto failed;
+               r->data = fcp_frame;
+       }
        r->resource.release = release_request;
        ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
        if (ret < 0)
        e->request.closure = handler->closure;
  
        queue_event(handler->client, &e->event,
-                   &e->request, sizeof(e->request), payload, length);
+                   &e->request, sizeof(e->request), r->data, length);
        return;
  
   failed:
        kfree(r);
        kfree(e);
-       if (request)
+       kfree(fcp_frame);
+       if (!is_fcp_request(request))
                fw_send_response(card, request, RCODE_CONFLICT_ERROR);
  }
  
@@@ -717,18 -740,17 +740,17 @@@ static int ioctl_send_response(struct c
  
        r = container_of(resource, struct inbound_transaction_resource,
                         resource);
-       if (r->request) {
-               if (request->length < r->length)
-                       r->length = request->length;
-               if (copy_from_user(r->data, u64_to_uptr(request->data),
-                                  r->length)) {
-                       ret = -EFAULT;
-                       kfree(r->request);
-                       goto out;
-               }
-               fw_send_response(client->device->card, r->request,
-                                request->rcode);
+       if (is_fcp_request(r->request))
+               goto out;
+       if (request->length < r->length)
+               r->length = request->length;
+       if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
+               ret = -EFAULT;
+               kfree(r->request);
+               goto out;
        }
+       fw_send_response(client->device->card, r->request, request->rcode);
   out:
        kfree(r);
  
@@@ -1013,19 -1035,21 +1035,19 @@@ static int ioctl_get_cycle_timer(struc
  {
        struct fw_cdev_get_cycle_timer *request = buffer;
        struct fw_card *card = client->device->card;
 -      unsigned long long bus_time;
        struct timeval tv;
 -      unsigned long flags;
 +      u32 cycle_time;
  
 -      preempt_disable();
 -      local_irq_save(flags);
 +      local_irq_disable();
  
 -      bus_time = card->driver->get_bus_time(card);
 +      cycle_time = card->driver->get_cycle_time(card);
        do_gettimeofday(&tv);
  
 -      local_irq_restore(flags);
 -      preempt_enable();
 +      local_irq_enable();
  
        request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
 -      request->cycle_timer = bus_time & 0xffffffff;
 +      request->cycle_timer = cycle_time;
 +
        return 0;
  }
  
diff --combined drivers/firewire/ohci.c
index f8a71397cf6ea72143cd0ceb97b271c8f20fa03a,43ebf337b131152bb0503372cadd8173535e5e62..0f7c4bb978e70e04406ab93f1c2f0d0a8810789a
@@@ -38,6 -38,7 +38,6 @@@
  #include <linux/spinlock.h>
  #include <linux/string.h>
  
 -#include <asm/atomic.h>
  #include <asm/byteorder.h>
  #include <asm/page.h>
  #include <asm/system.h>
@@@ -186,11 -187,11 +186,11 @@@ struct fw_ohci 
        int node_id;
        int generation;
        int request_generation; /* for timestamping incoming requests */
 -      atomic_t bus_seconds;
  
        bool use_dualbuffer;
        bool old_uninorth;
        bool bus_reset_packet_quirk;
 +      bool iso_cycle_timer_quirk;
  
        /*
         * Spinlock for accessing fw_ohci data.  Never call out of
@@@ -274,7 -275,7 +274,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%s\n", evt,
 +      fw_notify("IRQ %08x%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_isochTx              ? " IT"                 : "",
            evt & OHCI1394_postedWriteErr       ? " postedWriteErr"     : "",
            evt & OHCI1394_cycleTooLong         ? " cycleTooLong"       : "",
 -          evt & OHCI1394_cycle64Seconds       ? " cycle64Seconds"     : "",
            evt & OHCI1394_cycleInconsistent    ? " cycleInconsistent"  : "",
            evt & OHCI1394_regAccessFail        ? " regAccessFail"      : "",
            evt & OHCI1394_busReset             ? " busReset"           : "",
                    OHCI1394_RSPkt | OHCI1394_reqTxComplete |
                    OHCI1394_respTxComplete | OHCI1394_isochRx |
                    OHCI1394_isochTx | OHCI1394_postedWriteErr |
 -                  OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
 -                  OHCI1394_cycleInconsistent |
 +                  OHCI1394_cycleTooLong | OHCI1394_cycleInconsistent |
                    OHCI1394_regAccessFail | OHCI1394_busReset)
                                                ? " ?"                  : "");
  }
@@@ -1381,7 -1384,7 +1381,7 @@@ static void bus_reset_tasklet(unsigned 
  static irqreturn_t irq_handler(int irq, void *data)
  {
        struct fw_ohci *ohci = data;
 -      u32 event, iso_event, cycle_time;
 +      u32 event, iso_event;
        int i;
  
        event = reg_read(ohci, OHCI1394_IntEventClear);
                        fw_notify("isochronous cycle inconsistent\n");
        }
  
 -      if (event & OHCI1394_cycle64Seconds) {
 -              cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 -              if ((cycle_time & 0x80000000) == 0)
 -                      atomic_inc(&ohci->bus_seconds);
 -      }
 -
        return IRQ_HANDLED;
  }
  
@@@ -1544,7 -1553,8 +1544,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_cycleInconsistent | OHCI1394_regAccessFail |
                  OHCI1394_masterIntEnable);
        if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
                reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
@@@ -1784,61 -1794,16 +1784,61 @@@ static int ohci_enable_phys_dma(struct 
  #endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
  }
  
 -static u64 ohci_get_bus_time(struct fw_card *card)
 +static u32 cycle_timer_ticks(u32 cycle_timer)
  {
 -      struct fw_ohci *ohci = fw_ohci(card);
 -      u32 cycle_time;
 -      u64 bus_time;
 +      u32 ticks;
  
 -      cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 -      bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | cycle_time;
 +      ticks = cycle_timer & 0xfff;
 +      ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
 +      ticks += (3072 * 8000) * (cycle_timer >> 25);
  
 -      return bus_time;
 +      return ticks;
 +}
 +
 +/*
 + * Some controllers exhibit one or more of the following bugs when updating the
 + * iso cycle timer register:
 + *  - When the lowest six bits are wrapping around to zero, a read that happens
 + *    at the same time will return garbage in the lowest ten bits.
 + *  - When the cycleOffset field wraps around to zero, the cycleCount field is
 + *    not incremented for about 60 ns.
 + *  - Occasionally, the entire register reads zero.
 + *
 + * To catch these, we read the register three times and ensure that the
 + * difference between each two consecutive reads is approximately the same, i.e.
 + * less than twice the other.  Furthermore, any negative difference indicates an
 + * error.  (A PCI read should take at least 20 ticks of the 24.576 MHz timer to
 + * execute, so we have enough precision to compute the ratio of the differences.)
 + */
 +static u32 ohci_get_cycle_time(struct fw_card *card)
 +{
 +      struct fw_ohci *ohci = fw_ohci(card);
 +      u32 c0, c1, c2;
 +      u32 t0, t1, t2;
 +      s32 diff01, diff12;
 +      int i;
 +
 +      c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 +
 +      if (ohci->iso_cycle_timer_quirk) {
 +              i = 0;
 +              c1 = c2;
 +              c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 +              do {
 +                      c0 = c1;
 +                      c1 = c2;
 +                      c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 +                      t0 = cycle_timer_ticks(c0);
 +                      t1 = cycle_timer_ticks(c1);
 +                      t2 = cycle_timer_ticks(c2);
 +                      diff01 = t1 - t0;
 +                      diff12 = t2 - t1;
 +              } while ((diff01 <= 0 || diff12 <= 0 ||
 +                        diff01 / diff12 >= 2 || diff12 / diff01 >= 2)
 +                       && i++ < 20);
 +      }
 +
 +      return c2;
  }
  
  static void copy_iso_headers(struct iso_context *ctx, void *p)
@@@ -2136,11 -2101,6 +2136,6 @@@ static int ohci_queue_iso_transmit(stru
        u32 payload_index, payload_end_index, next_page_index;
        int page, end_page, i, length, offset;
  
-       /*
-        * FIXME: Cycle lost behavior should be configurable: lose
-        * packet, retransmit or terminate..
-        */
        p = packet;
        payload_index = payload;
  
        if (!p->skip) {
                d[0].control   = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE);
                d[0].req_count = cpu_to_le16(8);
+               /*
+                * Link the skip address to this descriptor itself.  This causes
+                * a context to skip a cycle whenever lost cycles or FIFO
+                * overruns occur, without dropping the data.  The application
+                * should then decide whether this is an error condition or not.
+                * FIXME:  Make the context's cycle-lost behaviour configurable?
+                */
+               d[0].branch_address = cpu_to_le32(d_bus | z);
  
                header = (__le32 *) &d[1];
                header[0] = cpu_to_le32(IT_HEADER_SY(p->sy) |
@@@ -2415,7 -2383,7 +2418,7 @@@ static const struct fw_card_driver ohci
        .send_response          = ohci_send_response,
        .cancel_packet          = ohci_cancel_packet,
        .enable_phys_dma        = ohci_enable_phys_dma,
 -      .get_bus_time           = ohci_get_bus_time,
 +      .get_cycle_time         = ohci_get_cycle_time,
  
        .allocate_iso_context   = ohci_allocate_iso_context,
        .free_iso_context       = ohci_free_iso_context,
@@@ -2455,6 -2423,7 +2458,7 @@@ static void ohci_pmac_off(struct pci_de
  
  #define PCI_VENDOR_ID_AGERE           PCI_VENDOR_ID_ATT
  #define PCI_DEVICE_ID_AGERE_FW643     0x5901
+ #define PCI_DEVICE_ID_TI_TSB43AB23    0x8024
  
  static int __devinit pci_probe(struct pci_dev *dev,
                               const struct pci_device_id *ent)
  #if !defined(CONFIG_X86_32)
        /* dual-buffer mode is broken with descriptor addresses above 2G */
        if (dev->vendor == PCI_VENDOR_ID_TI &&
-           dev->device == PCI_DEVICE_ID_TI_TSB43AB22)
+           (dev->device == PCI_DEVICE_ID_TI_TSB43AB22 ||
+            dev->device == PCI_DEVICE_ID_TI_TSB43AB23))
                ohci->use_dualbuffer = false;
  #endif
  
  #endif
        ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
  
 +      ohci->iso_cycle_timer_quirk = dev->vendor == PCI_VENDOR_ID_AL   ||
 +                                    dev->vendor == PCI_VENDOR_ID_NEC  ||
 +                                    dev->vendor == PCI_VENDOR_ID_VIA;
 +
        ar_context_init(&ohci->ar_request_ctx, ohci,
                        OHCI1394_AsReqRcvContextControlSet);
  
@@@ -2696,7 -2662,7 +2701,7 @@@ static int pci_resume(struct pci_dev *d
  }
  #endif
  
 -static struct pci_device_id pci_table[] = {
 +static const struct pci_device_id pci_table[] = {
        { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_FIREWIRE_OHCI, ~0) },
        { }
  };