struct tasklet_struct bus_reset_tasklet;
int node_id;
int generation;
- int request_generation;
+ int request_generation; /* for timestamping incoming requests */
u32 bus_seconds;
bool old_uninorth;
+ bool bus_reset_packet_quirk;
/*
* Spinlock for accessing fw_ohci data. Never call out of
#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
-#define OHCI_PARAM_DEBUG_IRQS 1
+#define OHCI_PARAM_DEBUG_AT_AR 1
#define OHCI_PARAM_DEBUG_SELFIDS 2
-#define OHCI_PARAM_DEBUG_AT_AR 4
+#define OHCI_PARAM_DEBUG_IRQS 4
+#define OHCI_PARAM_DEBUG_BUSRESETS 8 /* only effective before chip init */
static int param_debug;
module_param_named(debug, param_debug, int, 0644);
MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
- ", IRQs = " __stringify(OHCI_PARAM_DEBUG_IRQS)
- ", self-IDs = " __stringify(OHCI_PARAM_DEBUG_SELFIDS)
", AT/AR events = " __stringify(OHCI_PARAM_DEBUG_AT_AR)
+ ", self-IDs = " __stringify(OHCI_PARAM_DEBUG_SELFIDS)
+ ", IRQs = " __stringify(OHCI_PARAM_DEBUG_IRQS)
+ ", busReset events = " __stringify(OHCI_PARAM_DEBUG_BUSRESETS)
", or a combination, or all = -1)");
static void log_irqs(u32 evt)
{
- if (likely(!(param_debug & OHCI_PARAM_DEBUG_IRQS)))
+ if (likely(!(param_debug &
+ (OHCI_PARAM_DEBUG_IRQS | OHCI_PARAM_DEBUG_BUSRESETS))))
return;
- printk(KERN_DEBUG KBUILD_MODNAME ": IRQ %08x%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" : "",
- evt & OHCI1394_reqTxComplete ? " AT_req" : "",
- evt & OHCI1394_respTxComplete ? " AT_resp" : "",
- evt & OHCI1394_isochRx ? " IR" : "",
- evt & OHCI1394_isochTx ? " IT" : "",
- evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "",
- evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "",
- evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "",
- evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
- OHCI1394_RSPkt | OHCI1394_reqTxComplete |
- OHCI1394_respTxComplete | OHCI1394_isochRx |
- OHCI1394_isochTx | OHCI1394_postedWriteErr |
- OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds)
+ if (!(param_debug & OHCI_PARAM_DEBUG_IRQS) &&
+ !(evt & OHCI1394_busReset))
+ return;
+
+ fw_notify("IRQ %08x%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" : "",
+ evt & OHCI1394_reqTxComplete ? " AT_req" : "",
+ evt & OHCI1394_respTxComplete ? " AT_resp" : "",
+ evt & OHCI1394_isochRx ? " IR" : "",
+ evt & OHCI1394_isochTx ? " IT" : "",
+ evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "",
+ evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "",
+ evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "",
+ evt & OHCI1394_regAccessFail ? " regAccessFail" : "",
+ evt & OHCI1394_busReset ? " busReset" : "",
+ evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
+ OHCI1394_RSPkt | OHCI1394_reqTxComplete |
+ OHCI1394_respTxComplete | OHCI1394_isochRx |
+ OHCI1394_isochTx | OHCI1394_postedWriteErr |
+ OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
+ OHCI1394_regAccessFail | OHCI1394_busReset)
? " ?" : "");
}
return port[*s >> shift & 3];
}
-static void log_selfids(int generation, int self_id_count, u32 *s)
+static void log_selfids(int node_id, int generation, int self_id_count, u32 *s)
{
if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS)))
return;
- printk(KERN_DEBUG KBUILD_MODNAME ": %d selfIDs, generation %d\n",
- self_id_count, generation);
+ fw_notify("%d selfIDs, generation %d, local node ID %04x\n",
+ self_id_count, generation, node_id);
for (; self_id_count--; ++s)
if ((*s & 1 << 23) == 0)
- printk(KERN_DEBUG "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" : "");
+ fw_notify("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
- printk(KERN_DEBUG "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));
+ fw_notify("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));
}
static const char *evts[] = {
if (unlikely(evt >= ARRAY_SIZE(evts)))
evt = 0x1f;
+ if (evt == OHCI1394_evt_bus_reset) {
+ fw_notify("A%c evt_bus_reset, generation %d\n",
+ dir, (header[2] >> 16) & 0xff);
+ return;
+ }
+
if (header[0] == ~header[1]) {
- printk(KERN_DEBUG "A%c %s, %s, %08x\n",
- dir, evts[evt], phys[header[0] >> 30 & 0x3],
- header[0]);
+ fw_notify("A%c %s, %s, %08x\n",
+ dir, evts[evt], phys[header[0] >> 30 & 0x3], header[0]);
return;
}
switch (tcode) {
case 0xe: case 0xa:
- printk(KERN_DEBUG "A%c %s, %s\n",
- dir, evts[evt], tcodes[tcode]);
+ fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]);
break;
case 0x0: case 0x1: case 0x4: case 0x5: case 0x9:
- printk(KERN_DEBUG "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);
+ 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);
break;
default:
- printk(KERN_DEBUG "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);
+ 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);
}
}
#else
#define log_irqs(evt)
-#define log_selfids(generation, self_id_count, sid)
+#define log_selfids(node_id, generation, self_id_count, sid)
#define log_ar_at_event(dir, speed, header, evt)
#endif /* CONFIG_FIREWIRE_OHCI_DEBUG */
p.header_length = 12;
p.payload_length = 0;
break;
+
+ default:
+ /* FIXME: Stop context, discard everything, and restart? */
+ p.header_length = 0;
+ p.payload_length = 0;
}
p.payload = (void *) buffer + p.header_length;
* generation. We only need this for requests; for responses
* we use the unique tlabel for finding the matching
* request.
+ *
+ * Alas some chips sometimes emit bus reset packets with a
+ * wrong generation. We set the correct generation for these
+ * at a slightly incorrect time (in bus_reset_tasklet).
*/
-
- if (evt == OHCI1394_evt_bus_reset)
- ohci->request_generation = (p.header[2] >> 16) & 0xff;
- else if (ctx == &ohci->ar_request_ctx)
+ if (evt == OHCI1394_evt_bus_reset) {
+ if (!ohci->bus_reset_packet_quirk)
+ ohci->request_generation = (p.header[2] >> 16) & 0xff;
+ } else if (ctx == &ohci->ar_request_ctx) {
fw_core_handle_request(&ohci->card, &p);
- else
+ } else {
fw_core_handle_response(&ohci->card, &p);
+ }
return buffer + length + 1;
}
DESCRIPTOR_IRQ_ALWAYS |
DESCRIPTOR_BRANCH_ALWAYS);
- /* FIXME: Document how the locking works. */
- if (ohci->generation != packet->generation) {
+ /*
+ * 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) {
if (packet->payload_length > 0)
dma_unmap_single(ohci->card.device, payload_bus,
packet->payload_length, DMA_TO_DEVICE);
context_stop(&ohci->at_response_ctx);
reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+ if (ohci->bus_reset_packet_quirk)
+ ohci->request_generation = generation;
+
/*
* This next bit is unrelated to the AT context stuff but we
* have to do it under the spinlock also. If a new config rom
dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
free_rom, free_rom_bus);
- log_selfids(generation, self_id_count, ohci->self_id_buffer);
+ log_selfids(ohci->node_id, generation,
+ self_id_count, ohci->self_id_buffer);
fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
self_id_count, ohci->self_id_buffer);
if (!event || !~event)
return IRQ_NONE;
- reg_write(ohci, OHCI1394_IntEventClear, event);
+ /* busReset must not be cleared yet, see OHCI 1.1 clause 7.2.3.2 */
+ reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
log_irqs(event);
if (event & OHCI1394_selfIDComplete)
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))
fw_error("PCI posted write error\n");
{
struct fw_ohci *ohci = fw_ohci(card);
struct pci_dev *dev = to_pci_dev(card->device);
+ u32 lps;
+ int i;
if (software_reset(ohci)) {
fw_error("Failed to reset ohci card.\n");
* most of the registers. In fact, on some cards (ALI M5251),
* accessing registers in the SClk domain without LPS enabled
* will lock up the machine. Wait 50msec to make sure we have
- * full link enabled.
+ * full link enabled. However, with some cards (well, at least
+ * a JMicron PCIe card), we have to try again sometimes.
*/
reg_write(ohci, OHCI1394_HCControlSet,
OHCI1394_HCControl_LPS |
OHCI1394_HCControl_postedWriteEnable);
flush_writes(ohci);
- msleep(50);
+
+ for (lps = 0, i = 0; !lps && i < 3; i++) {
+ msleep(50);
+ lps = reg_read(ohci, OHCI1394_HCControlSet) &
+ OHCI1394_HCControl_LPS;
+ }
+
+ if (!lps) {
+ fw_error("Failed to set Link Power Status\n");
+ return -EIO;
+ }
reg_write(ohci, OHCI1394_HCControlClear,
OHCI1394_HCControl_noByteSwapData);
+ reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
+ reg_write(ohci, OHCI1394_LinkControlClear,
+ OHCI1394_LinkControl_rcvPhyPkt);
reg_write(ohci, OHCI1394_LinkControlSet,
OHCI1394_LinkControl_rcvSelfID |
OHCI1394_LinkControl_cycleTimerEnable |
ar_context_run(&ohci->ar_request_ctx);
ar_context_run(&ohci->ar_response_ctx);
- reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
reg_write(ohci, OHCI1394_IntEventClear, ~0);
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
OHCI1394_isochRx | OHCI1394_isochTx |
OHCI1394_postedWriteErr | OHCI1394_cycleTooLong |
- OHCI1394_cycle64Seconds | OHCI1394_masterIntEnable);
+ OHCI1394_cycle64Seconds | OHCI1394_regAccessFail |
+ OHCI1394_masterIntEnable);
+ if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
+ reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
/* Activate link_on bit and contender bit in our self ID packets.*/
if (ohci_update_phy_reg(card, 4, 0,
}
static const struct fw_card_driver ohci_driver = {
- .name = ohci_driver_name,
.enable = ohci_enable,
.update_phy_reg = ohci_update_phy_reg,
.set_config_rom = ohci_set_config_rom,
ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
#endif
+ ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
+
spin_lock_init(&ohci->lock);
tasklet_init(&ohci->bus_reset_tasklet,