diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 20:31:15 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 20:31:15 -0700 |
commit | 34699403e9916060af8ae23f5e4705a6c078e79d (patch) | |
tree | e149ca6354171caf61132d80508ad878b00878c9 /drivers/firewire/ohci.c | |
parent | 7fc86a7908a4e9eb2da4b6498f86193d113842d3 (diff) | |
parent | d1bbd20972936b9b178fda3eb1ec417cb27fdc01 (diff) | |
download | linux-34699403e9916060af8ae23f5e4705a6c078e79d.tar.gz linux-34699403e9916060af8ae23f5e4705a6c078e79d.tar.bz2 linux-34699403e9916060af8ae23f5e4705a6c078e79d.zip |
Merge tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394
Pull IEEE 1394 (FireWire) subsystem updates post v3.3 from Stefan Richter:
- Some SBP-2 initiator fixes, side product from ongoing work on a target.
- Reintroduction of an isochronous I/O feature of the older ieee1394 driver
stack (flush buffer completions); it was evidently rarely used but not
actually unused. Matching libraw1394 code is already available.
- Be sure to prefix all kernel log messages with device name or card name,
and other logging related cleanups.
- Misc other small cleanups, among them a small API change that affects
sound/firewire/ too. Clemens Ladisch is aware of it.
* tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394: (26 commits)
firewire: allow explicit flushing of iso packet completions
firewire: prevent dropping of completed iso packet header data
firewire: ohci: factor out iso completion flushing code
firewire: ohci: simplify iso header pointer arithmetic
firewire: ohci: optimize control bit checks
firewire: ohci: remove unused excess_bytes field
firewire: ohci: copy_iso_headers(): make comment match the code
firewire: cdev: fix IR multichannel event documentation
firewire: ohci: fix too-early completion of IR multichannel buffers
firewire: ohci: move runtime debug facility out of #ifdef
firewire: tone down some diagnostic log messages
firewire: sbp2: replace a GFP_ATOMIC allocation
firewire: sbp2: Fix SCSI sense data mangling
firewire: sbp2: Ignore SBP-2 targets on the local node
firewire: sbp2: Take into account Unit_Unique_ID
firewire: nosy: Use the macro DMA_BIT_MASK().
firewire: core: convert AR-req handler lock from _irqsave to _bh
firewire: core: fix race at address_handler unregistration
firewire: core: remove obsolete comment
firewire: core: prefix log messages with card name
...
Diffstat (limited to 'drivers/firewire/ohci.c')
-rw-r--r-- | drivers/firewire/ohci.c | 350 |
1 files changed, 209 insertions, 141 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 7f5f0da726da..187b3f2e797e 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -170,10 +170,12 @@ struct context { struct iso_context { struct fw_iso_context base; struct context context; - int excess_bytes; void *header; size_t header_length; - + unsigned long flushing_completions; + u32 mc_buffer_bus; + u16 mc_completed; + u16 last_timestamp; u8 sync; u8 tags; }; @@ -338,8 +340,6 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0" #define OHCI_PARAM_DEBUG_IRQS 4 #define OHCI_PARAM_DEBUG_BUSRESETS 8 /* only effective before chip init */ -#ifdef CONFIG_FIREWIRE_OHCI_DEBUG - static int param_debug; module_param_named(debug, param_debug, int, 0644); MODULE_PARM_DESC(debug, "Verbose logging (default = 0" @@ -349,7 +349,7 @@ MODULE_PARM_DESC(debug, "Verbose logging (default = 0" ", busReset events = " __stringify(OHCI_PARAM_DEBUG_BUSRESETS) ", or a combination, or all = -1)"); -static void log_irqs(u32 evt) +static void log_irqs(struct fw_ohci *ohci, u32 evt) { if (likely(!(param_debug & (OHCI_PARAM_DEBUG_IRQS | OHCI_PARAM_DEBUG_BUSRESETS)))) @@ -359,7 +359,8 @@ 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%s\n", evt, + dev_notice(ohci->card.device, + "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" : "", @@ -398,24 +399,29 @@ static char _p(u32 *s, int shift) return port[*s >> shift & 3]; } -static void log_selfids(int node_id, int generation, int self_id_count, u32 *s) +static void log_selfids(struct fw_ohci *ohci, int generation, int self_id_count) { + u32 *s; + if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS))) return; - fw_notify("%d selfIDs, generation %d, local node ID %04x\n", - self_id_count, generation, node_id); + dev_notice(ohci->card.device, + "%d selfIDs, generation %d, local node ID %04x\n", + self_id_count, generation, ohci->node_id); - for (; self_id_count--; ++s) + for (s = ohci->self_id_buffer; self_id_count--; ++s) if ((*s & 1 << 23) == 0) - fw_notify("selfID 0: %08x, phy %d [%c%c%c] " + dev_notice(ohci->card.device, + "selfID 0: %08x, phy %d [%c%c%c] " "%s gc=%d %s %s%s%s\n", *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2), speed[*s >> 14 & 3], *s >> 16 & 63, power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "", *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : ""); else - fw_notify("selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n", + dev_notice(ohci->card.device, + "selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n", *s, *s >> 24 & 63, _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10), _p(s, 8), _p(s, 6), _p(s, 4), _p(s, 2)); @@ -451,7 +457,8 @@ static const char *tcodes[] = { [0xe] = "link internal", [0xf] = "-reserved-", }; -static void log_ar_at_event(char dir, int speed, u32 *header, int evt) +static void log_ar_at_event(struct fw_ohci *ohci, + char dir, int speed, u32 *header, int evt) { int tcode = header[0] >> 4 & 0xf; char specific[12]; @@ -463,8 +470,9 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt) evt = 0x1f; if (evt == OHCI1394_evt_bus_reset) { - fw_notify("A%c evt_bus_reset, generation %d\n", - dir, (header[2] >> 16) & 0xff); + dev_notice(ohci->card.device, + "A%c evt_bus_reset, generation %d\n", + dir, (header[2] >> 16) & 0xff); return; } @@ -483,39 +491,35 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt) switch (tcode) { case 0xa: - fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]); + dev_notice(ohci->card.device, + "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]); + dev_notice(ohci->card.device, + "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, " - "%s, %04x%08x%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], header[1] & 0xffff, header[2], specific); + dev_notice(ohci->card.device, + "A%c spd %x tl %02x, " + "%04x -> %04x, %s, " + "%s, %04x%08x%s\n", + dir, speed, header[0] >> 10 & 0x3f, + header[1] >> 16, header[0] >> 16, evts[evt], + tcodes[tcode], header[1] & 0xffff, header[2], specific); break; default: - fw_notify("A%c spd %x tl %02x, " - "%04x -> %04x, %s, " - "%s%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], specific); + dev_notice(ohci->card.device, + "A%c spd %x tl %02x, " + "%04x -> %04x, %s, " + "%s%s\n", + dir, speed, header[0] >> 10 & 0x3f, + header[1] >> 16, header[0] >> 16, evts[evt], + tcodes[tcode], specific); } } -#else - -#define param_debug 0 -static inline void log_irqs(u32 evt) {} -static inline void log_selfids(int node_id, int generation, int self_id_count, u32 *s) {} -static inline void log_ar_at_event(char dir, int speed, u32 *header, int evt) {} - -#endif /* CONFIG_FIREWIRE_OHCI_DEBUG */ - static inline void reg_write(const struct fw_ohci *ohci, int offset, u32 data) { writel(data, ohci->registers + offset); @@ -559,7 +563,7 @@ static int read_phy_reg(struct fw_ohci *ohci, int addr) if (i >= 3) msleep(1); } - fw_error("failed to read phy reg\n"); + dev_err(ohci->card.device, "failed to read phy reg\n"); return -EBUSY; } @@ -581,7 +585,7 @@ static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val) if (i >= 3) msleep(1); } - fw_error("failed to write phy reg\n"); + dev_err(ohci->card.device, "failed to write phy reg\n"); return -EBUSY; } @@ -680,11 +684,14 @@ static void ar_context_release(struct ar_context *ctx) static void ar_context_abort(struct ar_context *ctx, const char *error_msg) { - if (reg_read(ctx->ohci, CONTROL_CLEAR(ctx->regs)) & CONTEXT_RUN) { - reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); - flush_writes(ctx->ohci); + struct fw_ohci *ohci = ctx->ohci; + + if (reg_read(ohci, CONTROL_CLEAR(ctx->regs)) & CONTEXT_RUN) { + reg_write(ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); + flush_writes(ohci); - fw_error("AR error: %s; DMA stopped\n", error_msg); + dev_err(ohci->card.device, "AR error: %s; DMA stopped\n", + error_msg); } /* FIXME: restart? */ } @@ -854,7 +861,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) p.timestamp = status & 0xffff; p.generation = ohci->request_generation; - log_ar_at_event('R', p.speed, p.header, evt); + log_ar_at_event(ohci, 'R', p.speed, p.header, evt); /* * Several controllers, notably from NEC and VIA, forget to @@ -1226,21 +1233,22 @@ static void context_append(struct context *ctx, static void context_stop(struct context *ctx) { + struct fw_ohci *ohci = ctx->ohci; u32 reg; int i; - reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); + reg_write(ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); ctx->running = false; for (i = 0; i < 1000; i++) { - reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs)); + reg = reg_read(ohci, CONTROL_SET(ctx->regs)); if ((reg & CONTEXT_ACTIVE) == 0) return; if (i) udelay(10); } - fw_error("Error: DMA context still active (0x%08x)\n", reg); + dev_err(ohci->card.device, "DMA context still active (0x%08x)\n", reg); } struct driver_data { @@ -1420,7 +1428,7 @@ static int handle_at_packet(struct context *context, evt = le16_to_cpu(last->transfer_status) & 0x1f; packet->timestamp = le16_to_cpu(last->res_count); - log_ar_at_event('T', packet->speed, packet->header, evt); + log_ar_at_event(ohci, 'T', packet->speed, packet->header, evt); switch (evt) { case OHCI1394_evt_timeout: @@ -1549,7 +1557,7 @@ static void handle_local_lock(struct fw_ohci *ohci, goto out; } - fw_error("swap not done (CSR lock timeout)\n"); + dev_err(ohci->card.device, "swap not done (CSR lock timeout)\n"); fw_fill_response(&response, packet->header, RCODE_BUSY, NULL, 0); out: @@ -1623,15 +1631,10 @@ static void detect_dead_context(struct fw_ohci *ohci, 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 - } + if (ctl & CONTEXT_DEAD) + dev_err(ohci->card.device, + "DMA context %s has stopped, error code: %s\n", + name, evts[ctl & 0x1f]); } static void handle_dead_contexts(struct fw_ohci *ohci) @@ -1781,7 +1784,8 @@ static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count) reg = reg_read(ohci, OHCI1394_NodeID); if (!(reg & OHCI1394_NodeID_idValid)) { - fw_notify("node ID not valid, new bus reset in progress\n"); + dev_notice(ohci->card.device, + "node ID not valid, new bus reset in progress\n"); return -EBUSY; } self_id |= ((reg & 0x3f) << 24); /* phy ID */ @@ -1827,11 +1831,12 @@ static void bus_reset_work(struct work_struct *work) reg = reg_read(ohci, OHCI1394_NodeID); if (!(reg & OHCI1394_NodeID_idValid)) { - fw_notify("node ID not valid, new bus reset in progress\n"); + dev_notice(ohci->card.device, + "node ID not valid, new bus reset in progress\n"); return; } if ((reg & OHCI1394_NodeID_nodeNumber) == 63) { - fw_notify("malconfigured bus\n"); + dev_notice(ohci->card.device, "malconfigured bus\n"); return; } ohci->node_id = reg & (OHCI1394_NodeID_busNumber | @@ -1845,7 +1850,7 @@ static void bus_reset_work(struct work_struct *work) reg = reg_read(ohci, OHCI1394_SelfIDCount); if (reg & OHCI1394_SelfIDCount_selfIDError) { - fw_notify("inconsistent self IDs\n"); + dev_notice(ohci->card.device, "inconsistent self IDs\n"); return; } /* @@ -1857,7 +1862,7 @@ static void bus_reset_work(struct work_struct *work) self_id_count = (reg >> 3) & 0xff; if (self_id_count > 252) { - fw_notify("inconsistent self IDs\n"); + dev_notice(ohci->card.device, "inconsistent self IDs\n"); return; } @@ -1875,11 +1880,13 @@ static void bus_reset_work(struct work_struct *work) */ if (cond_le32_to_cpu(ohci->self_id_cpu[i]) == 0xffff008f) { - fw_notify("ignoring spurious self IDs\n"); + dev_notice(ohci->card.device, + "ignoring spurious self IDs\n"); self_id_count = j; break; } else { - fw_notify("inconsistent self IDs\n"); + dev_notice(ohci->card.device, + "inconsistent self IDs\n"); return; } } @@ -1890,13 +1897,14 @@ static void bus_reset_work(struct work_struct *work) if (ohci->quirks & QUIRK_TI_SLLZ059) { self_id_count = find_and_insert_self_id(ohci, self_id_count); if (self_id_count < 0) { - fw_notify("could not construct local self ID\n"); + dev_notice(ohci->card.device, + "could not construct local self ID\n"); return; } } if (self_id_count == 0) { - fw_notify("inconsistent self IDs\n"); + dev_notice(ohci->card.device, "inconsistent self IDs\n"); return; } rmb(); @@ -1917,8 +1925,8 @@ static void bus_reset_work(struct work_struct *work) new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff; if (new_generation != generation) { - fw_notify("recursive bus reset detected, " - "discarding self ids\n"); + dev_notice(ohci->card.device, + "new bus reset, discarding self ids\n"); return; } @@ -1989,8 +1997,7 @@ static void bus_reset_work(struct work_struct *work) dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, free_rom, free_rom_bus); - log_selfids(ohci->node_id, generation, - self_id_count, ohci->self_id_buffer); + log_selfids(ohci, generation, self_id_count); fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation, self_id_count, ohci->self_id_buffer, @@ -2015,7 +2022,7 @@ static irqreturn_t irq_handler(int irq, void *data) */ reg_write(ohci, OHCI1394_IntEventClear, event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr)); - log_irqs(event); + log_irqs(ohci, event); if (event & OHCI1394_selfIDComplete) queue_work(fw_workqueue, &ohci->bus_reset_work); @@ -2057,8 +2064,7 @@ static irqreturn_t irq_handler(int irq, void *data) } if (unlikely(event & OHCI1394_regAccessFail)) - fw_error("Register access failure - " - "please notify linux1394-devel@lists.sf.net\n"); + dev_err(ohci->card.device, "register access failure\n"); if (unlikely(event & OHCI1394_postedWriteErr)) { reg_read(ohci, OHCI1394_PostedWriteAddressHi); @@ -2066,12 +2072,13 @@ static irqreturn_t irq_handler(int irq, void *data) reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_postedWriteErr); if (printk_ratelimit()) - fw_error("PCI posted write error\n"); + dev_err(ohci->card.device, "PCI posted write error\n"); } if (unlikely(event & OHCI1394_cycleTooLong)) { if (printk_ratelimit()) - fw_notify("isochronous cycle too long\n"); + dev_notice(ohci->card.device, + "isochronous cycle too long\n"); reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_cycleMaster); } @@ -2084,7 +2091,8 @@ static irqreturn_t irq_handler(int irq, void *data) * them at least two cycles later. (FIXME?) */ if (printk_ratelimit()) - fw_notify("isochronous cycle inconsistent\n"); + dev_notice(ohci->card.device, + "isochronous cycle inconsistent\n"); } if (unlikely(event & OHCI1394_unrecoverableError)) @@ -2211,7 +2219,7 @@ static int ohci_enable(struct fw_card *card, int i, ret; if (software_reset(ohci)) { - fw_error("Failed to reset ohci card.\n"); + dev_err(card->device, "failed to reset ohci card\n"); return -EBUSY; } @@ -2235,7 +2243,7 @@ static int ohci_enable(struct fw_card *card, } if (!lps) { - fw_error("Failed to set Link Power Status\n"); + dev_err(card->device, "failed to set Link Power Status\n"); return -EIO; } @@ -2244,7 +2252,7 @@ static int ohci_enable(struct fw_card *card, if (ret < 0) return ret; if (ret) - fw_notify("local TSB41BA3D phy\n"); + dev_notice(card->device, "local TSB41BA3D phy\n"); else ohci->quirks &= ~QUIRK_TI_SLLZ059; } @@ -2344,7 +2352,8 @@ static int ohci_enable(struct fw_card *card, if (request_irq(dev->irq, irq_handler, pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, ohci_driver_name, ohci)) { - fw_error("Failed to allocate interrupt %d.\n", dev->irq); + dev_err(card->device, "failed to allocate interrupt %d\n", + dev->irq); pci_disable_msi(dev); if (config_rom) { @@ -2509,7 +2518,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) dma_unmap_single(ohci->card.device, packet->payload_bus, packet->payload_length, DMA_TO_DEVICE); - log_ar_at_event('T', packet->speed, packet->header, 0x20); + log_ar_at_event(ohci, 'T', packet->speed, packet->header, 0x20); driver_data->packet = NULL; packet->ack = RCODE_CANCELLED; packet->callback(packet, &ohci->card, packet->ack); @@ -2674,25 +2683,35 @@ static void ohci_write_csr(struct fw_card *card, int csr_offset, u32 value) } } -static void copy_iso_headers(struct iso_context *ctx, void *p) +static void flush_iso_completions(struct iso_context *ctx) { - int i = ctx->header_length; + ctx->base.callback.sc(&ctx->base, ctx->last_timestamp, + ctx->header_length, ctx->header, + ctx->base.callback_data); + ctx->header_length = 0; +} - if (i + ctx->base.header_size > PAGE_SIZE) - return; +static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr) +{ + u32 *ctx_hdr; + + if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) + flush_iso_completions(ctx); + + ctx_hdr = ctx->header + ctx->header_length; + ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]); /* - * The iso header is byteswapped to little endian by - * the controller, but the remaining header quadlets - * are big endian. We want to present all the headers - * as big endian, so we have to swap the first quadlet. + * The two iso header quadlets are byteswapped to little + * endian by the controller, but we want to present them + * as big endian for consistency with the bus endianness. */ if (ctx->base.header_size > 0) - *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4)); + ctx_hdr[0] = swab32(dma_hdr[1]); /* iso packet header */ if (ctx->base.header_size > 4) - *(u32 *) (ctx->header + i + 4) = __swab32(*(u32 *) p); + ctx_hdr[1] = swab32(dma_hdr[0]); /* timestamp */ if (ctx->base.header_size > 8) - memcpy(ctx->header + i + 8, p + 8, ctx->base.header_size - 8); + memcpy(&ctx_hdr[2], &dma_hdr[2], ctx->base.header_size - 8); ctx->header_length += ctx->base.header_size; } @@ -2704,8 +2723,6 @@ static int handle_ir_packet_per_buffer(struct context *context, container_of(context, struct iso_context, context); struct descriptor *pd; u32 buffer_dma; - __le32 *ir_header; - void *p; for (pd = d; pd <= last; pd++) if (pd->transfer_status) @@ -2724,17 +2741,10 @@ static int handle_ir_packet_per_buffer(struct context *context, DMA_FROM_DEVICE); } - p = last + 1; - copy_iso_headers(ctx, p); + copy_iso_headers(ctx, (u32 *) (last + 1)); - if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) { - ir_header = (__le32 *) p; - ctx->base.callback.sc(&ctx->base, - le32_to_cpu(ir_header[0]) & 0xffff, - ctx->header_length, ctx->header, - ctx->base.callback_data); - ctx->header_length = 0; - } + if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) + flush_iso_completions(ctx); return 1; } @@ -2746,29 +2756,51 @@ static int handle_ir_buffer_fill(struct context *context, { struct iso_context *ctx = container_of(context, struct iso_context, context); + unsigned int req_count, res_count, completed; u32 buffer_dma; - if (!last->transfer_status) + req_count = le16_to_cpu(last->req_count); + res_count = le16_to_cpu(ACCESS_ONCE(last->res_count)); + completed = req_count - res_count; + buffer_dma = le32_to_cpu(last->data_address); + + if (completed > 0) { + ctx->mc_buffer_bus = buffer_dma; + ctx->mc_completed = completed; + } + + if (res_count != 0) /* Descriptor(s) not done yet, stop iteration */ return 0; - buffer_dma = le32_to_cpu(last->data_address); dma_sync_single_range_for_cpu(context->ohci->card.device, buffer_dma & PAGE_MASK, buffer_dma & ~PAGE_MASK, - le16_to_cpu(last->req_count), - DMA_FROM_DEVICE); + completed, DMA_FROM_DEVICE); - if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) + if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) { ctx->base.callback.mc(&ctx->base, - le32_to_cpu(last->data_address) + - le16_to_cpu(last->req_count) - - le16_to_cpu(last->res_count), + buffer_dma + completed, ctx->base.callback_data); + ctx->mc_completed = 0; + } return 1; } +static void flush_ir_buffer_fill(struct iso_context *ctx) +{ + dma_sync_single_range_for_cpu(ctx->context.ohci->card.device, + ctx->mc_buffer_bus & PAGE_MASK, + ctx->mc_buffer_bus & ~PAGE_MASK, + ctx->mc_completed, DMA_FROM_DEVICE); + + ctx->base.callback.mc(&ctx->base, + ctx->mc_buffer_bus + ctx->mc_completed, + ctx->base.callback_data); + ctx->mc_completed = 0; +} + static inline void sync_it_packet_for_cpu(struct context *context, struct descriptor *pd) { @@ -2812,8 +2844,8 @@ static int handle_it_packet(struct context *context, { struct iso_context *ctx = container_of(context, struct iso_context, context); - int i; struct descriptor *pd; + __be32 *ctx_hdr; for (pd = d; pd <= last; pd++) if (pd->transfer_status) @@ -2824,20 +2856,19 @@ static int handle_it_packet(struct context *context, sync_it_packet_for_cpu(context, d); - 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.sc(&ctx->base, le16_to_cpu(last->res_count), - ctx->header_length, ctx->header, - ctx->base.callback_data); - ctx->header_length = 0; - } + if (ctx->header_length + 4 > PAGE_SIZE) + flush_iso_completions(ctx); + + ctx_hdr = ctx->header + ctx->header_length; + ctx->last_timestamp = le16_to_cpu(last->res_count); + /* Present this value as big-endian to match the receive code */ + *ctx_hdr = cpu_to_be32((le16_to_cpu(pd->transfer_status) << 16) | + le16_to_cpu(pd->res_count)); + ctx->header_length += 4; + + if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) + flush_iso_completions(ctx); + return 1; } @@ -2924,8 +2955,10 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card, if (ret < 0) goto out_with_header; - if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) + if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) { set_multichannel_mask(ohci, 0); + ctx->mc_completed = 0; + } return &ctx->base; @@ -3387,6 +3420,39 @@ static void ohci_flush_queue_iso(struct fw_iso_context *base) reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); } +static int ohci_flush_iso_completions(struct fw_iso_context *base) +{ + struct iso_context *ctx = container_of(base, struct iso_context, base); + int ret = 0; + + tasklet_disable(&ctx->context.tasklet); + + if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) { + context_tasklet((unsigned long)&ctx->context); + + switch (base->type) { + case FW_ISO_CONTEXT_TRANSMIT: + case FW_ISO_CONTEXT_RECEIVE: + if (ctx->header_length != 0) + flush_iso_completions(ctx); + break; + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + if (ctx->mc_completed != 0) + flush_ir_buffer_fill(ctx); + break; + default: + ret = -ENOSYS; + } + + clear_bit_unlock(0, &ctx->flushing_completions); + smp_mb__after_clear_bit(); + } + + tasklet_enable(&ctx->context.tasklet); + + return ret; +} + static const struct fw_card_driver ohci_driver = { .enable = ohci_enable, .read_phy_reg = ohci_read_phy_reg, @@ -3404,6 +3470,7 @@ static const struct fw_card_driver ohci_driver = { .set_iso_channels = ohci_set_iso_channels, .queue_iso = ohci_queue_iso, .flush_queue_iso = ohci_flush_queue_iso, + .flush_iso_completions = ohci_flush_iso_completions, .start_iso = ohci_start_iso, .stop_iso = ohci_stop_iso, }; @@ -3463,7 +3530,7 @@ static int __devinit pci_probe(struct pci_dev *dev, err = pci_enable_device(dev); if (err) { - fw_error("Failed to enable OHCI hardware\n"); + dev_err(&dev->dev, "failed to enable OHCI hardware\n"); goto fail_free; } @@ -3478,13 +3545,13 @@ static int __devinit pci_probe(struct pci_dev *dev, err = pci_request_region(dev, 0, ohci_driver_name); if (err) { - fw_error("MMIO resource unavailable\n"); + dev_err(&dev->dev, "MMIO resource unavailable\n"); goto fail_disable; } ohci->registers = pci_iomap(dev, 0, OHCI1394_REGISTER_SIZE); if (ohci->registers == NULL) { - fw_error("Failed to remap registers\n"); + dev_err(&dev->dev, "failed to remap registers\n"); err = -ENXIO; goto fail_iomem; } @@ -3573,9 +3640,10 @@ static int __devinit pci_probe(struct pci_dev *dev, goto fail_contexts; version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; - fw_notify("Added fw-ohci device %s, OHCI v%x.%x, " + dev_notice(&dev->dev, + "added OHCI v%x.%x device as card %d, " "%d IR + %d IT contexts, quirks 0x%x\n", - dev_name(&dev->dev), version >> 16, version & 0xff, + version >> 16, version & 0xff, ohci->card.index, ohci->n_ir, ohci->n_it, ohci->quirks); return 0; @@ -3604,7 +3672,7 @@ static int __devinit pci_probe(struct pci_dev *dev, pmac_ohci_off(dev); fail: if (err == -ENOMEM) - fw_error("Out of memory\n"); + dev_err(&dev->dev, "out of memory\n"); return err; } @@ -3648,7 +3716,7 @@ static void pci_remove(struct pci_dev *dev) kfree(ohci); pmac_ohci_off(dev); - fw_notify("Removed fw-ohci device.\n"); + dev_notice(&dev->dev, "removed fw-ohci device\n"); } #ifdef CONFIG_PM @@ -3662,12 +3730,12 @@ static int pci_suspend(struct pci_dev *dev, pm_message_t state) pci_disable_msi(dev); err = pci_save_state(dev); if (err) { - fw_error("pci_save_state failed\n"); + dev_err(&dev->dev, "pci_save_state failed\n"); return err; } err = pci_set_power_state(dev, pci_choose_state(dev, state)); if (err) - fw_error("pci_set_power_state failed with %d\n", err); + dev_err(&dev->dev, "pci_set_power_state failed with %d\n", err); pmac_ohci_off(dev); return 0; @@ -3683,7 +3751,7 @@ static int pci_resume(struct pci_dev *dev) pci_restore_state(dev); err = pci_enable_device(dev); if (err) { - fw_error("pci_enable_device failed\n"); + dev_err(&dev->dev, "pci_enable_device failed\n"); return err; } |