wcxb: Reset TDM engine on IO errors.

There are error conditions that the firmware can detect but cannot recover from
without help from the driver. When firmware detects these conditions the
DESC_IO_ERROR bit will be set in the descriptor header to signal that the driver
should reset the TDM engine on the card. Since this is not due to failure of the
host to service the interrupt in time, it does not make sense to increase
latency when these conditions are detected.

Internal-Issue-ID: DAHDI-1087
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
This commit is contained in:
Shaun Ruffell
2014-03-11 23:41:44 -05:00
parent b817c7625a
commit 665bf9feb6
2 changed files with 32 additions and 3 deletions

View File

@@ -62,6 +62,7 @@
#define DRING_SIZE_MASK (DRING_SIZE-1)
#define DESC_EOR (1 << 0)
#define DESC_INT (1 << 1)
#define DESC_IO_ERROR (1 << 30)
#define DESC_OWN (1 << 31)
#define DESC_DEFAULT_STATUS 0xdeadbeef
#define DMA_CHAN_SIZE 128
@@ -357,10 +358,28 @@ static void _wcxb_reset_dring(struct wcxb *xb)
static void wcxb_handle_dma(struct wcxb *xb)
{
struct wcxb_meta_desc *mdesc;
struct wcxb_hw_desc *tail = &(xb->hw_dring[xb->dma_tail]);
while (!(xb->hw_dring[xb->dma_tail].control & cpu_to_be32(DESC_OWN))) {
while (!(tail->control & cpu_to_be32(DESC_OWN))) {
u_char *frame;
if (tail->control & cpu_to_be32(DESC_IO_ERROR)) {
u32 ier;
unsigned long flags;
/* The firmware detected an error condition on the bus.
* Force an underrun by disabling the descriptor
* complete interrupt. When the driver processes the
* underrun it will reset the TDM engine. */
xb->flags.io_error = 1;
spin_lock_irqsave(&xb->lock, flags);
ier = ioread32be(xb->membase + IER);
iowrite32be(ier & ~DESC_COMPLETE, xb->membase + IER);
spin_unlock_irqrestore(&xb->lock, flags);
return;
}
mdesc = &xb->meta_dring[xb->dma_tail];
frame = mdesc->rx_buf_virt;
@@ -368,6 +387,7 @@ static void wcxb_handle_dma(struct wcxb *xb)
xb->dma_tail =
(xb->dma_tail == xb->latency-1) ? 0 : xb->dma_tail + 1;
tail = &(xb->hw_dring[xb->dma_tail]);
mdesc = &xb->meta_dring[xb->dma_head];
frame = mdesc->tx_buf_virt;
@@ -403,10 +423,18 @@ static irqreturn_t _wcxb_isr(int irq, void *dev_id)
if (xb->ops->handle_error)
xb->ops->handle_error(xb);
/* bump latency */
spin_lock(&xb->lock);
if (!xb->flags.latency_locked) {
if (xb->flags.io_error) {
/* Since an IO error is not necessarily because
* the host could not keep up, we do not want to
* bump the latency. */
xb->flags.io_error = 0;
dev_warn(&xb->pdev->dev,
"IO error reported by firmware.\n");
} else if (!xb->flags.latency_locked) {
/* bump latency */
xb->latency = min(xb->latency + 1,
xb->max_latency);
#ifdef HAVE_RATELIMIT

View File

@@ -61,6 +61,7 @@ struct wcxb {
#ifdef WCXB_PCI_DEV_DOES_NOT_HAVE_IS_PCIE
u32 is_pcie:1;
#endif
u32 io_error:1;
} flags;
void __iomem *membase;
struct wcxb_meta_desc *meta_dring;