diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2011-01-10 11:21:35 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-01-23 06:31:00 -0500 |
commit | f117a3e3004381ccadadc5156178c283815ca393 (patch) | |
tree | afc150347ea9a50aec8ca7b4677d0267547d183b /drivers/firewire | |
parent | 6044565af458e7fa6e748bff437ecc49dea88d79 (diff) |
firewire: ohci: log dead DMA contexts
When a DMA context goes into the dead state (and the controller thus
stops working correctly), logging this error and the controller's error
code might be helpful for debugging.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/ohci.c | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index bd3c61b6dd8d..c7394361afcb 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 | |
@@ -1590,6 +1593,47 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet) | |||
1590 | 1593 | ||
1591 | } | 1594 | } |
1592 | 1595 | ||
1596 | static void detect_dead_context(struct fw_ohci *ohci, | ||
1597 | const char *name, unsigned int regs) | ||
1598 | { | ||
1599 | u32 ctl; | ||
1600 | |||
1601 | ctl = reg_read(ohci, CONTROL_SET(regs)); | ||
1602 | if (ctl & CONTEXT_DEAD) { | ||
1603 | #ifdef CONFIG_FIREWIRE_OHCI_DEBUG | ||
1604 | fw_error("DMA context %s has stopped, error code: %s\n", | ||
1605 | name, evts[ctl & 0x1f]); | ||
1606 | #else | ||
1607 | fw_error("DMA context %s has stopped, error code: %#x\n", | ||
1608 | name, ctl & 0x1f); | ||
1609 | #endif | ||
1610 | } | ||
1611 | } | ||
1612 | |||
1613 | static void handle_dead_contexts(struct fw_ohci *ohci) | ||
1614 | { | ||
1615 | unsigned int i; | ||
1616 | char name[8]; | ||
1617 | |||
1618 | detect_dead_context(ohci, "ATReq", OHCI1394_AsReqTrContextBase); | ||
1619 | detect_dead_context(ohci, "ATRsp", OHCI1394_AsRspTrContextBase); | ||
1620 | detect_dead_context(ohci, "ARReq", OHCI1394_AsReqRcvContextBase); | ||
1621 | detect_dead_context(ohci, "ARRsp", OHCI1394_AsRspRcvContextBase); | ||
1622 | for (i = 0; i < 32; ++i) { | ||
1623 | if (!(ohci->it_context_support & (1 << i))) | ||
1624 | continue; | ||
1625 | sprintf(name, "IT%u", i); | ||
1626 | detect_dead_context(ohci, name, OHCI1394_IsoXmitContextBase(i)); | ||
1627 | } | ||
1628 | for (i = 0; i < 32; ++i) { | ||
1629 | if (!(ohci->ir_context_support & (1 << i))) | ||
1630 | continue; | ||
1631 | sprintf(name, "IR%u", i); | ||
1632 | detect_dead_context(ohci, name, OHCI1394_IsoRcvContextBase(i)); | ||
1633 | } | ||
1634 | /* TODO: maybe try to flush and restart the dead contexts */ | ||
1635 | } | ||
1636 | |||
1593 | static u32 cycle_timer_ticks(u32 cycle_timer) | 1637 | static u32 cycle_timer_ticks(u32 cycle_timer) |
1594 | { | 1638 | { |
1595 | u32 ticks; | 1639 | u32 ticks; |
@@ -1904,6 +1948,9 @@ static irqreturn_t irq_handler(int irq, void *data) | |||
1904 | fw_notify("isochronous cycle inconsistent\n"); | 1948 | fw_notify("isochronous cycle inconsistent\n"); |
1905 | } | 1949 | } |
1906 | 1950 | ||
1951 | if (unlikely(event & OHCI1394_unrecoverableError)) | ||
1952 | handle_dead_contexts(ohci); | ||
1953 | |||
1907 | if (event & OHCI1394_cycle64Seconds) { | 1954 | if (event & OHCI1394_cycle64Seconds) { |
1908 | spin_lock(&ohci->lock); | 1955 | spin_lock(&ohci->lock); |
1909 | update_bus_time(ohci); | 1956 | update_bus_time(ohci); |
@@ -2141,7 +2188,9 @@ static int ohci_enable(struct fw_card *card, | |||
2141 | OHCI1394_selfIDComplete | | 2188 | OHCI1394_selfIDComplete | |
2142 | OHCI1394_regAccessFail | | 2189 | OHCI1394_regAccessFail | |
2143 | OHCI1394_cycle64Seconds | | 2190 | OHCI1394_cycle64Seconds | |
2144 | OHCI1394_cycleInconsistent | OHCI1394_cycleTooLong | | 2191 | OHCI1394_cycleInconsistent | |
2192 | OHCI1394_unrecoverableError | | ||
2193 | OHCI1394_cycleTooLong | | ||
2145 | OHCI1394_masterIntEnable; | 2194 | OHCI1394_masterIntEnable; |
2146 | if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) | 2195 | if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) |
2147 | irqs |= OHCI1394_busReset; | 2196 | irqs |= OHCI1394_busReset; |
@@ -3207,15 +3256,17 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
3207 | 3256 | ||
3208 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); | 3257 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); |
3209 | ohci->ir_context_channels = ~0ULL; | 3258 | ohci->ir_context_channels = ~0ULL; |
3210 | ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); | 3259 | ohci->ir_context_support = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); |
3211 | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); | 3260 | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); |
3261 | ohci->ir_context_mask = ohci->ir_context_support; | ||
3212 | ohci->n_ir = hweight32(ohci->ir_context_mask); | 3262 | ohci->n_ir = hweight32(ohci->ir_context_mask); |
3213 | size = sizeof(struct iso_context) * ohci->n_ir; | 3263 | size = sizeof(struct iso_context) * ohci->n_ir; |
3214 | ohci->ir_context_list = kzalloc(size, GFP_KERNEL); | 3264 | ohci->ir_context_list = kzalloc(size, GFP_KERNEL); |
3215 | 3265 | ||
3216 | reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); | 3266 | reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); |
3217 | ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); | 3267 | ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); |
3218 | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); | 3268 | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); |
3269 | ohci->it_context_mask = ohci->it_context_support; | ||
3219 | ohci->n_it = hweight32(ohci->it_context_mask); | 3270 | ohci->n_it = hweight32(ohci->it_context_mask); |
3220 | size = sizeof(struct iso_context) * ohci->n_it; | 3271 | size = sizeof(struct iso_context) * ohci->n_it; |
3221 | ohci->it_context_list = kzalloc(size, GFP_KERNEL); | 3272 | ohci->it_context_list = kzalloc(size, GFP_KERNEL); |