kernels/linux-2.4.0/drivers/net/3c527.c
/**
 *	mc32_rx_ring:
 *	@dev: 3c527 that needs its receive ring processing
 *
 *	We have received one or more indications from the card that
 *	a receive has completed. The ring buffer thus contains dirty
 *	entries. Firstly we tell the card to stop receiving, then We walk 
 *	the ring from the first filled entry, which is pointed to by the 
 *	card rx mailbox and for each completed packet we will either copy 
 *	it and pass it up the stack or if the packet is near MTU sized we 
 *	allocate another buffer and flip the old one up the stack.
 *
 *	We must succeed in keeping a buffer on the ring. If neccessary we
 *	will toss a received packet rather than lose a ring entry. Once the
 *	first packet that is unused is found we reload the mailbox with the
 *	buffer so that the card knows it can use the buffers again. Finally
 *	we set it receiving again. 
 *
 *	We must stop reception during the ring walk. I thought it would be
 *	neat to avoid it by clever tricks, but it turns out the event order
 *	on the card means you have to play by the manual.
 */
@dev: 3c527 that needs its receive ring processing

We have received one or more indications from the card that
a receive has completed. The ring buffer thus contains dirty
entries. Firstly we tell the card to stop receiving, then We walk
the ring from the first filled entry, which is pointed to by the
card rx mailbox and for each completed packet we will either copy
it and pass it up the stack or if the packet is near MTU sized we
allocate another buffer and flip the old one up the stack.

We must succeed in keeping a buffer on the ring. If neccessary we
will toss a received packet rather than lose a ring entry. Once the
first packet that is unused is found we reload the mailbox with the
buffer so that the card knows it can use the buffers again. Finally
we set it receiving again.

We must stop reception during the ring walk. I thought it would be
neat to avoid it by clever tricks, but it turns out the event order
on the card means you have to play by the manual.
@dev : 3c527 that needs its receive ring processing We have received one or more indications from the card that a receive has completed . The ring buffer thus contains dirty entries . Firstly we tell the card to stop receiving then We walk the ring from the first filled entry which is pointed to by the card rx mailbox and for each completed packet we will either copy it and pass it up the stack or if the packet is near MTU sized we allocate another buffer and flip the old one up the stack . We must succeed in keeping a buffer on the ring . If neccessary we will toss a received packet rather than lose a ring entry . Once the first packet that is unused is found we reload the mailbox with the buffer so that the card knows it can use the buffers again . Finally we set it receiving again . We must stop reception during the ring walk . I thought it would be neat to avoid it by clever tricks but it turns out the event order on the card means you have to play by the manual .
static void mc32_rx_ring(struct net_device *dev)
{
	struct mc32_local *lp=dev->priv;
	int ioaddr = dev->base_addr;
	int x=0;
	volatile struct skb_header *p;
	u16 base;
	u16 top;
	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
	outb(3<<3, ioaddr+HOST_CMD);
	while(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR);
	top = base = lp->rx_box->data[0];
	do
	{
		p=(struct skb_header *)bus_to_virt(base+lp->base);
		if(!(p->status & (1<<7)))
			break;
		if(p->status & (1<<6))
		{
			u16 length = p->length;
			struct sk_buff *skb=dev_alloc_skb(length+2);
			if(skb!=NULL)
			{
				skb_reserve(skb,2);
				memcpy(skb_put(skb, length),
					bus_to_virt(p->data), length);
				skb->protocol=eth_type_trans(skb,dev);
				skb->dev=dev;
				lp->net_stats.rx_packets++;
				lp->net_stats.rx_bytes+=skb->len;
				netif_rx(skb);
			}
			else
				lp->net_stats.rx_dropped++;
		}
		else
		{
			lp->net_stats.rx_errors++;
			switch(p->status&0x0F)
			{
				case 1:
					lp->net_stats.rx_crc_errors++;break;
				case 2:
					lp->net_stats.rx_fifo_errors++;break;
				case 3:
					lp->net_stats.rx_frame_errors++;break;
				case 4:
					lp->net_stats.rx_missed_errors++;break;
				case 5:
					lp->net_stats.rx_length_errors++;break;
			}
		}
		p->length = 1532;
		p->control &= ~(1<<6);
		p->status = 0;
		base = p->next;
	}
	while(x++<48);
	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
	lp->rx_box->mbox=0;
	lp->rx_box->data[0] = top;
	outb(1<<3, ioaddr+HOST_CMD);	
	lp->rx_halted=0;
}
static void mc32_rx_ring ( struct net_device * dev ) { struct mc32_local * lp = dev -> priv ; int ioaddr = dev -> base_addr ; int x = 0 ; volatile struct skb_header * p ; u16 base ; u16 top ; while ( ! ( inb ( ioaddr + HOST_STATUS ) & HOST_STATUS_CRR ) ) ; outb ( 3 << 3 , ioaddr + HOST_CMD ) ; while ( inb ( ioaddr + HOST_STATUS ) & HOST_STATUS_CRR ) ; top = base = lp -> rx_box -> data [ 0 ] ; do { p = ( struct skb_header * ) bus_to_virt ( base + lp -> base ) ; if ( ! ( p -> status & ( 1 << 7 ) ) ) break ; if ( p -> status & ( 1 << 6 ) ) { u16 length = p -> length ; struct sk_buff * skb = dev_alloc_skb ( length + 2 ) ; if ( skb != NULL ) { skb_reserve ( skb , 2 ) ; memcpy ( skb_put ( skb , length ) , bus_to_virt ( p -> data ) , length ) ; skb -> protocol = eth_type_trans ( skb , dev ) ; skb -> dev = dev ; lp -> net_stats . rx_packets ++ ; lp -> net_stats . rx_bytes += skb -> len ; netif_rx ( skb ) ; } else lp -> net_stats . rx_dropped ++ ; } else { lp -> net_stats . rx_errors ++ ; switch ( p -> status & 0x0F ) { case 1 : lp -> net_stats . rx_crc_errors ++ ; break ; case 2 : lp -> net_stats . rx_fifo_errors ++ ; break ; case 3 : lp -> net_stats . rx_frame_errors ++ ; break ; case 4 : lp -> net_stats . rx_missed_errors ++ ; break ; case 5 : lp -> net_stats . rx_length_errors ++ ; break ; } } p -> length = 1532 ; p -> control &= ~ ( 1 << 6 ) ; p -> status = 0 ; base = p -> next ; } while ( x ++ < 48 ) ; while ( ! ( inb ( ioaddr + HOST_STATUS ) & HOST_STATUS_CRR ) ) ; lp -> rx_box -> mbox = 0 ; lp -> rx_box -> data [ 0 ] = top ; outb ( 1 << 3 , ioaddr + HOST_CMD ) ; lp -> rx_halted = 0 ; }
mc32_rx_ring:
      @dev: 3c527 that needs its receive ring processing
mc32_rx_ring : @dev : 3c527 that needs its receive ring processing
/* Halt RX before walking the ring */ /*printk("Frame at %p\n", bus_to_virt(p->data)); */ /*
	 *	Restart ring processing
	 */