Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1880471
  • 博文数量: 376
  • 博客积分: 2147
  • 博客等级: 大尉
  • 技术积分: 3642
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-06 10:47
文章分类

全部博文(376)

文章存档

2019年(3)

2017年(28)

2016年(15)

2015年(17)

2014年(182)

2013年(16)

2012年(115)

我的朋友

分类: LINUX

2012-02-07 14:56:04

先给出源代码,明天开始再进行代码分析。这是两个函数,分别是中断处理和数据发送:
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;
}
阅读(704) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~