firewire: Fix for broken configrom updates in quick succession
[pandora-kernel.git] / drivers / firewire / ohci.c
index eb7b591..23d1468 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/bitops.h>
 #include <linux/bug.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>
@@ -124,6 +125,8 @@ struct context {
        struct fw_ohci *ohci;
        u32 regs;
        int total_allocation;
+       bool running;
+       bool flushing;
 
        /*
         * List of page-sized buffers for storing DMA descriptors.
@@ -168,6 +171,9 @@ struct iso_context {
        int excess_bytes;
        void *header;
        size_t header_length;
+
+       u8 sync;
+       u8 tags;
 };
 
 #define CONFIG_ROM_SIZE 1024
@@ -184,7 +190,8 @@ struct fw_ohci {
        u32 bus_time;
        bool is_root;
        bool csr_state_setclear_abdicate;
-
+       int n_ir;
+       int n_it;
        /*
         * Spinlock for accessing fw_ohci data.  Never call out of
         * this driver with this lock held.
@@ -201,9 +208,11 @@ struct fw_ohci {
        struct context at_request_ctx;
        struct context at_response_ctx;
 
+       u32 it_context_support;
        u32 it_context_mask;     /* unoccupied IT contexts */
        struct iso_context *it_context_list;
        u64 ir_context_channels; /* unoccupied channels */
+       u32 ir_context_support;
        u32 ir_context_mask;     /* unoccupied IR contexts */
        struct iso_context *ir_context_list;
        u64 mc_channels; /* channels in use by the multichannel IR context */
@@ -331,7 +340,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%s%s\n", evt,
            evt & OHCI1394_selfIDComplete       ? " selfID"             : "",
            evt & OHCI1394_RQPkt                ? " AR_req"             : "",
            evt & OHCI1394_RSPkt                ? " AR_resp"            : "",
@@ -344,6 +353,7 @@ static void log_irqs(u32 evt)
            evt & OHCI1394_cycle64Seconds       ? " cycle64Seconds"     : "",
            evt & OHCI1394_cycleInconsistent    ? " cycleInconsistent"  : "",
            evt & OHCI1394_regAccessFail        ? " regAccessFail"      : "",
+           evt & OHCI1394_unrecoverableError   ? " unrecoverableError" : "",
            evt & OHCI1394_busReset             ? " busReset"           : "",
            evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
                    OHCI1394_RSPkt | OHCI1394_reqTxComplete |
@@ -954,7 +964,7 @@ static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci,
        for (i = 0; i < AR_WRAPAROUND_PAGES; i++)
                pages[AR_BUFFERS + i] = ctx->pages[i];
        ctx->buffer = vm_map_ram(pages, AR_BUFFERS + AR_WRAPAROUND_PAGES,
-                                -1, PAGE_KERNEL_RO);
+                                -1, PAGE_KERNEL);
        if (!ctx->buffer)
                goto out_of_memory;
 
@@ -1166,6 +1176,7 @@ static void context_run(struct context *ctx, u32 extra)
                  le32_to_cpu(ctx->last->branch_address));
        reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0);
        reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra);
+       ctx->running = true;
        flush_writes(ohci);
 }
 
@@ -1193,6 +1204,7 @@ static void context_stop(struct context *ctx)
        int i;
 
        reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
+       ctx->running = false;
        flush_writes(ctx->ohci);
 
        for (i = 0; i < 10; i++) {
@@ -1223,7 +1235,6 @@ static int at_context_queue_packet(struct context *ctx,
        struct descriptor *d, *last;
        __le32 *header;
        int z, tcode;
-       u32 reg;
 
        d = context_get_descriptors(ctx, 4, &d_bus);
        if (d == NULL) {
@@ -1318,19 +1329,8 @@ static int at_context_queue_packet(struct context *ctx,
                                     DESCRIPTOR_IRQ_ALWAYS |
                                     DESCRIPTOR_BRANCH_ALWAYS);
 
-       /*
-        * If the controller and packet generations don't match, we need to
-        * bail out and try again.  If IntEvent.busReset is set, the AT context
-        * is halted, so appending to the context and trying to run it is
-        * futile.  Most controllers do the right thing and just flush the AT
-        * queue (per section 7.2.3.2 of the OHCI 1.1 specification), but
-        * some controllers (like a JMicron JMB381 PCI-e) misbehave and wind
-        * up stalling out.  So we just bail out in software and try again
-        * later, and everyone is happy.
-        * FIXME: Document how the locking works.
-        */
-       if (ohci->generation != packet->generation ||
-           reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
+       /* FIXME: Document how the locking works. */
+       if (ohci->generation != packet->generation) {
                if (packet->payload_mapped)
                        dma_unmap_single(ohci->card.device, payload_bus,
                                         packet->payload_length, DMA_TO_DEVICE);
@@ -1340,14 +1340,23 @@ static int at_context_queue_packet(struct context *ctx,
 
        context_append(ctx, d, z, 4 - z);
 
-       /* If the context isn't already running, start it up. */
-       reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));
-       if ((reg & CONTEXT_RUN) == 0)
+       if (!ctx->running)
                context_run(ctx, 0);
 
        return 0;
 }
 
+static void at_context_flush(struct context *ctx)
+{
+       tasklet_disable(&ctx->tasklet);
+
+       ctx->flushing = true;
+       context_tasklet((unsigned long)ctx);
+       ctx->flushing = false;
+
+       tasklet_enable(&ctx->tasklet);
+}
+
 static int handle_at_packet(struct context *context,
                            struct descriptor *d,
                            struct descriptor *last)
@@ -1357,7 +1366,7 @@ static int handle_at_packet(struct context *context,
        struct fw_ohci *ohci = context->ohci;
        int evt;
 
-       if (last->transfer_status == 0)
+       if (last->transfer_status == 0 && !context->flushing)
                /* This descriptor isn't done yet, stop iteration. */
                return 0;
 
@@ -1391,11 +1400,15 @@ static int handle_at_packet(struct context *context,
                break;
 
        case OHCI1394_evt_missing_ack:
-               /*
-                * Using a valid (current) generation count, but the
-                * node is not on the bus or not sending acks.
-                */
-               packet->ack = RCODE_NO_ACK;
+               if (context->flushing)
+                       packet->ack = RCODE_GENERATION;
+               else {
+                       /*
+                        * Using a valid (current) generation count, but the
+                        * node is not on the bus or not sending acks.
+                        */
+                       packet->ack = RCODE_NO_ACK;
+               }
                break;
 
        case ACK_COMPLETE + 0x10:
@@ -1408,6 +1421,13 @@ static int handle_at_packet(struct context *context,
                packet->ack = evt - 0x10;
                break;
 
+       case OHCI1394_evt_no_status:
+               if (context->flushing) {
+                       packet->ack = RCODE_GENERATION;
+                       break;
+               }
+               /* fall through */
+
        default:
                packet->ack = RCODE_SEND_ERROR;
                break;
@@ -1560,6 +1580,47 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet)
 
 }
 
+static void detect_dead_context(struct fw_ohci *ohci,
+                               const char *name, unsigned int regs)
+{
+       u32 ctl;
+
+       ctl = reg_read(ohci, CONTROL_SET(regs));
+       if (ctl & CONTEXT_DEAD) {
+#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
+               fw_error("DMA context %s has stopped, error code: %s\n",
+                        name, evts[ctl & 0x1f]);
+#else
+               fw_error("DMA context %s has stopped, error code: %#x\n",
+                        name, ctl & 0x1f);
+#endif
+       }
+}
+
+static void handle_dead_contexts(struct fw_ohci *ohci)
+{
+       unsigned int i;
+       char name[8];
+
+       detect_dead_context(ohci, "ATReq", OHCI1394_AsReqTrContextBase);
+       detect_dead_context(ohci, "ATRsp", OHCI1394_AsRspTrContextBase);
+       detect_dead_context(ohci, "ARReq", OHCI1394_AsReqRcvContextBase);
+       detect_dead_context(ohci, "ARRsp", OHCI1394_AsRspRcvContextBase);
+       for (i = 0; i < 32; ++i) {
+               if (!(ohci->it_context_support & (1 << i)))
+                       continue;
+               sprintf(name, "IT%u", i);
+               detect_dead_context(ohci, name, OHCI1394_IsoXmitContextBase(i));
+       }
+       for (i = 0; i < 32; ++i) {
+               if (!(ohci->ir_context_support & (1 << i)))
+                       continue;
+               sprintf(name, "IR%u", i);
+               detect_dead_context(ohci, name, OHCI1394_IsoRcvContextBase(i));
+       }
+       /* TODO: maybe try to flush and restart the dead contexts */
+}
+
 static u32 cycle_timer_ticks(u32 cycle_timer)
 {
        u32 ticks;
@@ -1713,9 +1774,23 @@ static void bus_reset_tasklet(unsigned long data)
        /* FIXME: Document how the locking works. */
        spin_lock_irqsave(&ohci->lock, flags);
 
-       ohci->generation = generation;
+       ohci->generation = -1; /* prevent AT packet queueing */
        context_stop(&ohci->at_request_ctx);
        context_stop(&ohci->at_response_ctx);
+
+       spin_unlock_irqrestore(&ohci->lock, flags);
+
+       /*
+        * Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent
+        * packets in the AT queues and software needs to drain them.
+        * Some OHCI 1.1 controllers (JMicron) apparently require this too.
+        */
+       at_context_flush(&ohci->at_request_ctx);
+       at_context_flush(&ohci->at_response_ctx);
+
+       spin_lock_irqsave(&ohci->lock, flags);
+
+       ohci->generation = generation;
        reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
 
        if (ohci->quirks & QUIRK_RESET_PACKET)
@@ -1860,6 +1935,9 @@ static irqreturn_t irq_handler(int irq, void *data)
                        fw_notify("isochronous cycle inconsistent\n");
        }
 
+       if (unlikely(event & OHCI1394_unrecoverableError))
+               handle_dead_contexts(ohci);
+
        if (event & OHCI1394_cycle64Seconds) {
                spin_lock(&ohci->lock);
                update_bus_time(ohci);
@@ -2097,7 +2175,9 @@ static int ohci_enable(struct fw_card *card,
                OHCI1394_selfIDComplete |
                OHCI1394_regAccessFail |
                OHCI1394_cycle64Seconds |
-               OHCI1394_cycleInconsistent | OHCI1394_cycleTooLong |
+               OHCI1394_cycleInconsistent |
+               OHCI1394_unrecoverableError |
+               OHCI1394_cycleTooLong |
                OHCI1394_masterIntEnable;
        if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
                irqs |= OHCI1394_busReset;
@@ -2119,7 +2199,6 @@ static int ohci_set_config_rom(struct fw_card *card,
 {
        struct fw_ohci *ohci;
        unsigned long flags;
-       int ret = -EBUSY;
        __be32 *next_config_rom;
        dma_addr_t uninitialized_var(next_config_rom_bus);
 
@@ -2160,22 +2239,37 @@ static int ohci_set_config_rom(struct fw_card *card,
 
        spin_lock_irqsave(&ohci->lock, flags);
 
+       /*
+        * If there is not an already pending config_rom update,
+        * push our new allocation into the ohci->next_config_rom
+        * and then mark the local variable as null so that we
+        * won't deallocate the new buffer.
+        *
+        * OTOH, if there is a pending config_rom update, just
+        * use that buffer with the new config_rom data, and
+        * let this routine free the unused DMA allocation.
+        */
+
        if (ohci->next_config_rom == NULL) {
                ohci->next_config_rom = next_config_rom;
                ohci->next_config_rom_bus = next_config_rom_bus;
+               next_config_rom = NULL;
+       }
 
-               copy_config_rom(ohci->next_config_rom, config_rom, length);
+       copy_config_rom(ohci->next_config_rom, config_rom, length);
 
-               ohci->next_header = config_rom[0];
-               ohci->next_config_rom[0] = 0;
+       ohci->next_header = config_rom[0];
+       ohci->next_config_rom[0] = 0;
 
-               reg_write(ohci, OHCI1394_ConfigROMmap,
-                         ohci->next_config_rom_bus);
-               ret = 0;
-       }
+       reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus);
 
        spin_unlock_irqrestore(&ohci->lock, flags);
 
+       /* If we didn't use the DMA allocation, delete it. */
+       if (next_config_rom != NULL)
+               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                 next_config_rom, next_config_rom_bus);
+
        /*
         * Now initiate a bus reset to have the changes take
         * effect. We clean up the old config rom memory and DMA
@@ -2183,13 +2277,10 @@ static int ohci_set_config_rom(struct fw_card *card,
         * controller could need to access it before the bus reset
         * takes effect.
         */
-       if (ret == 0)
-               fw_schedule_bus_reset(&ohci->card, true, true);
-       else
-               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
-                                 next_config_rom, next_config_rom_bus);
 
-       return ret;
+       fw_schedule_bus_reset(&ohci->card, true, true);
+
+       return 0;
 }
 
 static void ohci_send_request(struct fw_card *card, struct fw_packet *packet)
@@ -2613,6 +2704,10 @@ static int ohci_start_iso(struct fw_iso_context *base,
        u32 control = IR_CONTEXT_ISOCH_HEADER, match;
        int index;
 
+       /* the controller cannot start without any queued packets */
+       if (ctx->context.last->branch_address == 0)
+               return -ENODATA;
+
        switch (ctx->base.type) {
        case FW_ISO_CONTEXT_TRANSMIT:
                index = ctx - ohci->it_context_list;
@@ -2641,6 +2736,10 @@ static int ohci_start_iso(struct fw_iso_context *base,
                reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index);
                reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match);
                context_run(&ctx->context, control);
+
+               ctx->sync = sync;
+               ctx->tags = tags;
+
                break;
        }
 
@@ -2667,6 +2766,7 @@ static int ohci_stop_iso(struct fw_iso_context *base)
        }
        flush_writes(ohci);
        context_stop(&ctx->context);
+       tasklet_kill(&ctx->context.tasklet);
 
        return 0;
 }
@@ -2738,6 +2838,26 @@ static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels)
        return ret;
 }
 
+#ifdef CONFIG_PM
+static void ohci_resume_iso_dma(struct fw_ohci *ohci)
+{
+       int i;
+       struct iso_context *ctx;
+
+       for (i = 0 ; i < ohci->n_ir ; i++) {
+               ctx = &ohci->ir_context_list[i];
+               if (ctx->context.running)
+                       ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags);
+       }
+
+       for (i = 0 ; i < ohci->n_it ; i++) {
+               ctx = &ohci->it_context_list[i];
+               if (ctx->context.running)
+                       ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags);
+       }
+}
+#endif
+
 static int queue_iso_transmit(struct iso_context *ctx,
                              struct fw_iso_packet *packet,
                              struct fw_iso_buffer *buffer,
@@ -3047,7 +3167,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
        struct fw_ohci *ohci;
        u32 bus_options, max_receive, link_speed, version;
        u64 guid;
-       int i, err, n_ir, n_it;
+       int i, err;
        size_t size;
 
        ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);
@@ -3139,17 +3259,19 @@ static int __devinit pci_probe(struct pci_dev *dev,
 
        reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
        ohci->ir_context_channels = ~0ULL;
-       ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+       ohci->ir_context_support = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
        reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
-       n_ir = hweight32(ohci->ir_context_mask);
-       size = sizeof(struct iso_context) * n_ir;
+       ohci->ir_context_mask = ohci->ir_context_support;
+       ohci->n_ir = hweight32(ohci->ir_context_mask);
+       size = sizeof(struct iso_context) * ohci->n_ir;
        ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
 
        reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
-       ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
+       ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
        reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
-       n_it = hweight32(ohci->it_context_mask);
-       size = sizeof(struct iso_context) * n_it;
+       ohci->it_context_mask = ohci->it_context_support;
+       ohci->n_it = hweight32(ohci->it_context_mask);
+       size = sizeof(struct iso_context) * ohci->n_it;
        ohci->it_context_list = kzalloc(size, GFP_KERNEL);
 
        if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) {
@@ -3174,7 +3296,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
        fw_notify("Added fw-ohci device %s, OHCI v%x.%x, "
                  "%d IR + %d IT contexts, quirks 0x%x\n",
                  dev_name(&dev->dev), version >> 16, version & 0xff,
-                 n_ir, n_it, ohci->quirks);
+                 ohci->n_ir, ohci->n_it, ohci->quirks);
 
        return 0;
 
@@ -3198,7 +3320,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
  fail_disable:
        pci_disable_device(dev);
  fail_free:
-       kfree(&ohci->card);
+       kfree(ohci);
        pmac_ohci_off(dev);
  fail:
        if (err == -ENOMEM)
@@ -3242,7 +3364,7 @@ static void pci_remove(struct pci_dev *dev)
        pci_iounmap(dev, ohci->registers);
        pci_release_region(dev, 0);
        pci_disable_device(dev);
-       kfree(&ohci->card);
+       kfree(ohci);
        pmac_ohci_off(dev);
 
        fw_notify("Removed fw-ohci device.\n");
@@ -3284,7 +3406,20 @@ static int pci_resume(struct pci_dev *dev)
                return err;
        }
 
-       return ohci_enable(&ohci->card, NULL, 0);
+       /* Some systems don't setup GUID register on resume from ram  */
+       if (!reg_read(ohci, OHCI1394_GUIDLo) &&
+                                       !reg_read(ohci, OHCI1394_GUIDHi)) {
+               reg_write(ohci, OHCI1394_GUIDLo, (u32)ohci->card.guid);
+               reg_write(ohci, OHCI1394_GUIDHi, (u32)(ohci->card.guid >> 32));
+       }
+
+       err = ohci_enable(&ohci->card, NULL, 0);
+       if (err)
+               return err;
+
+       ohci_resume_iso_dma(ohci);
+
+       return 0;
 }
 #endif