Commit 9a4d93d4 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Russell King

[ARM] 4295/2: Fix error-handling in pxaficp_ir.c (version 2)

This patch addresses the following issues with the pxa2xx FIr driver:

1. increment overrun error counter and not frame error counter on ICSR1_ROR bit set in ICSR1.
2. drop frames reported with the frame error from the IC.
3. when resetting the receiver and preparing it for the next DMA in pxa_irda_fir_irq() actually clear the Rx FIFO. See description in Table 11-2 in PXA270 Developer's Manual of the RXE bit.

Correction added in version 2: clearing the IC Rx FIFO also has to be done in pxa_irda_fir_dma_tx_irq()
Signed-off-by: default avatarG. Liakhovetski <gl@dsa-ac.de>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 6c330ba7
...@@ -321,15 +321,22 @@ static void pxa_irda_fir_dma_tx_irq(int channel, void *data) ...@@ -321,15 +321,22 @@ static void pxa_irda_fir_dma_tx_irq(int channel, void *data)
pxa_irda_set_speed(si, si->newspeed); pxa_irda_set_speed(si, si->newspeed);
si->newspeed = 0; si->newspeed = 0;
} else { } else {
int i = 64;
ICCR0 = 0; ICCR0 = 0;
pxa_irda_fir_dma_rx_start(si); pxa_irda_fir_dma_rx_start(si);
while ((ICSR1 & ICSR1_RNE) && i--)
(void)ICDR;
ICCR0 = ICCR0_ITR | ICCR0_RXE; ICCR0 = ICCR0_ITR | ICCR0_RXE;
if (i < 0)
printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n");
} }
netif_wake_queue(dev); netif_wake_queue(dev);
} }
/* EIF(Error in FIFO/End in Frame) handler for FIR */ /* EIF(Error in FIFO/End in Frame) handler for FIR */
static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev) static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, int icsr0)
{ {
unsigned int len, stat, data; unsigned int len, stat, data;
...@@ -350,7 +357,7 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev) ...@@ -350,7 +357,7 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev)
} }
if (stat & ICSR1_ROR) { if (stat & ICSR1_ROR) {
printk(KERN_DEBUG "pxa_ir: fir receive overrun\n"); printk(KERN_DEBUG "pxa_ir: fir receive overrun\n");
si->stats.rx_frame_errors++; si->stats.rx_over_errors++;
} }
} else { } else {
si->dma_rx_buff[len++] = data; si->dma_rx_buff[len++] = data;
...@@ -362,7 +369,15 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev) ...@@ -362,7 +369,15 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev)
if (stat & ICSR1_EOF) { if (stat & ICSR1_EOF) {
/* end of frame. */ /* end of frame. */
struct sk_buff *skb = alloc_skb(len+1,GFP_ATOMIC); struct sk_buff *skb;
if (icsr0 & ICSR0_FRE) {
printk(KERN_ERR "pxa_ir: dropping erroneous frame\n");
si->stats.rx_dropped++;
return;
}
skb = alloc_skb(len+1,GFP_ATOMIC);
if (!skb) { if (!skb) {
printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n"); printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n");
si->stats.rx_dropped++; si->stats.rx_dropped++;
...@@ -392,7 +407,7 @@ static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id) ...@@ -392,7 +407,7 @@ static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id)
{ {
struct net_device *dev = dev_id; struct net_device *dev = dev_id;
struct pxa_irda *si = netdev_priv(dev); struct pxa_irda *si = netdev_priv(dev);
int icsr0; int icsr0, i = 64;
/* stop RX DMA */ /* stop RX DMA */
DCSR(si->rxdma) &= ~DCSR_RUN; DCSR(si->rxdma) &= ~DCSR_RUN;
...@@ -412,13 +427,18 @@ static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id) ...@@ -412,13 +427,18 @@ static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id)
if (icsr0 & ICSR0_EIF) { if (icsr0 & ICSR0_EIF) {
/* An error in FIFO occured, or there is a end of frame */ /* An error in FIFO occured, or there is a end of frame */
pxa_irda_fir_irq_eif(si, dev); pxa_irda_fir_irq_eif(si, dev, icsr0);
} }
ICCR0 = 0; ICCR0 = 0;
pxa_irda_fir_dma_rx_start(si); pxa_irda_fir_dma_rx_start(si);
while ((ICSR1 & ICSR1_RNE) && i--)
(void)ICDR;
ICCR0 = ICCR0_ITR | ICCR0_RXE; ICCR0 = ICCR0_ITR | ICCR0_RXE;
if (i < 0)
printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n");
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment