kernels/linux-2.4.0/drivers/net/3c527.c
/**
 *	mc32_send_packet:
 *	@skb: buffer to transmit
 *	@dev: 3c527 to send it out of
 *
 *	Transmit a buffer. This normally means throwing the buffer onto
 *	the transmit queue as the queue is quite large. If the queue is
 *	full then we set tx_busy and return. Once the interrupt handler
 *	gets messages telling it to reclaim transmit queue entries we will
 *	clear tx_busy and the kernel will start calling this again.
 *
 *	We use cli rather than spinlocks. Since I have no access to an SMP
 *	MCA machine I don't plan to change it. It is probably the top 
 *	performance hit for this driver on SMP however.
 */
@skb: buffer to transmit
@dev: 3c527 to send it out of

Transmit a buffer. This normally means throwing the buffer onto
the transmit queue as the queue is quite large. If the queue is
full then we set tx_busy and return. Once the interrupt handler
gets messages telling it to reclaim transmit queue entries we will
clear tx_busy and the kernel will start calling this again.

We use cli rather than spinlocks. Since I have no access to an SMP
MCA machine I don't plan to change it. It is probably the top
performance hit for this driver on SMP however.
@skb : buffer to transmit @dev : 3c527 to send it out of Transmit a buffer . This normally means throwing the buffer onto the transmit queue as the queue is quite large . If the queue is full then we set tx_busy and return . Once the interrupt handler gets messages telling it to reclaim transmit queue entries we will clear tx_busy and the kernel will start calling this again . We use cli rather than spinlocks . Since I have no access to an SMP MCA machine I don ' t plan to change it . It is probably the top performance hit for this driver on SMP however .
static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
{
	struct mc32_local *lp = (struct mc32_local *)dev->priv;
	int ioaddr = dev->base_addr;
	unsigned long flags;
	u16 tx_head;
	volatile struct skb_header *p, *np;
	netif_stop_queue(dev);
	save_flags(flags);
	cli();
	if(atomic_read(&lp->tx_count)==0)
	{
		restore_flags(flags);
		return 1;
	}
	tx_head = lp->tx_box->data[0];
	atomic_dec(&lp->tx_count);
	lp->tx_skb[lp->tx_skb_end] = skb;
	lp->tx_skb_end++;
	lp->tx_skb_end&=(TX_RING_MAX-1);
	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
	lp->tx_box->mbox=0;
	outb(3, ioaddr+HOST_CMD);
	p=(struct skb_header *)bus_to_virt(lp->base+tx_head);
	np=(struct skb_header *)bus_to_virt(lp->base+p->next);
	np->control	|= (1<<6);	
	wmb();
	np->length	= skb->len;
	if(np->length < 60)
		np->length = 60;
	np->data	= virt_to_bus(skb->data);
	np->status	= 0;
	np->control	= (1<<7)|(1<<6);	
	wmb();
	p->status	= 0;
	p->control	&= ~(1<<6);
	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
	lp->tx_box->mbox=0;
	outb(5, ioaddr+HOST_CMD);		
	restore_flags(flags);
	netif_wake_queue(dev);
	return 0;
}
static int mc32_send_packet ( struct sk_buff * skb , struct net_device * dev ) { struct mc32_local * lp = ( struct mc32_local * ) dev -> priv ; int ioaddr = dev -> base_addr ; unsigned long flags ; u16 tx_head ; volatile struct skb_header * p , * np ; netif_stop_queue ( dev ) ; save_flags ( flags ) ; cli ( ) ; if ( atomic_read ( & lp -> tx_count ) == 0 ) { restore_flags ( flags ) ; return 1 ; } tx_head = lp -> tx_box -> data [ 0 ] ; atomic_dec ( & lp -> tx_count ) ; lp -> tx_skb [ lp -> tx_skb_end ] = skb ; lp -> tx_skb_end ++ ; lp -> tx_skb_end &= ( TX_RING_MAX - 1 ) ; while ( ! ( inb ( ioaddr + HOST_STATUS ) & HOST_STATUS_CRR ) ) ; lp -> tx_box -> mbox = 0 ; outb ( 3 , ioaddr + HOST_CMD ) ; p = ( struct skb_header * ) bus_to_virt ( lp -> base + tx_head ) ; np = ( struct skb_header * ) bus_to_virt ( lp -> base + p -> next ) ; np -> control |= ( 1 << 6 ) ; wmb ( ) ; np -> length = skb -> len ; if ( np -> length < 60 ) np -> length = 60 ; np -> data = virt_to_bus ( skb -> data ) ; np -> status = 0 ; np -> control = ( 1 << 7 ) | ( 1 << 6 ) ; wmb ( ) ; p -> status = 0 ; p -> control &= ~ ( 1 << 6 ) ; while ( ! ( inb ( ioaddr + HOST_STATUS ) & HOST_STATUS_CRR ) ) ; lp -> tx_box -> mbox = 0 ; outb ( 5 , ioaddr + HOST_CMD ) ; restore_flags ( flags ) ; netif_wake_queue ( dev ) ; return 0 ; }
mc32_send_packet:
      @skb: buffer to transmit
      @dev: 3c527 to send it out of
mc32_send_packet : @skb : buffer to transmit @dev : 3c527 to send it out of
/* We will need this to flush the buffer out */ /* TX suspend - shouldnt be needed but apparently is.
	   This is a research item ... */ /* Transmit now stopped */ /* P is the last sending/sent buffer as a pointer */ /* NP is the buffer we will be loading */ /* EOL */ /* EOP EOL */ /* Restart TX */