diff options
Diffstat (limited to 'drivers/firewire/ohci.c')
-rw-r--r-- | drivers/firewire/ohci.c | 85 |
1 files changed, 64 insertions, 21 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index bd3c61b6dd8..f903d7b6f34 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -208,9 +208,11 @@ struct fw_ohci { | |||
208 | struct context at_request_ctx; | 208 | struct context at_request_ctx; |
209 | struct context at_response_ctx; | 209 | struct context at_response_ctx; |
210 | 210 | ||
211 | u32 it_context_support; | ||
211 | u32 it_context_mask; /* unoccupied IT contexts */ | 212 | u32 it_context_mask; /* unoccupied IT contexts */ |
212 | struct iso_context *it_context_list; | 213 | struct iso_context *it_context_list; |
213 | u64 ir_context_channels; /* unoccupied channels */ | 214 | u64 ir_context_channels; /* unoccupied channels */ |
215 | u32 ir_context_support; | ||
214 | u32 ir_context_mask; /* unoccupied IR contexts */ | 216 | u32 ir_context_mask; /* unoccupied IR contexts */ |
215 | struct iso_context *ir_context_list; | 217 | struct iso_context *ir_context_list; |
216 | u64 mc_channels; /* channels in use by the multichannel IR context */ | 218 | u64 mc_channels; /* channels in use by the multichannel IR context */ |
@@ -338,7 +340,7 @@ static void log_irqs(u32 evt) | |||
338 | !(evt & OHCI1394_busReset)) | 340 | !(evt & OHCI1394_busReset)) |
339 | return; | 341 | return; |
340 | 342 | ||
341 | fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, | 343 | fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, |
342 | evt & OHCI1394_selfIDComplete ? " selfID" : "", | 344 | evt & OHCI1394_selfIDComplete ? " selfID" : "", |
343 | evt & OHCI1394_RQPkt ? " AR_req" : "", | 345 | evt & OHCI1394_RQPkt ? " AR_req" : "", |
344 | evt & OHCI1394_RSPkt ? " AR_resp" : "", | 346 | evt & OHCI1394_RSPkt ? " AR_resp" : "", |
@@ -351,6 +353,7 @@ static void log_irqs(u32 evt) | |||
351 | evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "", | 353 | evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "", |
352 | evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "", | 354 | evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "", |
353 | evt & OHCI1394_regAccessFail ? " regAccessFail" : "", | 355 | evt & OHCI1394_regAccessFail ? " regAccessFail" : "", |
356 | evt & OHCI1394_unrecoverableError ? " unrecoverableError" : "", | ||
354 | evt & OHCI1394_busReset ? " busReset" : "", | 357 | evt & OHCI1394_busReset ? " busReset" : "", |
355 | evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | | 358 | evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | |
356 | OHCI1394_RSPkt | OHCI1394_reqTxComplete | | 359 | OHCI1394_RSPkt | OHCI1394_reqTxComplete | |
@@ -1326,21 +1329,8 @@ static int at_context_queue_packet(struct context *ctx, | |||
1326 | DESCRIPTOR_IRQ_ALWAYS | | 1329 | DESCRIPTOR_IRQ_ALWAYS | |
1327 | DESCRIPTOR_BRANCH_ALWAYS); | 1330 | DESCRIPTOR_BRANCH_ALWAYS); |
1328 | 1331 | ||
1329 | /* | 1332 | /* FIXME: Document how the locking works. */ |
1330 | * If the controller and packet generations don't match, we need to | 1333 | if (ohci->generation != packet->generation) { |
1331 | * bail out and try again. If IntEvent.busReset is set, the AT context | ||
1332 | * is halted, so appending to the context and trying to run it is | ||
1333 | * futile. Most controllers do the right thing and just flush the AT | ||
1334 | * queue (per section 7.2.3.2 of the OHCI 1.1 specification), but | ||
1335 | * some controllers (like a JMicron JMB381 PCI-e) misbehave and wind | ||
1336 | * up stalling out. So we just bail out in software and try again | ||
1337 | * later, and everyone is happy. | ||
1338 | * FIXME: Test of IntEvent.busReset may no longer be necessary since we | ||
1339 | * flush AT queues in bus_reset_tasklet. | ||
1340 | * FIXME: Document how the locking works. | ||
1341 | */ | ||
1342 | if (ohci->generation != packet->generation || | ||
1343 | reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { | ||
1344 | if (packet->payload_mapped) | 1334 | if (packet->payload_mapped) |
1345 | dma_unmap_single(ohci->card.device, payload_bus, | 1335 | dma_unmap_single(ohci->card.device, payload_bus, |
1346 | packet->payload_length, DMA_TO_DEVICE); | 1336 | packet->payload_length, DMA_TO_DEVICE); |
@@ -1590,6 +1580,47 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet) | |||
1590 | 1580 | ||
1591 | } | 1581 | } |
1592 | 1582 | ||
1583 | static void detect_dead_context(struct fw_ohci *ohci, | ||
1584 | const char *name, unsigned int regs) | ||
1585 | { | ||
1586 | u32 ctl; | ||
1587 | |||
1588 | ctl = reg_read(ohci, CONTROL_SET(regs)); | ||
1589 | if (ctl & CONTEXT_DEAD) { | ||
1590 | #ifdef CONFIG_FIREWIRE_OHCI_DEBUG | ||
1591 | fw_error("DMA context %s has stopped, error code: %s\n", | ||
1592 | name, evts[ctl & 0x1f]); | ||
1593 | #else | ||
1594 | fw_error("DMA context %s has stopped, error code: %#x\n", | ||
1595 | name, ctl & 0x1f); | ||
1596 | #endif | ||
1597 | } | ||
1598 | } | ||
1599 | |||
1600 | static void handle_dead_contexts(struct fw_ohci *ohci) | ||
1601 | { | ||
1602 | unsigned int i; | ||
1603 | char name[8]; | ||
1604 | |||
1605 | detect_dead_context(ohci, "ATReq", OHCI1394_AsReqTrContextBase); | ||
1606 | detect_dead_context(ohci, "ATRsp", OHCI1394_AsRspTrContextBase); | ||
1607 | detect_dead_context(ohci, "ARReq", OHCI1394_AsReqRcvContextBase); | ||
1608 | detect_dead_context(ohci, "ARRsp", OHCI1394_AsRspRcvContextBase); | ||
1609 | for (i = 0; i < 32; ++i) { | ||
1610 | if (!(ohci->it_context_support & (1 << i))) | ||
1611 | continue; | ||
1612 | sprintf(name, "IT%u", i); | ||
1613 | detect_dead_context(ohci, name, OHCI1394_IsoXmitContextBase(i)); | ||
1614 | } | ||
1615 | for (i = 0; i < 32; ++i) { | ||
1616 | if (!(ohci->ir_context_support & (1 << i))) | ||
1617 | continue; | ||
1618 | sprintf(name, "IR%u", i); | ||
1619 | detect_dead_context(ohci, name, OHCI1394_IsoRcvContextBase(i)); | ||
1620 | } | ||
1621 | /* TODO: maybe try to flush and restart the dead contexts */ | ||
1622 | } | ||
1623 | |||
1593 | static u32 cycle_timer_ticks(u32 cycle_timer) | 1624 | static u32 cycle_timer_ticks(u32 cycle_timer) |
1594 | { | 1625 | { |
1595 | u32 ticks; | 1626 | u32 ticks; |
@@ -1904,6 +1935,9 @@ static irqreturn_t irq_handler(int irq, void *data) | |||
1904 | fw_notify("isochronous cycle inconsistent\n"); | 1935 | fw_notify("isochronous cycle inconsistent\n"); |
1905 | } | 1936 | } |
1906 | 1937 | ||
1938 | if (unlikely(event & OHCI1394_unrecoverableError)) | ||
1939 | handle_dead_contexts(ohci); | ||
1940 | |||
1907 | if (event & OHCI1394_cycle64Seconds) { | 1941 | if (event & OHCI1394_cycle64Seconds) { |
1908 | spin_lock(&ohci->lock); | 1942 | spin_lock(&ohci->lock); |
1909 | update_bus_time(ohci); | 1943 | update_bus_time(ohci); |
@@ -2141,7 +2175,9 @@ static int ohci_enable(struct fw_card *card, | |||
2141 | OHCI1394_selfIDComplete | | 2175 | OHCI1394_selfIDComplete | |
2142 | OHCI1394_regAccessFail | | 2176 | OHCI1394_regAccessFail | |
2143 | OHCI1394_cycle64Seconds | | 2177 | OHCI1394_cycle64Seconds | |
2144 | OHCI1394_cycleInconsistent | OHCI1394_cycleTooLong | | 2178 | OHCI1394_cycleInconsistent | |
2179 | OHCI1394_unrecoverableError | | ||
2180 | OHCI1394_cycleTooLong | | ||
2145 | OHCI1394_masterIntEnable; | 2181 | OHCI1394_masterIntEnable; |
2146 | if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) | 2182 | if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) |
2147 | irqs |= OHCI1394_busReset; | 2183 | irqs |= OHCI1394_busReset; |
@@ -2657,6 +2693,10 @@ static int ohci_start_iso(struct fw_iso_context *base, | |||
2657 | u32 control = IR_CONTEXT_ISOCH_HEADER, match; | 2693 | u32 control = IR_CONTEXT_ISOCH_HEADER, match; |
2658 | int index; | 2694 | int index; |
2659 | 2695 | ||
2696 | /* the controller cannot start without any queued packets */ | ||
2697 | if (ctx->context.last->branch_address == 0) | ||
2698 | return -ENODATA; | ||
2699 | |||
2660 | switch (ctx->base.type) { | 2700 | switch (ctx->base.type) { |
2661 | case FW_ISO_CONTEXT_TRANSMIT: | 2701 | case FW_ISO_CONTEXT_TRANSMIT: |
2662 | index = ctx - ohci->it_context_list; | 2702 | index = ctx - ohci->it_context_list; |
@@ -2715,6 +2755,7 @@ static int ohci_stop_iso(struct fw_iso_context *base) | |||
2715 | } | 2755 | } |
2716 | flush_writes(ohci); | 2756 | flush_writes(ohci); |
2717 | context_stop(&ctx->context); | 2757 | context_stop(&ctx->context); |
2758 | tasklet_kill(&ctx->context.tasklet); | ||
2718 | 2759 | ||
2719 | return 0; | 2760 | return 0; |
2720 | } | 2761 | } |
@@ -3207,15 +3248,17 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
3207 | 3248 | ||
3208 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); | 3249 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); |
3209 | ohci->ir_context_channels = ~0ULL; | 3250 | ohci->ir_context_channels = ~0ULL; |
3210 | ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); | 3251 | ohci->ir_context_support = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); |
3211 | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); | 3252 | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); |
3253 | ohci->ir_context_mask = ohci->ir_context_support; | ||
3212 | ohci->n_ir = hweight32(ohci->ir_context_mask); | 3254 | ohci->n_ir = hweight32(ohci->ir_context_mask); |
3213 | size = sizeof(struct iso_context) * ohci->n_ir; | 3255 | size = sizeof(struct iso_context) * ohci->n_ir; |
3214 | ohci->ir_context_list = kzalloc(size, GFP_KERNEL); | 3256 | ohci->ir_context_list = kzalloc(size, GFP_KERNEL); |
3215 | 3257 | ||
3216 | reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); | 3258 | reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); |
3217 | ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); | 3259 | ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); |
3218 | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); | 3260 | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); |
3261 | ohci->it_context_mask = ohci->it_context_support; | ||
3219 | ohci->n_it = hweight32(ohci->it_context_mask); | 3262 | ohci->n_it = hweight32(ohci->it_context_mask); |
3220 | size = sizeof(struct iso_context) * ohci->n_it; | 3263 | size = sizeof(struct iso_context) * ohci->n_it; |
3221 | ohci->it_context_list = kzalloc(size, GFP_KERNEL); | 3264 | ohci->it_context_list = kzalloc(size, GFP_KERNEL); |
@@ -3266,7 +3309,7 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
3266 | fail_disable: | 3309 | fail_disable: |
3267 | pci_disable_device(dev); | 3310 | pci_disable_device(dev); |
3268 | fail_free: | 3311 | fail_free: |
3269 | kfree(&ohci->card); | 3312 | kfree(ohci); |
3270 | pmac_ohci_off(dev); | 3313 | pmac_ohci_off(dev); |
3271 | fail: | 3314 | fail: |
3272 | if (err == -ENOMEM) | 3315 | if (err == -ENOMEM) |
@@ -3310,7 +3353,7 @@ static void pci_remove(struct pci_dev *dev) | |||
3310 | pci_iounmap(dev, ohci->registers); | 3353 | pci_iounmap(dev, ohci->registers); |
3311 | pci_release_region(dev, 0); | 3354 | pci_release_region(dev, 0); |
3312 | pci_disable_device(dev); | 3355 | pci_disable_device(dev); |
3313 | kfree(&ohci->card); | 3356 | kfree(ohci); |
3314 | pmac_ohci_off(dev); | 3357 | pmac_ohci_off(dev); |
3315 | 3358 | ||
3316 | fw_notify("Removed fw-ohci device.\n"); | 3359 | fw_notify("Removed fw-ohci device.\n"); |