Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+25 −5
Original line number Original line Diff line number Diff line
@@ -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)
			}
			}
			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)


	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)
{
{
	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)


	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;
}
}