firewire: Fix for broken configrom updates in quick succession
[pandora-kernel.git] / drivers / firewire / ohci.c
index 276324d..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.
@@ -193,14 +200,19 @@ struct fw_ohci {
 
        struct mutex phy_reg_mutex;
 
+       void *misc_buffer;
+       dma_addr_t misc_buffer_bus;
+
        struct ar_context ar_request_ctx;
        struct ar_context ar_response_ctx;
        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 */
@@ -328,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"            : "",
@@ -341,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 |
@@ -418,10 +431,6 @@ static const char *tcodes[] = {
        [0xc] = "-reserved-",           [0xd] = "-reserved-",
        [0xe] = "link internal",        [0xf] = "-reserved-",
 };
-static const char *phys[] = {
-       [0x0] = "phy config packet",    [0x1] = "link-on packet",
-       [0x2] = "self-id packet",       [0x3] = "-reserved-",
-};
 
 static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
 {
@@ -440,12 +449,6 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
                return;
        }
 
-       if (header[0] == ~header[1]) {
-               fw_notify("A%c %s, %s, %08x\n",
-                   dir, evts[evt], phys[header[0] >> 30 & 0x3], header[0]);
-               return;
-       }
-
        switch (tcode) {
        case 0x0: case 0x6: case 0x8:
                snprintf(specific, sizeof(specific), " = %08x",
@@ -460,9 +463,13 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
        }
 
        switch (tcode) {
-       case 0xe: case 0xa:
+       case 0xa:
                fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]);
                break;
+       case 0xe:
+               fw_notify("A%c %s, PHY %08x %08x\n",
+                         dir, evts[evt], header[1], header[2]);
+               break;
        case 0x0: case 0x1: case 0x4: case 0x5: case 0x9:
                fw_notify("A%c spd %x tl %02x, "
                    "%04x -> %04x, %s, "
@@ -629,11 +636,6 @@ static void ar_context_release(struct ar_context *ctx)
 {
        unsigned int i;
 
-       if (ctx->descriptors)
-               dma_free_coherent(ctx->ohci->card.device,
-                                 AR_BUFFERS * sizeof(struct descriptor),
-                                 ctx->descriptors, ctx->descriptors_bus);
-
        if (ctx->buffer)
                vm_unmap_ram(ctx->buffer, AR_BUFFERS + AR_WRAPAROUND_PAGES);
 
@@ -931,8 +933,8 @@ error:
        ctx->pointer = NULL;
 }
 
-static int ar_context_init(struct ar_context *ctx,
-                          struct fw_ohci *ohci, u32 regs)
+static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci,
+                          unsigned int descriptors_offset, u32 regs)
 {
        unsigned int i;
        dma_addr_t dma_addr;
@@ -962,17 +964,12 @@ static int ar_context_init(struct ar_context *ctx,
        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;
 
-       ctx->descriptors =
-               dma_alloc_coherent(ohci->card.device,
-                                  AR_BUFFERS * sizeof(struct descriptor),
-                                  &ctx->descriptors_bus,
-                                  GFP_KERNEL);
-       if (!ctx->descriptors)
-               goto out_of_memory;
+       ctx->descriptors     = ohci->misc_buffer     + descriptors_offset;
+       ctx->descriptors_bus = ohci->misc_buffer_bus + descriptors_offset;
 
        for (i = 0; i < AR_BUFFERS; i++) {
                d = &ctx->descriptors[i];
@@ -1179,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);
 }
 
@@ -1206,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++) {
@@ -1236,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) {
@@ -1250,21 +1248,27 @@ static int at_context_queue_packet(struct context *ctx,
        /*
         * The DMA format for asyncronous link packets is different
         * from the IEEE1394 layout, so shift the fields around
-        * accordingly.  If header_length is 8, it's a PHY packet, to
-        * which we need to prepend an extra quadlet.
+        * accordingly.
         */
 
+       tcode = (packet->header[0] >> 4) & 0x0f;
        header = (__le32 *) &d[1];
-       switch (packet->header_length) {
-       case 16:
-       case 12:
+       switch (tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+       case TCODE_WRITE_BLOCK_REQUEST:
+       case TCODE_WRITE_RESPONSE:
+       case TCODE_READ_QUADLET_REQUEST:
+       case TCODE_READ_BLOCK_REQUEST:
+       case TCODE_READ_QUADLET_RESPONSE:
+       case TCODE_READ_BLOCK_RESPONSE:
+       case TCODE_LOCK_REQUEST:
+       case TCODE_LOCK_RESPONSE:
                header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
                                        (packet->speed << 16));
                header[1] = cpu_to_le32((packet->header[1] & 0xffff) |
                                        (packet->header[0] & 0xffff0000));
                header[2] = cpu_to_le32(packet->header[2]);
 
-               tcode = (packet->header[0] >> 4) & 0x0f;
                if (TCODE_IS_BLOCK_PACKET(tcode))
                        header[3] = cpu_to_le32(packet->header[3]);
                else
@@ -1273,18 +1277,18 @@ static int at_context_queue_packet(struct context *ctx,
                d[0].req_count = cpu_to_le16(packet->header_length);
                break;
 
-       case 8:
+       case TCODE_LINK_INTERNAL:
                header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) |
                                        (packet->speed << 16));
-               header[1] = cpu_to_le32(packet->header[0]);
-               header[2] = cpu_to_le32(packet->header[1]);
+               header[1] = cpu_to_le32(packet->header[1]);
+               header[2] = cpu_to_le32(packet->header[2]);
                d[0].req_count = cpu_to_le16(12);
 
-               if (is_ping_packet(packet->header))
+               if (is_ping_packet(&packet->header[1]))
                        d[0].control |= cpu_to_le16(DESCRIPTOR_PING);
                break;
 
-       case 4:
+       case TCODE_STREAM_DATA:
                header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
                                        (packet->speed << 16));
                header[1] = cpu_to_le32(packet->header[0] & 0xffff0000);
@@ -1325,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);
@@ -1347,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)
@@ -1364,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;
 
@@ -1398,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:
@@ -1415,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;
@@ -1567,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;
@@ -1720,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)
@@ -1790,8 +1858,12 @@ static irqreturn_t irq_handler(int irq, void *data)
        if (!event || !~event)
                return IRQ_NONE;
 
-       /* busReset must not be cleared yet, see OHCI 1.1 clause 7.2.3.2 */
-       reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
+       /*
+        * busReset and postedWriteErr must not be cleared yet
+        * (OHCI 1.1 clauses 7.2.3.2 and 13.2.8.1)
+        */
+       reg_write(ohci, OHCI1394_IntEventClear,
+                 event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr));
        log_irqs(event);
 
        if (event & OHCI1394_selfIDComplete)
@@ -1809,30 +1881,41 @@ static irqreturn_t irq_handler(int irq, void *data)
        if (event & OHCI1394_respTxComplete)
                tasklet_schedule(&ohci->at_response_ctx.tasklet);
 
-       iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
-       reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event);
+       if (event & OHCI1394_isochRx) {
+               iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
+               reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event);
 
-       while (iso_event) {
-               i = ffs(iso_event) - 1;
-               tasklet_schedule(&ohci->ir_context_list[i].context.tasklet);
-               iso_event &= ~(1 << i);
+               while (iso_event) {
+                       i = ffs(iso_event) - 1;
+                       tasklet_schedule(
+                               &ohci->ir_context_list[i].context.tasklet);
+                       iso_event &= ~(1 << i);
+               }
        }
 
-       iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear);
-       reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event);
+       if (event & OHCI1394_isochTx) {
+               iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear);
+               reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event);
 
-       while (iso_event) {
-               i = ffs(iso_event) - 1;
-               tasklet_schedule(&ohci->it_context_list[i].context.tasklet);
-               iso_event &= ~(1 << i);
+               while (iso_event) {
+                       i = ffs(iso_event) - 1;
+                       tasklet_schedule(
+                               &ohci->it_context_list[i].context.tasklet);
+                       iso_event &= ~(1 << i);
+               }
        }
 
        if (unlikely(event & OHCI1394_regAccessFail))
                fw_error("Register access failure - "
                         "please notify linux1394-devel@lists.sf.net\n");
 
-       if (unlikely(event & OHCI1394_postedWriteErr))
+       if (unlikely(event & OHCI1394_postedWriteErr)) {
+               reg_read(ohci, OHCI1394_PostedWriteAddressHi);
+               reg_read(ohci, OHCI1394_PostedWriteAddressLo);
+               reg_write(ohci, OHCI1394_IntEventClear,
+                         OHCI1394_postedWriteErr);
                fw_error("PCI posted write error\n");
+       }
 
        if (unlikely(event & OHCI1394_cycleTooLong)) {
                if (printk_ratelimit())
@@ -1852,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);
@@ -2089,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;
@@ -2111,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);
 
@@ -2152,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
@@ -2175,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)
@@ -2605,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;
@@ -2633,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;
        }
 
@@ -2659,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;
 }
@@ -2730,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,
@@ -3039,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);
@@ -3093,12 +3221,28 @@ static int __devinit pci_probe(struct pci_dev *dev,
        if (param_quirks)
                ohci->quirks = param_quirks;
 
-       err = ar_context_init(&ohci->ar_request_ctx, ohci,
+       /*
+        * Because dma_alloc_coherent() allocates at least one page,
+        * we save space by using a common buffer for the AR request/
+        * response descriptors and the self IDs buffer.
+        */
+       BUILD_BUG_ON(AR_BUFFERS * sizeof(struct descriptor) > PAGE_SIZE/4);
+       BUILD_BUG_ON(SELF_ID_BUF_SIZE > PAGE_SIZE/2);
+       ohci->misc_buffer = dma_alloc_coherent(ohci->card.device,
+                                              PAGE_SIZE,
+                                              &ohci->misc_buffer_bus,
+                                              GFP_KERNEL);
+       if (!ohci->misc_buffer) {
+               err = -ENOMEM;
+               goto fail_iounmap;
+       }
+
+       err = ar_context_init(&ohci->ar_request_ctx, ohci, 0,
                              OHCI1394_AsReqRcvContextControlSet);
        if (err < 0)
-               goto fail_iounmap;
+               goto fail_misc_buf;
 
-       err = ar_context_init(&ohci->ar_response_ctx, ohci,
+       err = ar_context_init(&ohci->ar_response_ctx, ohci, PAGE_SIZE/4,
                              OHCI1394_AsRspRcvContextControlSet);
        if (err < 0)
                goto fail_arreq_ctx;
@@ -3115,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) {
@@ -3133,15 +3279,8 @@ static int __devinit pci_probe(struct pci_dev *dev,
                goto fail_contexts;
        }
 
-       /* self-id dma buffer allocation */
-       ohci->self_id_cpu = dma_alloc_coherent(ohci->card.device,
-                                              SELF_ID_BUF_SIZE,
-                                              &ohci->self_id_bus,
-                                              GFP_KERNEL);
-       if (ohci->self_id_cpu == NULL) {
-               err = -ENOMEM;
-               goto fail_contexts;
-       }
+       ohci->self_id_cpu = ohci->misc_buffer     + PAGE_SIZE/2;
+       ohci->self_id_bus = ohci->misc_buffer_bus + PAGE_SIZE/2;
 
        bus_options = reg_read(ohci, OHCI1394_BusOptions);
        max_receive = (bus_options >> 12) & 0xf;
@@ -3151,19 +3290,16 @@ static int __devinit pci_probe(struct pci_dev *dev,
 
        err = fw_card_add(&ohci->card, max_receive, link_speed, guid);
        if (err)
-               goto fail_self_id;
+               goto fail_contexts;
 
        version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
        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;
 
- fail_self_id:
-       dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
-                         ohci->self_id_cpu, ohci->self_id_bus);
  fail_contexts:
        kfree(ohci->ir_context_list);
        kfree(ohci->it_context_list);
@@ -3174,6 +3310,9 @@ static int __devinit pci_probe(struct pci_dev *dev,
        ar_context_release(&ohci->ar_response_ctx);
  fail_arreq_ctx:
        ar_context_release(&ohci->ar_request_ctx);
+ fail_misc_buf:
+       dma_free_coherent(ohci->card.device, PAGE_SIZE,
+                         ohci->misc_buffer, ohci->misc_buffer_bus);
  fail_iounmap:
        pci_iounmap(dev, ohci->registers);
  fail_iomem:
@@ -3181,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)
@@ -3213,10 +3352,10 @@ static void pci_remove(struct pci_dev *dev)
        if (ohci->config_rom)
                dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
                                  ohci->config_rom, ohci->config_rom_bus);
-       dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
-                         ohci->self_id_cpu, ohci->self_id_bus);
        ar_context_release(&ohci->ar_request_ctx);
        ar_context_release(&ohci->ar_response_ctx);
+       dma_free_coherent(ohci->card.device, PAGE_SIZE,
+                         ohci->misc_buffer, ohci->misc_buffer_bus);
        context_release(&ohci->at_request_ctx);
        context_release(&ohci->at_response_ctx);
        kfree(ohci->it_context_list);
@@ -3225,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");
@@ -3267,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