aboutsummaryrefslogtreecommitdiff
path: root/drivers/firewire/ohci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/ohci.c')
-rw-r--r--drivers/firewire/ohci.c624
1 files changed, 389 insertions, 235 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 7f5f0da726d..a66a3217f1d 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -46,7 +46,6 @@
#include <asm/byteorder.h>
#include <asm/page.h>
-#include <asm/system.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/pmac_feature.h>
@@ -55,6 +54,10 @@
#include "core.h"
#include "ohci.h"
+#define ohci_info(ohci, f, args...) dev_info(ohci->card.device, f, ##args)
+#define ohci_notice(ohci, f, args...) dev_notice(ohci->card.device, f, ##args)
+#define ohci_err(ohci, f, args...) dev_err(ohci->card.device, f, ##args)
+
#define DESCRIPTOR_OUTPUT_MORE 0
#define DESCRIPTOR_OUTPUT_LAST (1 << 12)
#define DESCRIPTOR_INPUT_MORE (2 << 12)
@@ -69,6 +72,8 @@
#define DESCRIPTOR_BRANCH_ALWAYS (3 << 2)
#define DESCRIPTOR_WAIT (3 << 0)
+#define DESCRIPTOR_CMD (0xf << 12)
+
struct descriptor {
__le16 req_count;
__le16 control;
@@ -150,10 +155,11 @@ struct context {
struct descriptor *last;
/*
- * The last descriptor in the DMA program. It contains the branch
+ * The last descriptor block in the DMA program. It contains the branch
* address that must be updated upon appending a new descriptor.
*/
struct descriptor *prev;
+ int prev_z;
descriptor_callback_t callback;
@@ -170,10 +176,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;
};
@@ -190,6 +198,7 @@ struct fw_ohci {
unsigned quirks;
unsigned int pri_req_max;
u32 bus_time;
+ bool bus_time_running;
bool is_root;
bool csr_state_setclear_abdicate;
int n_ir;
@@ -226,13 +235,15 @@ struct fw_ohci {
dma_addr_t next_config_rom_bus;
__be32 next_header;
- __le32 *self_id_cpu;
+ __le32 *self_id;
dma_addr_t self_id_bus;
struct work_struct bus_reset_work;
u32 self_id_buffer[512];
};
+static struct workqueue_struct *selfid_workqueue;
+
static inline struct fw_ohci *fw_ohci(struct fw_card *card)
{
return container_of(card, struct fw_ohci, card);
@@ -262,20 +273,24 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
static char ohci_driver_name[] = KBUILD_MODNAME;
+#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd
#define PCI_DEVICE_ID_AGERE_FW643 0x5901
#define PCI_DEVICE_ID_CREATIVE_SB1394 0x4001
#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380
#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009
#define PCI_DEVICE_ID_TI_TSB12LV26 0x8020
#define PCI_DEVICE_ID_TI_TSB82AA2 0x8025
-#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd
-
-#define QUIRK_CYCLE_TIMER 1
-#define QUIRK_RESET_PACKET 2
-#define QUIRK_BE_HEADERS 4
-#define QUIRK_NO_1394A 8
-#define QUIRK_NO_MSI 16
-#define QUIRK_TI_SLLZ059 32
+#define PCI_DEVICE_ID_VIA_VT630X 0x3044
+#define PCI_REV_ID_VIA_VT6306 0x46
+#define PCI_DEVICE_ID_VIA_VT6315 0x3403
+
+#define QUIRK_CYCLE_TIMER 0x1
+#define QUIRK_RESET_PACKET 0x2
+#define QUIRK_BE_HEADERS 0x4
+#define QUIRK_NO_1394A 0x8
+#define QUIRK_NO_MSI 0x10
+#define QUIRK_TI_SLLZ059 0x20
+#define QUIRK_IR_WAKE 0x40
/* In case of multiple matches in ohci_quirks[], only the first one is used. */
static const struct {
@@ -317,6 +332,15 @@ static const struct {
{PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_RESET_PACKET},
+ {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT630X, PCI_REV_ID_VIA_VT6306,
+ QUIRK_CYCLE_TIMER | QUIRK_IR_WAKE},
+
+ {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT6315, 0,
+ QUIRK_CYCLE_TIMER /* FIXME: necessary? */ | QUIRK_NO_MSI},
+
+ {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT6315, PCI_ANY_ID,
+ QUIRK_NO_MSI},
+
{PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_CYCLE_TIMER | QUIRK_NO_MSI},
};
@@ -327,10 +351,11 @@ module_param_named(quirks, param_quirks, int, 0644);
MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
", nonatomic cycle timer = " __stringify(QUIRK_CYCLE_TIMER)
", reset packet generation = " __stringify(QUIRK_RESET_PACKET)
- ", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS)
+ ", AR/selfID endianness = " __stringify(QUIRK_BE_HEADERS)
", no 1394a enhancements = " __stringify(QUIRK_NO_1394A)
", disable MSI = " __stringify(QUIRK_NO_MSI)
", TI SLLZ059 erratum = " __stringify(QUIRK_TI_SLLZ059)
+ ", IR wake unreliable = " __stringify(QUIRK_IR_WAKE)
")");
#define OHCI_PARAM_DEBUG_AT_AR 1
@@ -338,8 +363,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 +372,11 @@ 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 bool param_remote_dma;
+module_param_named(remote_dma, param_remote_dma, bool, 0444);
+MODULE_PARM_DESC(remote_dma, "Enable unfiltered remote DMA (default = N)");
+
+static void log_irqs(struct fw_ohci *ohci, u32 evt)
{
if (likely(!(param_debug &
(OHCI_PARAM_DEBUG_IRQS | OHCI_PARAM_DEBUG_BUSRESETS))))
@@ -359,7 +386,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%s\n", evt,
+ ohci_notice(ohci, "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 +425,27 @@ 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);
+ ohci_notice(ohci, "%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] "
- "%s gc=%d %s %s%s%s\n",
+ ohci_notice(ohci,
+ "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",
+ ohci_notice(ohci,
+ "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 +481,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 +494,8 @@ 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);
+ ohci_notice(ohci, "A%c evt_bus_reset, generation %d\n",
+ dir, (header[2] >> 16) & 0xff);
return;
}
@@ -483,39 +514,29 @@ 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]);
+ ohci_notice(ohci, "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]);
+ ohci_notice(ohci, "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);
+ ohci_notice(ohci,
+ "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);
+ ohci_notice(ohci,
+ "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 +580,8 @@ static int read_phy_reg(struct fw_ohci *ohci, int addr)
if (i >= 3)
msleep(1);
}
- fw_error("failed to read phy reg\n");
+ ohci_err(ohci, "failed to read phy reg %d\n", addr);
+ dump_stack();
return -EBUSY;
}
@@ -581,7 +603,8 @@ 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");
+ ohci_err(ohci, "failed to write phy reg %d, val %u\n", addr, val);
+ dump_stack();
return -EBUSY;
}
@@ -680,11 +703,13 @@ 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);
+ ohci_err(ohci, "AR error: %s; DMA stopped\n", error_msg);
}
/* FIXME: restart? */
}
@@ -854,7 +879,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
@@ -1150,6 +1175,7 @@ static int context_init(struct context *ctx, struct fw_ohci *ohci,
ctx->buffer_tail->used += sizeof(*ctx->buffer_tail->buffer);
ctx->last = ctx->buffer_tail->buffer;
ctx->prev = ctx->buffer_tail->buffer;
+ ctx->prev_z = 1;
return 0;
}
@@ -1214,33 +1240,55 @@ static void context_append(struct context *ctx,
{
dma_addr_t d_bus;
struct descriptor_buffer *desc = ctx->buffer_tail;
+ struct descriptor *d_branch;
d_bus = desc->buffer_bus + (d - desc->buffer) * sizeof(*d);
desc->used += (z + extra) * sizeof(*d);
wmb(); /* finish init of new descriptors before branch_address update */
- ctx->prev->branch_address = cpu_to_le32(d_bus | z);
- ctx->prev = find_branch_descriptor(d, z);
+
+ d_branch = find_branch_descriptor(ctx->prev, ctx->prev_z);
+ d_branch->branch_address = cpu_to_le32(d_bus | z);
+
+ /*
+ * VT6306 incorrectly checks only the single descriptor at the
+ * CommandPtr when the wake bit is written, so if it's a
+ * multi-descriptor block starting with an INPUT_MORE, put a copy of
+ * the branch address in the first descriptor.
+ *
+ * Not doing this for transmit contexts since not sure how it interacts
+ * with skip addresses.
+ */
+ if (unlikely(ctx->ohci->quirks & QUIRK_IR_WAKE) &&
+ d_branch != ctx->prev &&
+ (ctx->prev->control & cpu_to_le16(DESCRIPTOR_CMD)) ==
+ cpu_to_le16(DESCRIPTOR_INPUT_MORE)) {
+ ctx->prev->branch_address = cpu_to_le32(d_bus | z);
+ }
+
+ ctx->prev = d;
+ ctx->prev_z = z;
}
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);
+ ohci_err(ohci, "DMA context still active (0x%08x)\n", reg);
}
struct driver_data {
@@ -1273,7 +1321,7 @@ static int at_context_queue_packet(struct context *ctx,
d[0].res_count = cpu_to_le16(packet->timestamp);
/*
- * The DMA format for asyncronous link packets is different
+ * The DMA format for asynchronous link packets is different
* from the IEEE1394 layout, so shift the fields around
* accordingly.
*/
@@ -1420,7 +1468,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 +1597,7 @@ static void handle_local_lock(struct fw_ohci *ohci,
goto out;
}
- fw_error("swap not done (CSR lock timeout)\n");
+ ohci_err(ohci, "swap not done (CSR lock timeout)\n");
fw_fill_response(&response, packet->header, RCODE_BUSY, NULL, 0);
out:
@@ -1623,15 +1671,9 @@ 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)
+ ohci_err(ohci, "DMA context %s has stopped, error code: %s\n",
+ name, evts[ctl & 0x1f]);
}
static void handle_dead_contexts(struct fw_ohci *ohci)
@@ -1724,6 +1766,13 @@ static u32 update_bus_time(struct fw_ohci *ohci)
{
u32 cycle_time_seconds = get_cycle_time(ohci) >> 25;
+ if (unlikely(!ohci->bus_time_running)) {
+ reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_cycle64Seconds);
+ ohci->bus_time = (lower_32_bits(get_seconds()) & ~0x7f) |
+ (cycle_time_seconds & 0x40);
+ ohci->bus_time_running = true;
+ }
+
if ((ohci->bus_time & 0x40) != (cycle_time_seconds & 0x40))
ohci->bus_time += 0x40;
@@ -1767,11 +1816,35 @@ static int get_self_id_pos(struct fw_ohci *ohci, u32 self_id,
return i;
}
+static int initiated_reset(struct fw_ohci *ohci)
+{
+ int reg;
+ int ret = 0;
+
+ mutex_lock(&ohci->phy_reg_mutex);
+ reg = write_phy_reg(ohci, 7, 0xe0); /* Select page 7 */
+ if (reg >= 0) {
+ reg = read_phy_reg(ohci, 8);
+ reg |= 0x40;
+ reg = write_phy_reg(ohci, 8, reg); /* set PMODE bit */
+ if (reg >= 0) {
+ reg = read_phy_reg(ohci, 12); /* read register 12 */
+ if (reg >= 0) {
+ if ((reg & 0x08) == 0x08) {
+ /* bit 3 indicates "initiated reset" */
+ ret = 0x2;
+ }
+ }
+ }
+ }
+ mutex_unlock(&ohci->phy_reg_mutex);
+ return ret;
+}
+
/*
* TI TSB82AA2B and TSB12LV26 do not receive the selfID of a locally
* attached TSB41BA3D phy; see http://www.ti.com/litv/pdf/sllz059.
* Construct the selfID from phy register contents.
- * FIXME: How to determine the selfID.i flag?
*/
static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count)
{
@@ -1781,7 +1854,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");
+ ohci_notice(ohci,
+ "node ID not valid, new bus reset in progress\n");
return -EBUSY;
}
self_id |= ((reg & 0x3f) << 24); /* phy ID */
@@ -1803,6 +1877,8 @@ static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count)
self_id |= ((status & 0x3) << (6 - (i * 2)));
}
+ self_id |= initiated_reset(ohci);
+
pos = get_self_id_pos(ohci, self_id, self_id_count);
if (pos >= 0) {
memmove(&(ohci->self_id_buffer[pos+1]),
@@ -1818,20 +1894,20 @@ static void bus_reset_work(struct work_struct *work)
{
struct fw_ohci *ohci =
container_of(work, struct fw_ohci, bus_reset_work);
- int self_id_count, i, j, reg;
- int generation, new_generation;
- unsigned long flags;
+ int self_id_count, generation, new_generation, i, j;
+ u32 reg;
void *free_rom = NULL;
dma_addr_t free_rom_bus = 0;
bool is_new_root;
reg = reg_read(ohci, OHCI1394_NodeID);
if (!(reg & OHCI1394_NodeID_idValid)) {
- fw_notify("node ID not valid, new bus reset in progress\n");
+ ohci_notice(ohci,
+ "node ID not valid, new bus reset in progress\n");
return;
}
if ((reg & OHCI1394_NodeID_nodeNumber) == 63) {
- fw_notify("malconfigured bus\n");
+ ohci_notice(ohci, "malconfigured bus\n");
return;
}
ohci->node_id = reg & (OHCI1394_NodeID_busNumber |
@@ -1845,7 +1921,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");
+ ohci_notice(ohci, "self ID receive error\n");
return;
}
/*
@@ -1857,15 +1933,18 @@ 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");
+ ohci_notice(ohci, "bad selfIDSize (%08x)\n", reg);
return;
}
- generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff;
+ generation = (cond_le32_to_cpu(ohci->self_id[0]) >> 16) & 0xff;
rmb();
for (i = 1, j = 0; j < self_id_count; i += 2, j++) {
- if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) {
+ u32 id = cond_le32_to_cpu(ohci->self_id[i]);
+ u32 id2 = cond_le32_to_cpu(ohci->self_id[i + 1]);
+
+ if (id != ~id2) {
/*
* If the invalid data looks like a cycle start packet,
* it's likely to be the result of the cycle master
@@ -1873,30 +1952,30 @@ static void bus_reset_work(struct work_struct *work)
* so far are valid and should be processed so that the
* bus manager can then correct the gap count.
*/
- if (cond_le32_to_cpu(ohci->self_id_cpu[i])
- == 0xffff008f) {
- fw_notify("ignoring spurious self IDs\n");
+ if (id == 0xffff008f) {
+ ohci_notice(ohci, "ignoring spurious self IDs\n");
self_id_count = j;
break;
- } else {
- fw_notify("inconsistent self IDs\n");
- return;
}
+
+ ohci_notice(ohci, "bad self ID %d/%d (%08x != ~%08x)\n",
+ j, self_id_count, id, id2);
+ return;
}
- ohci->self_id_buffer[j] =
- cond_le32_to_cpu(ohci->self_id_cpu[i]);
+ ohci->self_id_buffer[j] = id;
}
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");
+ ohci_notice(ohci,
+ "could not construct local self ID\n");
return;
}
}
if (self_id_count == 0) {
- fw_notify("inconsistent self IDs\n");
+ ohci_notice(ohci, "no self IDs\n");
return;
}
rmb();
@@ -1917,19 +1996,18 @@ 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");
+ ohci_notice(ohci, "new bus reset, discarding self ids\n");
return;
}
/* FIXME: Document how the locking works. */
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
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);
+ spin_unlock_irq(&ohci->lock);
/*
* Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent
@@ -1939,7 +2017,7 @@ static void bus_reset_work(struct work_struct *work)
at_context_flush(&ohci->at_request_ctx);
at_context_flush(&ohci->at_response_ctx);
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
ohci->generation = generation;
reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
@@ -1978,19 +2056,18 @@ static void bus_reset_work(struct work_struct *work)
be32_to_cpu(ohci->next_header));
}
-#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA
- reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0);
- reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0);
-#endif
+ if (param_remote_dma) {
+ reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0);
+ reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0);
+ }
- spin_unlock_irqrestore(&ohci->lock, flags);
+ spin_unlock_irq(&ohci->lock);
if (free_rom)
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,10 +2092,10 @@ 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);
+ queue_work(selfid_workqueue, &ohci->bus_reset_work);
if (event & OHCI1394_RQPkt)
tasklet_schedule(&ohci->ar_request_ctx.tasklet);
@@ -2057,8 +2134,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");
+ ohci_err(ohci, "register access failure\n");
if (unlikely(event & OHCI1394_postedWriteErr)) {
reg_read(ohci, OHCI1394_PostedWriteAddressHi);
@@ -2066,12 +2142,12 @@ 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");
+ ohci_err(ohci, "PCI posted write error\n");
}
if (unlikely(event & OHCI1394_cycleTooLong)) {
if (printk_ratelimit())
- fw_notify("isochronous cycle too long\n");
+ ohci_notice(ohci, "isochronous cycle too long\n");
reg_write(ohci, OHCI1394_LinkControlSet,
OHCI1394_LinkControl_cycleMaster);
}
@@ -2084,7 +2160,7 @@ 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");
+ ohci_notice(ohci, "isochronous cycle inconsistent\n");
}
if (unlikely(event & OHCI1394_unrecoverableError))
@@ -2206,12 +2282,11 @@ static int ohci_enable(struct fw_card *card,
const __be32 *config_rom, size_t length)
{
struct fw_ohci *ohci = fw_ohci(card);
- struct pci_dev *dev = to_pci_dev(card->device);
- u32 lps, seconds, version, irqs;
+ u32 lps, version, irqs;
int i, ret;
if (software_reset(ohci)) {
- fw_error("Failed to reset ohci card.\n");
+ ohci_err(ohci, "failed to reset ohci card\n");
return -EBUSY;
}
@@ -2222,7 +2297,12 @@ static int ohci_enable(struct fw_card *card,
* will lock up the machine. Wait 50msec to make sure we have
* full link enabled. However, with some cards (well, at least
* a JMicron PCIe card), we have to try again sometimes.
+ *
+ * TI TSB82AA2 + TSB81BA3(A) cards signal LPS enabled early but
+ * cannot actually use the phy at that time. These need tens of
+ * millisecods pause between LPS write and first phy access too.
*/
+
reg_write(ohci, OHCI1394_HCControlSet,
OHCI1394_HCControl_LPS |
OHCI1394_HCControl_postedWriteEnable);
@@ -2235,7 +2315,7 @@ static int ohci_enable(struct fw_card *card,
}
if (!lps) {
- fw_error("Failed to set Link Power Status\n");
+ ohci_err(ohci, "failed to set Link Power Status\n");
return -EIO;
}
@@ -2244,7 +2324,7 @@ static int ohci_enable(struct fw_card *card,
if (ret < 0)
return ret;
if (ret)
- fw_notify("local TSB41BA3D phy\n");
+ ohci_notice(ohci, "local TSB41BA3D phy\n");
else
ohci->quirks &= ~QUIRK_TI_SLLZ059;
}
@@ -2263,9 +2343,12 @@ static int ohci_enable(struct fw_card *card,
(OHCI1394_MAX_PHYS_RESP_RETRIES << 8) |
(200 << 16));
- seconds = lower_32_bits(get_seconds());
- reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
- ohci->bus_time = seconds & ~0x3f;
+ ohci->bus_time_running = false;
+
+ for (i = 0; i < 32; i++)
+ if (ohci->ir_context_support & (1 << i))
+ reg_write(ohci, OHCI1394_IsoRcvContextControlClear(i),
+ IR_CONTEXT_MULTI_CHANNEL_MODE);
version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
if (version >= OHCI_VERSION_1_1) {
@@ -2280,7 +2363,7 @@ static int ohci_enable(struct fw_card *card,
reg_write(ohci, OHCI1394_FairnessControl, 0);
card->priority_budget_implemented = ohci->pri_req_max != 0;
- reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
+ reg_write(ohci, OHCI1394_PhyUpperBound, FW_MAX_PHYSICAL_RANGE >> 16);
reg_write(ohci, OHCI1394_IntEventClear, ~0);
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
@@ -2339,30 +2422,12 @@ static int ohci_enable(struct fw_card *card,
reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
- if (!(ohci->quirks & QUIRK_NO_MSI))
- pci_enable_msi(dev);
- 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);
- pci_disable_msi(dev);
-
- if (config_rom) {
- dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
- ohci->next_config_rom,
- ohci->next_config_rom_bus);
- ohci->next_config_rom = NULL;
- }
- return -EIO;
- }
-
irqs = OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
OHCI1394_RQPkt | OHCI1394_RSPkt |
OHCI1394_isochTx | OHCI1394_isochRx |
OHCI1394_postedWriteErr |
OHCI1394_selfIDComplete |
OHCI1394_regAccessFail |
- OHCI1394_cycle64Seconds |
OHCI1394_cycleInconsistent |
OHCI1394_unrecoverableError |
OHCI1394_cycleTooLong |
@@ -2394,7 +2459,6 @@ static int ohci_set_config_rom(struct fw_card *card,
const __be32 *config_rom, size_t length)
{
struct fw_ohci *ohci;
- unsigned long flags;
__be32 *next_config_rom;
dma_addr_t uninitialized_var(next_config_rom_bus);
@@ -2433,7 +2497,7 @@ static int ohci_set_config_rom(struct fw_card *card,
if (next_config_rom == NULL)
return -ENOMEM;
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
/*
* If there is not an already pending config_rom update,
@@ -2459,7 +2523,7 @@ static int ohci_set_config_rom(struct fw_card *card,
reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus);
- spin_unlock_irqrestore(&ohci->lock, flags);
+ spin_unlock_irq(&ohci->lock);
/* If we didn't use the DMA allocation, delete it. */
if (next_config_rom != NULL)
@@ -2509,7 +2573,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);
@@ -2523,13 +2587,13 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
static int ohci_enable_phys_dma(struct fw_card *card,
int node_id, int generation)
{
-#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA
- return 0;
-#else
struct fw_ohci *ohci = fw_ohci(card);
unsigned long flags;
int n, ret = 0;
+ if (param_remote_dma)
+ return 0;
+
/*
* FIXME: Make sure this bitmask is cleared when we clear the busReset
* interrupt bit. Clear physReqResourceAllBuses on bus reset.
@@ -2558,7 +2622,6 @@ static int ohci_enable_phys_dma(struct fw_card *card,
spin_unlock_irqrestore(&ohci->lock, flags);
return ret;
-#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
}
static u32 ohci_read_csr(struct fw_card *card, int csr_offset)
@@ -2652,7 +2715,8 @@ static void ohci_write_csr(struct fw_card *card, int csr_offset, u32 value)
case CSR_BUS_TIME:
spin_lock_irqsave(&ohci->lock, flags);
- ohci->bus_time = (ohci->bus_time & 0x7f) | (value & ~0x7f);
+ ohci->bus_time = (update_bus_time(ohci) & 0x40) |
+ (value & ~0x7f);
spin_unlock_irqrestore(&ohci->lock, flags);
break;
@@ -2674,25 +2738,38 @@ 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) {
+ if (ctx->base.drop_overflow_headers)
+ return;
+ 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 +2781,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 +2799,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 +2814,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 +2902,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 +2914,22 @@ 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) {
+ if (ctx->base.drop_overflow_headers)
+ return 1;
+ 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;
}
@@ -2861,10 +2953,9 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
descriptor_callback_t uninitialized_var(callback);
u64 *uninitialized_var(channels);
u32 *uninitialized_var(mask), uninitialized_var(regs);
- unsigned long flags;
int index, ret = -EBUSY;
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
switch (type) {
case FW_ISO_CONTEXT_TRANSMIT:
@@ -2908,7 +2999,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
ret = -ENOSYS;
}
- spin_unlock_irqrestore(&ohci->lock, flags);
+ spin_unlock_irq(&ohci->lock);
if (index < 0)
return ERR_PTR(ret);
@@ -2924,15 +3015,17 @@ 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;
out_with_header:
free_page((unsigned long)ctx->header);
out:
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
switch (type) {
case FW_ISO_CONTEXT_RECEIVE:
@@ -2945,7 +3038,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
}
*mask |= 1 << index;
- spin_unlock_irqrestore(&ohci->lock, flags);
+ spin_unlock_irq(&ohci->lock);
return ERR_PTR(ret);
}
@@ -3387,6 +3480,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_atomic();
+ }
+
+ 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 +3530,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,
};
@@ -3437,7 +3564,7 @@ static inline void pmac_ohci_on(struct pci_dev *dev) {}
static inline void pmac_ohci_off(struct pci_dev *dev) {}
#endif /* CONFIG_PPC_PMAC */
-static int __devinit pci_probe(struct pci_dev *dev,
+static int pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
struct fw_ohci *ohci;
@@ -3463,7 +3590,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;
}
@@ -3476,15 +3603,22 @@ static int __devinit pci_probe(struct pci_dev *dev,
INIT_WORK(&ohci->bus_reset_work, bus_reset_work);
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM) ||
+ pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE) {
+ ohci_err(ohci, "invalid MMIO resource\n");
+ err = -ENXIO;
+ goto fail_disable;
+ }
+
err = pci_request_region(dev, 0, ohci_driver_name);
if (err) {
- fw_error("MMIO resource unavailable\n");
+ ohci_err(ohci, "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");
+ ohci_err(ohci, "failed to remap registers\n");
err = -ENXIO;
goto fail_iomem;
}
@@ -3559,7 +3693,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
goto fail_contexts;
}
- ohci->self_id_cpu = ohci->misc_buffer + PAGE_SIZE/2;
+ ohci->self_id = ohci->misc_buffer + PAGE_SIZE/2;
ohci->self_id_bus = ohci->misc_buffer_bus + PAGE_SIZE/2;
bus_options = reg_read(ohci, OHCI1394_BusOptions);
@@ -3568,18 +3702,35 @@ static int __devinit pci_probe(struct pci_dev *dev,
guid = ((u64) reg_read(ohci, OHCI1394_GUIDHi) << 32) |
reg_read(ohci, OHCI1394_GUIDLo);
+ if (!(ohci->quirks & QUIRK_NO_MSI))
+ pci_enable_msi(dev);
+ if (request_irq(dev->irq, irq_handler,
+ pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED,
+ ohci_driver_name, ohci)) {
+ ohci_err(ohci, "failed to allocate interrupt %d\n", dev->irq);
+ err = -EIO;
+ goto fail_msi;
+ }
+
err = fw_card_add(&ohci->card, max_receive, link_speed, guid);
if (err)
- goto fail_contexts;
+ goto fail_irq;
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,
- ohci->n_ir, ohci->n_it, ohci->quirks);
+ ohci_notice(ohci,
+ "added OHCI v%x.%x device as card %d, "
+ "%d IR + %d IT contexts, quirks 0x%x%s\n",
+ version >> 16, version & 0xff, ohci->card.index,
+ ohci->n_ir, ohci->n_it, ohci->quirks,
+ reg_read(ohci, OHCI1394_PhyUpperBound) ?
+ ", physUB" : "");
return 0;
+ fail_irq:
+ free_irq(dev->irq, ohci);
+ fail_msi:
+ pci_disable_msi(dev);
fail_contexts:
kfree(ohci->ir_context_list);
kfree(ohci->it_context_list);
@@ -3603,19 +3754,21 @@ static int __devinit pci_probe(struct pci_dev *dev,
kfree(ohci);
pmac_ohci_off(dev);
fail:
- if (err == -ENOMEM)
- fw_error("Out of memory\n");
-
return err;
}
static void pci_remove(struct pci_dev *dev)
{
- struct fw_ohci *ohci;
+ struct fw_ohci *ohci = pci_get_drvdata(dev);
- ohci = pci_get_drvdata(dev);
- reg_write(ohci, OHCI1394_IntMaskClear, ~0);
- flush_writes(ohci);
+ /*
+ * If the removal is happening from the suspend state, LPS won't be
+ * enabled and host registers (eg., IntMaskClear) won't be accessible.
+ */
+ if (reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS) {
+ reg_write(ohci, OHCI1394_IntMaskClear, ~0);
+ flush_writes(ohci);
+ }
cancel_work_sync(&ohci->bus_reset_work);
fw_core_remove_card(&ohci->card);
@@ -3648,7 +3801,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
@@ -3658,16 +3811,14 @@ static int pci_suspend(struct pci_dev *dev, pm_message_t state)
int err;
software_reset(ohci);
- free_irq(dev->irq, ohci);
- pci_disable_msi(dev);
err = pci_save_state(dev);
if (err) {
- fw_error("pci_save_state failed\n");
+ ohci_err(ohci, "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);
+ ohci_err(ohci, "pci_set_power_state failed with %d\n", err);
pmac_ohci_off(dev);
return 0;
@@ -3683,7 +3834,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");
+ ohci_err(ohci, "pci_enable_device failed\n");
return err;
}
@@ -3722,24 +3873,27 @@ static struct pci_driver fw_ohci_pci_driver = {
#endif
};
-MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
-MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers");
-MODULE_LICENSE("GPL");
-
-/* Provide a module alias so root-on-sbp2 initrds don't break. */
-#ifndef CONFIG_IEEE1394_OHCI1394_MODULE
-MODULE_ALIAS("ohci1394");
-#endif
-
static int __init fw_ohci_init(void)
{
+ selfid_workqueue = alloc_workqueue(KBUILD_MODNAME, WQ_MEM_RECLAIM, 0);
+ if (!selfid_workqueue)
+ return -ENOMEM;
+
return pci_register_driver(&fw_ohci_pci_driver);
}
static void __exit fw_ohci_cleanup(void)
{
pci_unregister_driver(&fw_ohci_pci_driver);
+ destroy_workqueue(selfid_workqueue);
}
module_init(fw_ohci_init);
module_exit(fw_ohci_cleanup);
+
+MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
+MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers");
+MODULE_LICENSE("GPL");
+
+/* Provide a module alias so root-on-sbp2 initrds don't break. */
+MODULE_ALIAS("ohci1394");