Commit 968d9bd9 authored by Martin Diehl's avatar Martin Diehl Committed by Stephen Hemminger

[IRDA]: vlsi_ir v0.5 update, 4/7.

* interrupt handler cleanup, focus on fast path and low latency
* rx-path cleanup
* add missing crc16 check of incoming SIR frames
parent 79486734
...@@ -49,6 +49,7 @@ MODULE_LICENSE("GPL"); ...@@ -49,6 +49,7 @@ MODULE_LICENSE("GPL");
#include <net/irda/irda.h> #include <net/irda/irda.h>
#include <net/irda/irda_device.h> #include <net/irda/irda_device.h>
#include <net/irda/wrapper.h> #include <net/irda/wrapper.h>
#include <net/irda/crc.h>
#include <net/irda/vlsi_ir.h> #include <net/irda/vlsi_ir.h>
...@@ -669,32 +670,52 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) ...@@ -669,32 +670,52 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd)
ret |= VLSI_RX_FRAME; ret |= VLSI_RX_FRAME;
if (status & RD_RX_CRCERR) if (status & RD_RX_CRCERR)
ret |= VLSI_RX_CRC; ret |= VLSI_RX_CRC;
goto done;
} }
else {
len = rd_get_count(rd); len = rd_get_count(rd);
crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16); crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16);
len -= crclen; /* remove trailing CRC */ len -= crclen; /* remove trailing CRC */
if (len <= 0) { if (len <= 0) {
WARNING("%s: strange frame (len=%d)\n", __FUNCTION__, len); IRDA_DEBUG(0, "%s: strange frame (len=%d)\n", __FUNCTION__, len);
ret |= VLSI_RX_DROP; ret |= VLSI_RX_DROP;
} goto done;
else if (!rd->skb) { }
WARNING("%s: rx packet dropped\n", __FUNCTION__);
ret |= VLSI_RX_DROP; if (idev->mode == IFF_SIR) { /* hw checks CRC in MIR, FIR mode */
}
else { /* rd->buf is a streaming PCI_DMA_FROMDEVICE map. Doing the
skb = rd->skb; * endian-adjustment there just in place will dirty a cache line
rd->skb = NULL; * which belongs to the map and thus we must be sure it will
skb->dev = ndev; * get flushed before giving the buffer back to hardware.
memcpy(skb_put(skb,len), rd->buf, len); * vlsi_fill_rx() will do this anyway - but here we rely on.
skb->mac.raw = skb->data; */
if (in_interrupt()) le16_to_cpus(rd->buf+len);
netif_rx(skb); if (irda_calc_crc16(INIT_FCS,rd->buf,len+crclen) != GOOD_FCS) {
else IRDA_DEBUG(0, "%s: crc error\n", __FUNCTION__);
netif_rx_ni(skb); ret |= VLSI_RX_CRC;
ndev->last_rx = jiffies; goto done;
} }
} }
if (!rd->skb) {
WARNING("%s: rx packet lost\n", __FUNCTION__);
ret |= VLSI_RX_DROP;
goto done;
}
skb = rd->skb;
rd->skb = NULL;
skb->dev = ndev;
memcpy(skb_put(skb,len), rd->buf, len);
skb->mac.raw = skb->data;
if (in_interrupt())
netif_rx(skb);
else
netif_rx_ni(skb);
ndev->last_rx = jiffies;
done:
rd_set_status(rd, 0); rd_set_status(rd, 0);
rd_set_count(rd, 0); rd_set_count(rd, 0);
/* buffer still owned by CPU */ /* buffer still owned by CPU */
...@@ -1583,38 +1604,33 @@ static irqreturn_t vlsi_interrupt(int irq, void *dev_instance, ...@@ -1583,38 +1604,33 @@ static irqreturn_t vlsi_interrupt(int irq, void *dev_instance,
vlsi_irda_dev_t *idev = ndev->priv; vlsi_irda_dev_t *idev = ndev->priv;
unsigned iobase; unsigned iobase;
u8 irintr; u8 irintr;
int boguscount = 32; int boguscount = 5;
unsigned got_act;
unsigned long flags; unsigned long flags;
int handled = 0; int handled = 0;
got_act = 0;
iobase = ndev->base_addr; iobase = ndev->base_addr;
spin_lock_irqsave(&idev->lock,flags);
do { do {
spin_lock_irqsave(&idev->lock,flags);
irintr = inb(iobase+VLSI_PIO_IRINTR); irintr = inb(iobase+VLSI_PIO_IRINTR);
rmb(); mb();
outb(irintr, iobase+VLSI_PIO_IRINTR); /* acknowledge asap */ outb(irintr, iobase+VLSI_PIO_IRINTR); /* acknowledge asap */
spin_unlock_irqrestore(&idev->lock,flags);
if (!(irintr&=IRINTR_INT_MASK)) /* not our INT - probably shared */ if (!(irintr&=IRINTR_INT_MASK)) /* not our INT - probably shared */
break; break;
handled = 1; handled = 1;
if (unlikely(!(irintr & ~IRINTR_ACTIVITY)))
break; /* nothing todo if only activity */
if (irintr&IRINTR_RPKTINT) if (irintr&IRINTR_RPKTINT)
vlsi_rx_interrupt(ndev); vlsi_rx_interrupt(ndev);
if (irintr&IRINTR_TPKTINT) if (irintr&IRINTR_TPKTINT)
vlsi_tx_interrupt(ndev); vlsi_tx_interrupt(ndev);
if (!(irintr & ~IRINTR_ACTIVITY))
break; /* done if only activity remaining */
if (irintr & ~(IRINTR_RPKTINT|IRINTR_TPKTINT|IRINTR_ACTIVITY)) {
IRDA_DEBUG(1, "%s: IRINTR = %02x\n",
__FUNCTION__, (unsigned)irintr);
vlsi_reg_debug(iobase,__FUNCTION__);
}
} while (--boguscount > 0); } while (--boguscount > 0);
spin_unlock_irqrestore(&idev->lock,flags);
if (boguscount <= 0) if (boguscount <= 0)
MESSAGE("%s: too much work in interrupt!\n", __FUNCTION__); MESSAGE("%s: too much work in interrupt!\n", __FUNCTION__);
......
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