wcxb: Fix "I/O error reported by firmware" followed by underruns

The cards affected include the TE131/3, TE235/435, A4B, and A8B.

Update all PCIe cards' firmware to increase the incoming and outgoing TDM FIFOs
to 16ms. The FIFOs will only be filled to a depth equal to the driver's latency
setting (ie. 3ms default). The total system latency is not effected. The
firmware and driver now also report the maximum DMA transaction time when in
DEBUG mode to aid in determining if the system is experiencing long PCIe
transactions (ie. TLP completion timeouts).

Decreased the maximum latency to from 20 to 12ms

Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
(cherry picked from commit ae5fa08abd)
This commit is contained in:
John Sloan 2015-02-13 14:46:22 -06:00 committed by Russ Meyerriecks
parent b6fe19cff5
commit 4305b44108
6 changed files with 30 additions and 47 deletions

View File

@ -31,14 +31,14 @@ VPMADT032_VERSION:=1.25.0
HX8_VERSION:=2.06
VPMOCT032_VERSION:=1.12.0
WCT820_VERSION:=1.76
TE133_VERSION:=780019
TE133_VERSION:=7a001e
TE134_VERSION:=780017
TE435_VERSION:=e0019
TE435_VERSION:=13001e
TE436_VERSION:=10017
A8A_VERSION:=1d0017
A8B_VERSION:=1d0019
A8B_VERSION:=1f001e
A4A_VERSION:=a0017
A4B_VERSION:=b0019
A4B_VERSION:=d001e
FIRMWARE_URL:=http://downloads.digium.com/pub/telephony/firmware/releases

View File

@ -3886,9 +3886,9 @@ static int wcaxx_check_firmware(struct wcaxx *wc)
u32 firmware_version;
const bool force_firmware = false;
const unsigned int A4A_VERSION = 0x0a0017;
const unsigned int A4B_VERSION = 0x0b0019;
const unsigned int A4B_VERSION = 0x0d001e;
const unsigned int A8A_VERSION = 0x1d0017;
const unsigned int A8B_VERSION = 0x1d0019;
const unsigned int A8B_VERSION = 0x1f001e;
if (wc->desc == &device_a8a) {
firmware_version = A8A_VERSION;

View File

@ -45,7 +45,7 @@
static const char *TE133_FW_FILENAME = "dahdi-fw-te133.bin";
static const char *TE134_FW_FILENAME = "dahdi-fw-te134.bin";
static const u32 TE133_FW_VERSION = 0x780019;
static const u32 TE133_FW_VERSION = 0x7a001e;
static const u32 TE134_FW_VERSION = 0x780017;
#define WC_MAX_IFACES 8

View File

@ -66,7 +66,7 @@ static inline int delayed_work_pending(struct work_struct *work)
static const char *TE435_FW_FILENAME = "dahdi-fw-te435.bin";
static const char *TE436_FW_FILENAME = "dahdi-fw-te436.bin";
static const u32 TE435_VERSION = 0xe0019;
static const u32 TE435_VERSION = 0x13001e;
static const u32 TE436_VERSION = 0x10017;
/* #define RPC_RCLK */

View File

@ -66,7 +66,6 @@
#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 0xdeadbe00
#define DMA_CHAN_SIZE 128
@ -358,45 +357,25 @@ static void _wcxb_reset_dring(struct wcxb *xb)
hdesc->control |= cpu_to_be32(DESC_EOR);
#ifdef DEBUG
xb->last_retry_count = 0;
xb->max_retry_count = 0;
xb->last_dma_time = 0;
xb->max_dma_time = 0;
#endif
iowrite32be(xb->hw_dring_phys, xb->membase + TDM_DRING_ADDR);
}
static void wcxb_handle_dma(struct wcxb *xb)
{
#ifdef DEBUG
bool did_retry_dma = false;
u8 retry;
#endif
struct wcxb_meta_desc *mdesc;
struct wcxb_hw_desc *tail = &(xb->hw_dring[xb->dma_tail]);
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;
}
#ifdef DEBUG
retry = be32_to_cpu(tail->status) & 0xff;
if (xb->last_retry_count != retry) {
xb->last_retry_count = retry;
did_retry_dma = true;
}
xb->last_retry_count =
((be32_to_cpu(tail->control) & 0x0000ff00) >> 8);
xb->last_dma_time = (be32_to_cpu(tail->status));
#endif
mdesc = &xb->meta_dring[xb->dma_tail];
@ -420,9 +399,17 @@ static void wcxb_handle_dma(struct wcxb *xb)
}
#ifdef DEBUG
if (did_retry_dma) {
if (xb->last_retry_count > xb->max_retry_count) {
xb->max_retry_count = xb->last_retry_count;
dev_info(&xb->pdev->dev,
"DMA retries detected: %d\n", xb->last_retry_count);
"New DMA max retries detected: %d\n",
xb->max_retry_count);
}
if (xb->last_dma_time > xb->max_dma_time) {
xb->max_dma_time = xb->last_dma_time;
dev_info(&xb->pdev->dev,
"New DMA max transfer time detected: %d\n",
xb->max_dma_time);
}
#endif
}
@ -451,14 +438,7 @@ static irqreturn_t _wcxb_isr(int irq, void *dev_id)
spin_lock(&xb->lock);
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) {
if (!xb->flags.latency_locked) {
/* bump latency */
xb->latency = min(xb->latency + 1,

View File

@ -24,7 +24,7 @@
#define __WCXB_H__
#define WCXB_DEFAULT_LATENCY 3U
#define WCXB_DEFAULT_MAXLATENCY 20U
#define WCXB_DEFAULT_MAXLATENCY 12U
#define WCXB_DMA_CHAN_SIZE 128
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
@ -66,7 +66,7 @@ struct wcxb {
#ifdef WCXB_PCI_DEV_DOES_NOT_HAVE_IS_PCIE
u32 is_pcie:1;
#endif
u32 io_error:1;
u32 dma_ins:1;
} flags;
void __iomem *membase;
struct wcxb_meta_desc *meta_dring;
@ -78,6 +78,9 @@ struct wcxb {
unsigned long framecount;
#ifdef DEBUG
u8 last_retry_count;
u8 max_retry_count;
u32 last_dma_time;
u32 max_dma_time;
#endif
};