先给出源代码,明天开始再进行代码分析。这是两个函数,分别是中断处理和数据发送:
static irqreturn_t pcnet32_interrupt( int irq, void *dev_id,
struct pt_regs *regs )
{
struct net_device *dev = dev_id;
struct pcnet32_private *lp;
unsigned long ioaddr;
u16 csr0, rap;
int boguscnt = max_interrupt_work;
int must_restart;
if( !dev ){
printk(KERN_DEBUG "%s(): irq %d for unknown device\n",
__FUNCTION__, irq );
return IRQ_NONE;
}
ioaddr = dev->base_addr;
lp = dev->priv;
spin_lock( &lp->lock );
rap = lp->a.read_rap( ioaddr );
while( (csr0 = lp->a.read_csr(ioaddr, 0)) & 0x8f00 && --boguscnt >= 0 ){
if( csr0 == 0xffff ) break;
}
lp->a.write_csr( ioaddr, 0, csr0 & ~0x004f );
must_restart = 0;
printk(KERN_INFO "%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
dev->name, csr0, lp->a.read_csr( ioaddr, 0 ) );
if( csr0 & 0x0200 ){
unsigned int dirty_tx = lp->dirty_tx;
int delta;
while( dirty_tx != lp->cur_tx ){
int entry = dirty_tx & TX_RING_MOD_MASK;
int status = (short)le16_to_cpu( lp->tx_ring[entry].status );
if( status < 0 )
break;
lp->tx_ring[entry].base = 0;
if( status & 0x4000 ){
int err_status = le32_to_cpu( lp->tx_ring[entry].misc );
lp->stats.tx_errors++;
printk(KERN_ERR "%s: Tx error status=%04x err status=%08x\n",
dev->name, status, err_status );
if( err_status & 0x04000000 )
lp->stats.tx_aborted_errors++;
if( err_status & 0x08000000 )
lp->stats.tx_carrier_errors++;
if( err_status & 0x10000000 )
lp->stats.tx_window_errors++;
if( err_status & 0x40000000 )
lp->stats.tx_fifo_errors++;
if( !lp->dxsuflo ){
printk( KERN_ERR, "%s: Tx FIFO error! CSR0=%4.4x\n",
dev->name, csr0 );
must_restart = 1;
}
}else{
if( status & 0x1800 )
lp->stats.collisions++;
lp->stats.tx_packets++;
}
if( lp->tx_skbuff[entry] ){
pci_unmap_single( lp->pci_dev, lp->tx_dma_addr[entry],
lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq( lp->tx_skbuff[entry] );
lp->tx_skbuff[entry] = NULL;
lp->tx_dma_addr[entry] = 0;
}
dirty_tx ++;
}
delta = (lp->cur_tx - dirty_tx)&(TX_RING_MOD_MASK + TX_RING_SIZE);
if( delta > TX_RING_SIZE ){
printk( KERN_ERR "%s: out-of_svnc dirty pointer. %d vs. %d."
"full=%d.\n",
dev->name, dirty_tx, lp->cur_tx, lp->tx_full );
dirty_tx += TX_RING_SIZE;
delta -= TX_RING_SIZE;
}
if( lp->tx_full && netif_queue_stopped(dev) &&
delta < TX_RING_SIZE -2 ){
lp->tx_full = 0;
netif_wake_queue(dev);
}
lp->dirty_tx = dirty_tx;
}
lp->a.write_csr( ioaddr, 0, 0x0040 );
lp->a.write_rap( ioaddr, rap );
printk(KERN_INFO "%s: exiting interrupt, csr0=%#4.4x.\n",
dev->name, lp->a.read_csr( ioaddr, 0 ) );
spin_unlock( &lp->lock );
return IRQ_HANDLED;
}
static int pcnet32_start_xmit( struct sk_buff *skb, struct net_device *dev )
{
struct pcnet32_private *lp = dev->priv;
unsigned long ioaddr = dev->base_addr;
u16 status;
int entry;
unsigned long flags;
spin_lock_irqsave( &lp->lock, flags );
status = 0x8300;
entry = lp->cur_tx & TX_RING_MOD_MASK;
printk(KERN_INFO "entry: %d\n", entry);
lp->tx_ring[entry].length = le16_to_cpu( -skb->len );
lp->tx_ring[entry].misc = 0x00000000;
lp->tx_skbuff[entry] = skb;
lp->tx_dma_addr[entry] = pci_map_single( lp->pci_dev, skb->data,
skb->len, PCI_DMA_FROMDEVICE );
lp->tx_ring[entry].base = (u32)le32_to_cpu( lp->tx_dma_addr[entry] );
wmb();
lp->tx_ring[entry].status = le16_to_cpu( status );
lp->cur_tx++;
lp->stats.tx_bytes += skb->len;
lp->a.write_csr( ioaddr, 0, 0x0048 );
dev->trans_start = jiffies;
if( lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base != 0 ){
lp->tx_full = 1;
netif_stop_queue( dev );
}
spin_unlock_irqrestore( &lp->lock, flags );
return 0;
}
阅读(738) | 评论(0) | 转发(0) |