]> err.no Git - linux-2.6/blobdiff - drivers/firewire/fw-ohci.c
Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6] / drivers / firewire / fw-ohci.c
index 46660ac0dac55579522efccef464b160498633a4..4f02c55f13e15131b95bc615e540e2931ad63d96 100644 (file)
@@ -178,9 +178,10 @@ struct fw_ohci {
        struct tasklet_struct bus_reset_tasklet;
        int node_id;
        int generation;
-       int request_generation;
+       int request_generation; /* for timestamping incoming requests */
        u32 bus_seconds;
        bool old_uninorth;
+       bool bus_reset_packet_quirk;
 
        /*
         * Spinlock for accessing fw_ohci data.  Never call out of
@@ -302,13 +303,13 @@ static char _p(u32 *s, int shift)
        return port[*s >> shift & 3];
 }
 
-static void log_selfids(int generation, int self_id_count, u32 *s)
+static void log_selfids(int node_id, int generation, int self_id_count, u32 *s)
 {
        if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS)))
                return;
 
-       printk(KERN_DEBUG KBUILD_MODNAME ": %d selfIDs, generation %d\n",
-              self_id_count, generation);
+       printk(KERN_DEBUG KBUILD_MODNAME ": %d selfIDs, generation %d, "
+              "local node ID %04x\n", self_id_count, generation, node_id);
 
        for (; self_id_count--; ++s)
                if ((*s & 1 << 23) == 0)
@@ -371,6 +372,12 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
        if (unlikely(evt >= ARRAY_SIZE(evts)))
                        evt = 0x1f;
 
+       if (evt == OHCI1394_evt_bus_reset) {
+               printk(KERN_DEBUG "A%c evt_bus_reset, generation %d\n",
+                      dir, (header[2] >> 16) & 0xff);
+               return;
+       }
+
        if (header[0] == ~header[1]) {
                printk(KERN_DEBUG "A%c %s, %s, %08x\n",
                       dir, evts[evt], phys[header[0] >> 30 & 0x3],
@@ -417,7 +424,7 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
 #else
 
 #define log_irqs(evt)
-#define log_selfids(generation, self_id_count, sid)
+#define log_selfids(node_id, generation, self_id_count, sid)
 #define log_ar_at_event(dir, speed, header, evt)
 
 #endif /* CONFIG_FIREWIRE_OHCI_DEBUG */
@@ -565,14 +572,19 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
         * generation.  We only need this for requests; for responses
         * we use the unique tlabel for finding the matching
         * request.
+        *
+        * Alas some chips sometimes emit bus reset packets with a
+        * wrong generation.  We set the correct generation for these
+        * at a slightly incorrect time (in bus_reset_tasklet).
         */
-
-       if (evt == OHCI1394_evt_bus_reset)
-               ohci->request_generation = (p.header[2] >> 16) & 0xff;
-       else if (ctx == &ohci->ar_request_ctx)
+       if (evt == OHCI1394_evt_bus_reset) {
+               if (!ohci->bus_reset_packet_quirk)
+                       ohci->request_generation = (p.header[2] >> 16) & 0xff;
+       } else if (ctx == &ohci->ar_request_ctx) {
                fw_core_handle_request(&ohci->card, &p);
-       else
+       } else {
                fw_core_handle_response(&ohci->card, &p);
+       }
 
        return buffer + length + 1;
 }
@@ -1279,6 +1291,9 @@ static void bus_reset_tasklet(unsigned long data)
        context_stop(&ohci->at_response_ctx);
        reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
 
+       if (ohci->bus_reset_packet_quirk)
+               ohci->request_generation = generation;
+
        /*
         * This next bit is unrelated to the AT context stuff but we
         * have to do it under the spinlock also.  If a new config rom
@@ -1320,7 +1335,8 @@ static void bus_reset_tasklet(unsigned long data)
                dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
                                  free_rom, free_rom_bus);
 
-       log_selfids(generation, self_id_count, ohci->self_id_buffer);
+       log_selfids(ohci->node_id, generation,
+                   self_id_count, ohci->self_id_buffer);
 
        fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
                                 self_id_count, ohci->self_id_buffer);
@@ -2353,6 +2369,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
        ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
                             dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
 #endif
+       ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
+
        spin_lock_init(&ohci->lock);
 
        tasklet_init(&ohci->bus_reset_tasklet,