in zatm.c [361:481]
static void poll_rx(struct atm_dev *dev,int mbx)
{
struct zatm_dev *zatm_dev;
unsigned long pos;
u32 x;
int error;
EVENT("poll_rx\n",0,0);
zatm_dev = ZATM_DEV(dev);
pos = (zatm_dev->mbx_start[mbx] & ~0xffffUL) | zin(MTA(mbx));
while (x = zin(MWA(mbx)), (pos & 0xffff) != x) {
u32 *here;
struct sk_buff *skb;
struct atm_vcc *vcc;
int cells,size,chan;
EVENT("MBX: host 0x%lx, nic 0x%x\n",pos,x);
here = (u32 *) pos;
if (((pos += 16) & 0xffff) == zatm_dev->mbx_end[mbx])
pos = zatm_dev->mbx_start[mbx];
cells = here[0] & uPD98401_AAL5_SIZE;
#if 0
printk("RX IND: 0x%x, 0x%x, 0x%x, 0x%x\n",here[0],here[1],here[2],here[3]);
{
unsigned long *x;
printk("POOL: 0x%08x, 0x%08x\n",zpeekl(zatm_dev,
zatm_dev->pool_base),
zpeekl(zatm_dev,zatm_dev->pool_base+1));
x = (unsigned long *) here[2];
printk("[0..3] = 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n",
x[0],x[1],x[2],x[3]);
}
#endif
error = 0;
if (here[3] & uPD98401_AAL5_ERR) {
error = (here[3] & uPD98401_AAL5_ES) >>
uPD98401_AAL5_ES_SHIFT;
if (error == uPD98401_AAL5_ES_DEACT ||
error == uPD98401_AAL5_ES_FREE) continue;
}
EVENT("error code 0x%x/0x%x\n",(here[3] & uPD98401_AAL5_ES) >>
uPD98401_AAL5_ES_SHIFT,error);
skb = ((struct rx_buffer_head *) bus_to_virt(here[2]))->skb;
__net_timestamp(skb);
#if 0
printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",((unsigned *) skb->data)[-3],
((unsigned *) skb->data)[-2],((unsigned *) skb->data)[-1],
((unsigned *) skb->data)[0]);
#endif
EVENT("skb 0x%lx, here 0x%lx\n",(unsigned long) skb,
(unsigned long) here);
#if 0
printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
#endif
size = error ? 0 : ntohs(((__be16 *) skb->data)[cells*
ATM_CELL_PAYLOAD/sizeof(u16)-3]);
EVENT("got skb 0x%lx, size %d\n",(unsigned long) skb,size);
chan = (here[3] & uPD98401_AAL5_CHAN) >>
uPD98401_AAL5_CHAN_SHIFT;
if (chan < zatm_dev->chans && zatm_dev->rx_map[chan]) {
int pos;
vcc = zatm_dev->rx_map[chan];
pos = ZATM_VCC(vcc)->pool;
if (skb == zatm_dev->last_free[pos])
zatm_dev->last_free[pos] = NULL;
skb_unlink(skb, zatm_dev->pool + pos);
}
else {
printk(KERN_ERR DEV_LABEL "(itf %d): RX indication "
"for non-existing channel\n",dev->number);
size = 0;
vcc = NULL;
event_dump();
}
if (error) {
static unsigned long silence = 0;
static int last_error = 0;
if (error != last_error ||
time_after(jiffies, silence) || silence == 0){
printk(KERN_WARNING DEV_LABEL "(itf %d): "
"chan %d error %s\n",dev->number,chan,
err_txt[error]);
last_error = error;
silence = (jiffies+2*HZ)|1;
}
size = 0;
}
if (size && (size > cells*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER ||
size <= (cells-1)*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER)) {
printk(KERN_ERR DEV_LABEL "(itf %d): size %d with %d "
"cells\n",dev->number,size,cells);
size = 0;
event_dump();
}
if (size > ATM_MAX_AAL5_PDU) {
printk(KERN_ERR DEV_LABEL "(itf %d): size too big "
"(%d)\n",dev->number,size);
size = 0;
event_dump();
}
if (!size) {
dev_kfree_skb_irq(skb);
if (vcc) atomic_inc(&vcc->stats->rx_err);
continue;
}
if (!atm_charge(vcc,skb->truesize)) {
dev_kfree_skb_irq(skb);
continue;
}
skb->len = size;
ATM_SKB(skb)->vcc = vcc;
vcc->push(vcc,skb);
atomic_inc(&vcc->stats->rx);
}
zout(pos & 0xffff,MTA(mbx));
#if 0 /* probably a stupid idea */
refill_pool(dev,zatm_vcc->pool);
/* maybe this saves us a few interrupts */
#endif
}