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",
+ if (!(param_debug & OHCI_PARAM_DEBUG_IRQS) &&
+ !(evt & OHCI1394_busReset))
+ return;
+
+ printk(KERN_DEBUG KBUILD_MODNAME ": 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_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_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);
+ printk(KERN_DEBUG KBUILD_MODNAME ": %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)
if (unlikely(evt >= ARRAY_SIZE(evts)))
evt = 0x1f;
+ if (evt == OHCI1394_evt_bus_reset) {
+ printk(KERN_DEBUG "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],
#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);
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,
int err;
size_t size;
- ohci_pmac_on(dev);
-
ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);
if (ohci == NULL) {
fw_error("Could not malloc fw_ohci data.\n");
fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev);
+ ohci_pmac_on(dev);
+
err = pci_enable_device(dev);
if (err) {
fw_error("Failed to enable OHCI hardware.\n");
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,
pci_disable_device(dev);
fail_free:
kfree(&ohci->card);
+ ohci_pmac_off(dev);
return err;
}