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>
This commit is contained in:
parent
6287954087
commit
ae5fa08abd
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user