免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 13130 | 回复: 18

改写drivers/net/8139too.c [复制链接]

论坛徽章:
0
发表于 2007-04-11 18:39 |显示全部楼层
改写drivers/net/8139too.c,虽说是改写,只是对8139too的代码进行了剪裁。
由原来的2600多行,减少到现在的800多行,但基本功能依然保留,这样有兴趣的朋友分析起来较方便。

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/compiler.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/completion.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>

#if defined(CONFIG_SH_DREAMCAST)
#define RX_BUF_IDX        1        /* 16K ring */
#else
#define RX_BUF_IDX        2        /* 32K ring */
#endif
#define RX_BUF_LEN        (8192 << RX_BUF_IDX)
#define RX_BUF_PAD        16
#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */

#if RX_BUF_LEN == 65536
#define RX_BUF_TOT_LEN        RX_BUF_LEN
#else
#define RX_BUF_TOT_LEN        (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
#endif

typedef enum {
        RTL8139 = 0,
        RTL8129,
} board_t;
static struct pci_device_id xc_id[] = {
        {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x1259, 0xa11e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
#ifdef CONFIG_SH_SECUREEDGE5410
        /* Bogus 8139 silicon reports 8129 without external PROM */
        {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
#endif
#ifdef CONFIG_8139TOO_8129
        {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
#endif
        {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
        {PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, RTL8139 },
        {PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, RTL8139 },
        {0,}
};
MODULE_DEVICE_TABLE (pci,xc_id);

enum RTL8139_registers {
        MAC0 = 0,                /* Ethernet hardware address. */
        MAR0 = 8,                /* Multicast filter. */
        TxStatus0 = 0x10,        /* Transmit status (Four 32bit registers). */
        TxAddr0 = 0x20,                /*物理地址*/
        RxBuf = 0x30,                /*物理地址*/
        ChipCmd = 0x37,
        RxBufPtr = 0x38,
        IntrMask = 0x3C,
        IntrStatus = 0x3E,
        TxConfig = 0x40,
        RxConfig = 0x44,
        RxMissed = 0x4C,
        Cfg9346 = 0x50,
        Config1 = 0x52,
        Config3 = 0x59,
        Config4 = 0x5A,
        HltClk = 0x5B,
        MultiIntr = 0x5C,
        /*MII*/
        BasicModeCtrl = 0x62,
        BasicModeStatus = 0x64,
        NWayAdvert = 0x66,
        NWayLPAR = 0x68,
        NWayExpansion = 0x6A,
        /*MII*/
        CSCR = 0x74,
};
enum ChipCmdBits {/*ChipCmd = 0x37 register*/
        CmdReset = 0x10,/*chip重置*/
        CmdRxEnb = 0x08,/*开启读*/
        CmdTxEnb = 0x04,/*开启写*/
        RxBufEmpty = 0x01,/*如果设置这个位表示接收缓冲区为空*/
};
enum IntrStatusBits {
        PCIErr = 0x8000,
        PCSTimeout = 0x4000,
        RxFIFOOver = 0x40,
        RxUnderrun = 0x20,
        RxOverflow = 0x10,
        TxErr = 0x08,
        TxOK = 0x04,
        RxErr = 0x02,
        RxOK = 0x01,

        RxAckBits = RxFIFOOver | RxOverflow | RxOK,
};
static const u16 xc_intr_mask =
        PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
        TxErr | TxOK | RxErr | RxOK;
static const u16 xc_norx_intr_mask =/*不包含任何接收中断*/
        PCIErr | PCSTimeout | RxUnderrun | TxErr | TxOK | RxErr ;
enum Config1Bits {/*Config1 = 0x52*/
        Cfg1_PM_Enable = 0x01,/*开启电源管理(cfg9346要设置为可写)*/
        LWAKE = 0x10,/*于Config4的LWPTN共同工作 同时设置为0为(active high)*/
};
enum Config3Bits {/*Config3 = 0x59*/
        Cfg3_Magic     = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
};
enum Config4Bits {/*Config4 = 0x5A*/
        LWPTN = (1 << 2),/*于Config1的LWAKE共同工作 同时设置为0为(active high)*/
};
enum Cfg9346Bits {
        Cfg9346_lock = 0x00,/*一般状态*/
        Cfg9346_Unlock = 0xC0,/*可写状态*/
};
enum TxStatusBits {/*TxStatus0 = 0x10 共4个发送状态register 0x10-0x1f*/
        TxHostOwns = 0x2000,
        TxUnderrun = 0x4000,/*在发送数据时如果,Tx FIFO耗尽时设置为1*/
        TxStatOK = 0x8000,/*发送数据成功*/
        TxOutOfWindow = 0x20000000,/*发生 "out of windown" 冲突*/
        TxAborted = 0x40000000,/*设置为1表示发送被中止,该位是只读的*/
        TxCarrierLost = 0x80000000,/*在发送数据包时,carrier丢失*/
};
/* Bits in RxConfig. */
enum rx_mode_bits {
        AcceptErr = 0x20,
        AcceptRunt = 0x10,
        AcceptBroadcast = 0x08,
        AcceptMulticast = 0x04,
        AcceptMyPhys = 0x02,
        AcceptAllPhys = 0x01,
};
typedef enum {
        CH_8139 = 0,
        CH_8139_K,
        CH_8139A,
        CH_8139A_G,
        CH_8139B,
        CH_8130,
        CH_8139C,
        CH_8100,
        CH_8100B_8139D,/*网卡类型*/
        CH_8101,
} chip_t;
enum chip_flags {
        HasHltClk = (1 << 0),
        HasLWake = (1 << 1),
};
#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
        (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
#define HW_REVID_MASK        HW_REVID(1, 1, 1, 1, 1, 1, 1)
static const struct {
        const char *name;
        u32 version; /* from RTL8139C/RTL8139D docs */
        u32 flags;
} rtl_chip_info[] = {
{ "RTL-8139",HW_REVID(1, 0, 0, 0, 0, 0, 0),HasHltClk,},
{ "RTL-8139 rev K",HW_REVID(1, 1, 0, 0, 0, 0, 0),HasHltClk,},
{ "RTL-8139A",HW_REVID(1, 1, 1, 0, 0, 0, 0),HasHltClk,},
{ "RTL-8139A rev G",HW_REVID(1, 1, 1, 0, 0, 1, 0),HasHltClk,},
{ "RTL-8139B",HW_REVID(1, 1, 1, 1, 0, 0, 0),HasLWake,},
{ "RTL-8130",HW_REVID(1, 1, 1, 1, 1, 0, 0),HasLWake,},
{ "RTL-8139C",HW_REVID(1, 1, 1, 0, 1, 0, 0),HasLWake,},
{ "RTL-8100",HW_REVID(1, 1, 1, 1, 0, 1, 0),HasLWake,},
{ "RTL-8100B/8139D",HW_REVID(1, 1, 1, 0, 1, 0, 1),HasHltClk | HasLWake,},
{ "RTL-8101", HW_REVID(1, 1, 1, 0, 1, 1, 1),HasLWake,},
};
struct xc_priv
{
        void __iomem *ioaddr;
        spinlock_t lock;
        spinlock_t rx_lock;
        chip_t chipset;
        struct pci_dev *pdev;
        struct net_device_stats stats;

        u32 rx_config;
        unsigned char *rx_bufs;
        unsigned int cur_rx;
        dma_addr_t rx_bufs_dma;

        unsigned int tx_flag;
        unsigned long cur_tx;
        unsigned long dirty_tx;
        unsigned char *tx_bufs;
        unsigned char *tx_buf[4];
        dma_addr_t tx_bufs_dma;
        /*MII define*/
        u32 msg_enable;
        unsigned int default_port : 4;  /* Last dev->if_port value. */
        signed char phys[4];            /* MII device addresses. */
        struct mii_if_info mii;
        /*MII*/
};

#if RX_BUF_IDX == 1
static const unsigned int xc_rx_config =
        (1 << 11) | (1 << 7) | (7 << 13) | (7 << ;/*(1<<11) 16k-0x00002980*/
#elif RX_BUF_IDX == 2
static const unsigned int xc_rx_config =
        (1 << 12) | (1 << 7) | (7 << 13) | (7 << ;/*(1<<12) 32k-0x00003180*/
#else
#error "Invalid configuration for 8139_RXBUF_IDX"
#endif

/*MII*/
static char mii_2_8139_map[8] = {
        BasicModeCtrl,BasicModeStatus,0,0,
        NWayAdvert,NWayLPAR,NWayExpansion,0
};/*一些于MII相关的8139register*/

static void xc_check_media(struct net_device *dev, unsigned int init_media)
{
        struct xc_priv *tp = netdev_priv(dev);
        if(tp->phys[0] >= 0)
                mii_check_media(&tp->mii, netif_msg_link(tp), init_media);
}

static int mdio_read (struct net_device *dev, int phy_id, int location)
{
        struct xc_priv *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->ioaddr;
        return location < 8 && mii_2_8139_map[location] ?
                ioread16(ioaddr+mii_2_8139_map[location]) : 0;
}

static void mdio_write(struct net_device *dev, int phy_id, int location,int value)
{
        struct xc_priv *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->ioaddr;
        if(location < 8 && mii_2_8139_map[location])
        {
                if(location == 0)
                {
                        iowrite8(Cfg9346_Unlock,ioaddr+Cfg9346);
                        iowrite16(value,ioaddr+BasicModeCtrl);
                        iowrite8(Cfg9346_lock,ioaddr+Cfg9346);
                }
                else
                        iowrite32(value,ioaddr+mii_2_8139_map[location]);
        }
}

/*MII*/

/*ethtool*/
static u32 xc_get_link(struct net_device *dev)
{
        struct xc_priv *tp = netdev_priv(dev);
        return mii_link_ok(&tp->mii);
}

static int xc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
        struct xc_priv *tp = netdev_priv(dev);
        spin_lock_irq(&tp->lock);
        mii_ethtool_gset(&tp->mii, cmd);
        spin_unlock_irq(&tp->lock);
        return 0;
}
static struct ethtool_ops xc_ethtool_ops = {
        .get_settings                = xc_get_settings,
        .get_link                = xc_get_link,
};
/*ethtool*/

论坛徽章:
0
发表于 2007-04-11 18:40 |显示全部楼层
static void __set_rx_mode (struct net_device *dev)
{////(leave)
        struct xc_priv *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->ioaddr;
        u32 mc_filter[2];        /* Multicast hash filter */
        int i, rx_mode;
        u32 tmp;

        struct dev_mc_list *mclist;
        rx_mode = AcceptBroadcast | AcceptMyPhys;
        mc_filter[1] = mc_filter[0] = 0;
        for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
                i++, mclist = mclist->next) {
                int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;

                mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
                rx_mode |= AcceptMulticast;
        }

        /* We can safely update without stopping the chip. */
        tmp = xc_rx_config | rx_mode;
        if (tp->rx_config != tmp) {
                iowrite32(tmp,ioaddr+RxConfig);
                ioread32(ioaddr+RxConfig);
                tp->rx_config = tmp;
        }
        iowrite32(mc_filter[0],ioaddr+MAR0 + 0);
        iowrite32(mc_filter[1],ioaddr+MAR0 + 4);
}

static void xc_set_multicast_list(struct net_device *dev)
{
        unsigned long flags;
        struct xc_priv *tp = netdev_priv(dev);

        spin_lock_irqsave (&tp->lock, flags);
        __set_rx_mode(dev);
        spin_unlock_irqrestore (&tp->lock, flags);
}

static void xc_reset(void __iomem *ioaddr)
{
        int i;
        /* Soft reset the chip. */
        iowrite8(CmdReset,ioaddr+ChipCmd);
        /* Check that the chip has finished the reset. */
        for (i = 1000; i > 0; i--) {
                barrier();
                if ((ioread8(ioaddr+ChipCmd) & CmdReset) == 0)
                        break;
                udelay (10);
        }
}

static void xc_cleanup_dev(struct net_device *dev)
{
        struct xc_priv *tp = netdev_priv(dev);
        if(tp->pdev == NULL || dev == NULL)
                return;
        if(tp->ioaddr)
                pci_iounmap(tp->pdev,tp->ioaddr);
        pci_release_regions(tp->pdev);
        free_netdev(dev);
        pci_set_drvdata(tp->pdev,NULL);
}

static int xc_rx(struct net_device *dev, struct xc_priv *tp,int budget)
{
        u16 status;
        struct sk_buff *skb;
        int packet_size,data_size;
        int work_done = 0;
        void __iomem *ioaddr = tp->ioaddr;
        unsigned long cur_rx = tp->cur_rx;

        while(netif_running(dev) && work_done < budget && ((ioread8(ioaddr+ChipCmd) & RxBufEmpty) == 0))
        {
                u32 tmp_size;
                u32 offset = cur_rx % RX_BUF_LEN;
                rmb();
                tmp_size = le32_to_cpu(*(u32 *)(tp->rx_bufs+offset));
                packet_size = tmp_size >> 16;
                data_size = packet_size - 4;
                skb = dev_alloc_skb(data_size + 2);
                if(likely(skb))
                {
                        skb->dev = dev;
                        skb_reserve(skb,2);
                        eth_copy_and_sum (skb, &tp->rx_bufs[offset + 4],data_size,0);
                        skb_put(skb,data_size);
                        skb->protocol = eth_type_trans (skb, dev);
                        dev->last_rx = jiffies;
                        tp->stats.rx_bytes += data_size;
                        tp->stats.rx_packets++;
                        netif_receive_skb (skb);
                }
                else
                        tp->stats.rx_dropped++;
                ++work_done;
                cur_rx = (cur_rx + packet_size + 4 + 3) & ~3;/*更新接收offset*/
                iowrite16((u16)(cur_rx - 16),ioaddr+RxBufPtr);/*更新当前包读取地址*/

                status = ioread16(ioaddr+IntrStatus) & RxAckBits;
                /* Clear out errors and receive interrupts */
                if (likely(status != 0))
                {
                        iowrite16 (RxAckBits,ioaddr+IntrStatus);
                        ioread16(ioaddr+IntrStatus);
                }
        }
        tp->cur_rx = cur_rx;
        return work_done;
}

static int xc_poll(struct net_device *dev, int *budget)
{
        struct xc_priv *tp = netdev_priv(dev);
        int mbudget = min(*budget, dev->quota);
        int work_done = 0;
        void __iomem *ioaddr = tp->ioaddr;

        if(mbudget <= 0)
                return -1;
        spin_lock(&tp->rx_lock);
        if(likely(ioread16(ioaddr+IntrStatus) & RxAckBits))
        {
                work_done = xc_rx(dev,tp,mbudget);
                *budget -= work_done;
                dev->quota -= work_done;
        }
        if(mbudget > work_done)
        {
                local_irq_disable();
                iowrite16(xc_intr_mask,ioaddr+IntrMask);
                __netif_rx_complete(dev);
                local_irq_enable();
        }
        spin_unlock(&tp->rx_lock);
        return !(work_done < mbudget);
}

static int xc_tx(struct sk_buff *skb, struct net_device *dev)
{
        struct xc_priv *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->ioaddr;
        unsigned int entry = tp->cur_tx % 4;
        unsigned int len = skb->len;
        if(skb->len < 1536)/*定义的发送缓冲区大小*/
        {
                if (len < ETH_ZLEN)
                        memset(tp->tx_buf[entry], 0, ETH_ZLEN);
                skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
                dev_kfree_skb(skb);
        }
        else
        {
                dev_kfree_skb(skb);/*释放skb*/
                tp->stats.tx_dropped++;/*更新统计数据*/
                return 0;
        }
        spin_lock_irq(&tp->lock);
        iowrite32(tp->tx_flag | max(len, (unsigned int)ETH_ZLEN),
                ioaddr+TxStatus0 + (entry * sizeof (u32)));/*状态register存放发送包大小*/
        dev->trans_start = jiffies;/*设置发送开始时间*/
        tp->cur_tx++;/*设置下一个发送要用的register*/
        wmb();
        if(tp->cur_tx - 4 == tp->dirty_tx)
                netif_stop_queue(dev);
        spin_unlock_irq(&tp->lock);
        return 0;
}

static void tx_interrupt (struct net_device *dev,
                                struct xc_priv *tp,void __iomem *ioaddr)
{
        unsigned long dirty_tx,tx_left;
        if(dev == NULL || ioaddr == NULL)
                return;
        dirty_tx = tp->dirty_tx;
        tx_left = tp->cur_tx - dirty_tx;
        while (tx_left > 0)
        {
                int entry = dirty_tx % 4;
                int txstatus;
                txstatus = ioread32(ioaddr+TxStatus0 + (entry * sizeof (u32)));
                if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
                        break;/* It still hasn't been Txed */
                dirty_tx++;
                tx_left--;
        }
        if (tp->dirty_tx != dirty_tx)
        {
                tp->dirty_tx = dirty_tx;
                mb();
                netif_wake_queue (dev);
        }
}

static irqreturn_t xc_interrupt(int irq, void *dev_inst,struct pt_regs *regs)
{
        u16 status,ackstat;
        struct net_device *dev = (struct net_device *)dev_inst;
        struct xc_priv *tp = netdev_priv(dev);
        int handle = 0;
        int link_changed = 0;
        void __iomem *ioaddr = tp->ioaddr;

        spin_lock(&tp->lock);
        status = ioread16(ioaddr+IntrStatus);
        if(unlikely(status & xc_intr_mask) == 0) goto out;
        handle = 1;
        if (unlikely(status == 0xFFFF)) goto out;
        if (unlikely(!netif_running(dev))) {iowrite16(0,ioaddr+IntrMask);goto out;}
        if (unlikely(status & RxUnderrun))
                link_changed = ioread16(ioaddr+CSCR) & 0x0800;
        ackstat = status & ~(RxAckBits | TxErr);
        if (ackstat) iowrite16(ackstat,ioaddr+IntrStatus);
        if(status & RxAckBits)
        {
                if(netif_rx_schedule_prep(dev))
                {
                        iowrite16(xc_norx_intr_mask,ioaddr+IntrStatus);
                        __netif_rx_schedule(dev);
                }
        }
        if(status & (TxOK | TxErr))
        {
                tx_interrupt(dev, tp, ioaddr);
                if(status & TxErr)
                        iowrite16(TxErr,ioaddr+IntrStatus);
        }
out:
        spin_unlock (&tp->lock);
        return IRQ_RETVAL(handle);
}

static void xc_hw_start(struct net_device *dev)
{
        int i;
        u8 tmp;
        struct xc_priv *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->ioaddr;
        if(rtl_chip_info[tp->chipset].flags & HasHltClk)
                iowrite8('R',ioaddr+HltClk);
        xc_reset(ioaddr);
       
        iowrite8(Cfg9346_Unlock,ioaddr+Cfg9346);
        iowrite32(cpu_to_le32(*(u32*)(dev->dev_addr+0)),ioaddr+MAC0+0);
        iowrite32(cpu_to_le32(*(u32*)(dev->dev_addr+4)),ioaddr+MAC0+4);
        iowrite8(CmdRxEnb | CmdTxEnb,ioaddr+ChipCmd);
        tp->rx_config = xc_rx_config | AcceptBroadcast | AcceptMyPhys;
        iowrite32(tp->rx_config,ioaddr+RxConfig);
        iowrite32(xc_rx_config,ioaddr+TxConfig);
        tp->cur_rx = 0;
        xc_check_media (dev, 1);
        if (tp->chipset >= CH_8139B)
                iowrite8(ioread8(ioaddr+Config3) & ~Cfg3_Magic,ioaddr+Config3);
        iowrite8(Cfg9346_lock,ioaddr+Cfg9346);

        iowrite32(tp->rx_bufs_dma,ioaddr+RxBuf);
        ioread32(ioaddr+RxBuf);
        for (i = 0; i < 4; i++)
        {
                iowrite32(tp->tx_bufs_dma + (tp->tx_buf - tp->tx_bufs),
                        ioaddr+TxAddr0 + (i * 4));
                ioread32(ioaddr+TxAddr0 + (i * 4));
        }
        iowrite32(0,ioaddr+RxMissed);
        xc_set_multicast_list(dev);
        iowrite16(ioread16(ioaddr+MultiIntr) & 0xF000,ioaddr+MultiIntr);
        tmp = ioread8(ioaddr+ChipCmd);
        if(!(tmp & CmdRxEnb) || !(tmp & CmdTxEnb))
                iowrite8(CmdRxEnb | CmdTxEnb,ioaddr+ChipCmd);
        iowrite16(xc_intr_mask,ioaddr+IntrMask);
}

static int xc_open(struct net_device *dev)
{
        int rc,i;
        struct xc_priv *tp = netdev_priv(dev);;
        rc = request_irq (dev->irq, xc_interrupt, SA_SHIRQ, dev->name, dev);
        if(rc) return rc;
        tp->tx_bufs = pci_alloc_consistent(tp->pdev, 1536*4,&tp->tx_bufs_dma);
tp->rx_bufs = pci_alloc_consistent(tp->pdev, RX_BUF_TOT_LEN,&tp->rx_bufs_dma);
        if(tp->rx_bufs == NULL || tp->tx_bufs == NULL)
        {
                free_irq(dev->irq, dev);
                if(tp->tx_bufs)
                pci_free_consistent(tp->pdev, 1536*4,tp->tx_bufs,tp->tx_bufs_dma);
                if(tp->rx_bufs)
        pci_free_consistent(tp->pdev, RX_BUF_TOT_LEN,tp->rx_bufs,tp->rx_bufs_dma);
                return -ENOMEM;
        }
        tp->mii.full_duplex = tp->mii.force_media;
        tp->tx_flag = (256 << 11) & 0x003f0000;
        tp->cur_rx = 0;
        tp->cur_tx = 0;
        tp->dirty_tx = 0;
        for (i = 0; i < 4; i++)
                tp->tx_buf = &tp->tx_bufs[i * 1536];
        xc_hw_start(dev);
        netif_start_queue(dev);
        return 0;
}

static int xc_stop(struct net_device *dev)
{
        unsigned long flags;
        struct xc_priv *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->ioaddr;
        netif_stop_queue(dev);

        spin_lock_irqsave(&tp->lock,flags);
        iowrite8(0,ioaddr+ChipCmd);
        iowrite16(0,ioaddr+IntrMask);
        tp->stats.rx_missed_errors += ioread32(ioaddr+RxMissed);
        iowrite32(0,ioaddr+RxMissed);
        spin_unlock_irqrestore (&tp->lock, flags);

        synchronize_irq (dev->irq);/* racy, but that's ok here */
        free_irq (dev->irq, dev);
        tp->cur_tx = 0;
        tp->dirty_tx = 0;
pci_free_consistent(tp->pdev, RX_BUF_TOT_LEN,tp->rx_bufs, tp->rx_bufs_dma);
pci_free_consistent(tp->pdev, 1536*4,tp->tx_bufs, tp->tx_bufs_dma);
        tp->rx_bufs = NULL;
        tp->tx_bufs = NULL;
        /* Green! Put the chip in low-power mode. */
        iowrite8(Cfg9346_Unlock,ioaddr+Cfg9346);
        if (rtl_chip_info[tp->chipset].flags & HasHltClk)
                iowrite8('H',ioaddr+HltClk);
        return 0;
}

论坛徽章:
0
发表于 2007-04-11 18:42 |显示全部楼层
static struct net_device_stats *xc_get_stats (struct net_device *dev)
{
        struct xc_priv *tp = netdev_priv(dev);
        return &tp->stats;
}

static void xc_tx_timeout(struct net_device *dev)
{
        struct xc_priv *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->ioaddr;
        u8 tmp8;

        tmp8= ioread8(ioaddr+ChipCmd);
        if (tmp8 & CmdTxEnb)
                iowrite8(CmdRxEnb,ioaddr+ChipCmd);/*如果8139任开启写则关闭,只保留读*/

        spin_lock_bh(&tp->rx_lock);
        /* Disable interrupts by clearing the interrupt mask. */
        iowrite16(0x0000,ioaddr+IntrMask);

        /* Stop a shared interrupt from scavenging while we are. */
        spin_lock_irq(&tp->lock);
        tp->cur_tx = 0;
        tp->dirty_tx = 0;
        spin_unlock_irq(&tp->lock);

        if (netif_running(dev))
        {/*重新设置8139所有信息*/
                xc_hw_start (dev);
                netif_wake_queue (dev);
        }
        spin_unlock_bh(&tp->rx_lock);
}

static int __devinit xc_board(struct pci_dev *pdev,struct net_device **dev_out)
{
        struct net_device *dev;
        struct xc_priv *tp;
        void __iomem *ioaddr;
        int rc,dev_on,i;
        u32 version;
        u8 tmp;
        if(pdev == NULL)
                return -1;
        dev_on = 0;
        *dev_out = NULL;
        dev = alloc_etherdev(sizeof(*tp));
        if(dev == NULL)
                return -ENOMEM;
        SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
        tp = netdev_priv(dev);
        tp->pdev = pdev;
        rc = pci_enable_device(pdev);
        if(rc)        goto err_out;
        rc = pci_request_regions (pdev, "xc8139too";
        if (rc) goto err_out;
        dev_on = 1;
        pci_set_master (pdev);
        ioaddr = pci_iomap(pdev, 1, 0);
        if (ioaddr == NULL) {rc = -EIO;goto err_out;}
        tp->ioaddr = ioaddr;
        dev->base_addr = (long)ioaddr;
        iowrite8('R',ioaddr+HltClk);
        if (ioread32(ioaddr+TxConfig) == 0xFFFFFFFF) {rc = -EIO;goto err_out;}
        version = ioread32(ioaddr+TxConfig) & HW_REVID_MASK;
        for(i=0;i<ARRAY_SIZE(rtl_chip_info);++i)
                if(version == rtl_chip_info.version)
                {tp->chipset = i;goto match;}
        tp->chipset = 0;
match:
        if(tp->chipset >= CH_8139B)
        {
                u8 ntmp = tmp = ioread8(ioaddr+Config1);
                if((rtl_chip_info[tp->chipset].flags & HasLWake) && (ntmp & LWAKE))
                        ntmp = ntmp & ~LWAKE;
                ntmp = ntmp | Cfg1_PM_Enable;
                if(ntmp != tmp)
                {
                        iowrite8(Cfg9346_Unlock,ioaddr+Cfg9346);
                        iowrite8(ntmp,ioaddr+Config1);
                        iowrite8(Cfg9346_lock,ioaddr+Cfg9346);
                }
                if(rtl_chip_info[tp->chipset].flags & HasLWake)
                {
                        tmp = ioread8(ioaddr+Config4);
                        if(tmp & LWPTN)
                        {
                                iowrite8(Cfg9346_Unlock,ioaddr+Cfg9346);
                                iowrite8(tmp & ~LWPTN,ioaddr+Config4);
                                iowrite8(Cfg9346_lock,ioaddr+Cfg9346);       
                        }
                }
        }
        else
        {
                tmp = ioread8(ioaddr+Config1);
                tmp = tmp & ~((1 << 1) | (1 << 0));
                iowrite8(tmp,ioaddr+Config1);
        }
        xc_reset(ioaddr);
        *dev_out = dev;
        return 0;
err_out:
        xc_cleanup_dev (dev);
        if(dev_on)
                pci_disable_device(pdev);
        return rc;
       
}

static int __devinit xc_probe(struct pci_dev *pdev,const struct pci_device_id *ent)
{
        struct xc_priv *tp;
        struct net_device *dev = NULL;
        void __iomem *ioaddr;
        int rc,option;
        static int index = -1;
        if(pdev == NULL || ent == NULL)
                return -ENODEV;
        ++index;
        rc = xc_board(pdev,&dev);
        if(rc < 0)
                return rc;
        if(dev == NULL)
                return -1;
        tp = netdev_priv(dev);
        ioaddr = tp->ioaddr;
        if(ioaddr == NULL)
                return -1;
        ((u16*)dev->dev_addr)[0] = 0xE000;
        ((u16*)dev->dev_addr)[1] = 0x964C;
        ((u16*)dev->dev_addr)[2] = 0x9D16;
        if(!dev->addr_len)
        {
                printk(KERN_INFO "XC:%i:dev->addr_len is set here\n",dev->addr_len);
                dev->addr_len = 6;
        }
        memcpy(dev->perm_addr,dev->dev_addr,dev->addr_len);
        /*dev function init*/
        dev->open                = xc_open;
        dev->stop                = xc_stop;
        dev->hard_start_xmit        = xc_tx;
        dev->poll                = xc_poll;
        dev->weight                = 64;
        dev->get_stats                = xc_get_stats;
        dev->set_multicast_list        = xc_set_multicast_list;
        dev->do_ioctl                = NULL;
        dev->ethtool_ops        = &xc_ethtool_ops;
        dev->tx_timeout                = xc_tx_timeout;
        dev->watchdog_timeo        = 6*HZ;
        dev->features                 |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
        dev->irq                = pdev->irq;

        tp                = netdev_priv(dev);
        ioaddr                = tp->ioaddr;
        tp->msg_enable        = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK;
        spin_lock_init(&tp->lock);
        spin_lock_init(&tp->rx_lock);
        tp->mii.dev                = dev;
        tp->mii.mdio_read        = mdio_read;
        tp->mii.mdio_write        = mdio_write;
        tp->mii.phy_id_mask        = 0x3f;
        tp->mii.reg_num_mask        = 0x1f;
        rc = register_netdev(dev);
        if(rc) goto err_out;
        pci_set_drvdata (pdev, dev);

        printk (KERN_INFO "%s:0x%lx--%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x,IRQ %d\n",
        dev->name,dev->base_addr,dev->dev_addr[0], dev->dev_addr[1],
        dev->dev_addr[2], dev->dev_addr[3],dev->dev_addr[4], dev->dev_addr[5],
        dev->irq);
        printk (KERN_DEBUG "%s:  Identified 8139 chip type '%s'\n",
                dev->name, rtl_chip_info[tp->chipset].name);
        /*MII define*/
        tp->phys[0] = 32;
        tp->mii.phy_id = tp->phys[0];

        /* The lower four bits are the media type. */
        option = (index >= ? 0 : -1;
        if (tp->mii.full_duplex) {
        printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
                /* Changing the MII-advertised media because might prevent
                   re-connection. */
                tp->mii.force_media = 1;
        }
        if (tp->default_port) {
                printk(KERN_INFO "  Forcing %dMbps %s-duplex operation.\n",
                           (option & 0x20 ? 100 : 10),
                           (option & 0x10 ? "full" : "half");
                mdio_write(dev, tp->phys[0], 0,
                                   ((option & 0x20) ? 0x2000 : 0) |         /* 100Mbps? */
                                   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
        }
        /*MII*/
        if (rtl_chip_info[tp->chipset].flags & HasHltClk)
                iowrite8('H',ioaddr+HltClk);
        return 0;
err_out:
        xc_cleanup_dev (dev);
        pci_disable_device (pdev);
        return rc;
}

static void __devexit xc_remove(struct pci_dev *pdev)
{
        struct net_device *dev = pci_get_drvdata(pdev);
        unregister_netdev(dev);
        xc_cleanup_dev(dev);
        pci_disable_device(pdev);
}

struct pci_driver xc_driver =
{
        .name                = "xc8139too",
        .id_table        = xc_id,
        .probe                = xc_probe,
        .remove                = __devexit_p(xc_remove),
};

static int __init xc_module_init(void)
{
        return pci_module_init(&xc_driver);
}
static void __exit xc_module_exit(void)
{
        pci_unregister_driver(&xc_driver);
}
module_init(xc_module_init);
module_exit(xc_module_exit);

论坛徽章:
0
发表于 2007-04-12 10:18 |显示全部楼层
绝对的--原创精华


楼主的单个C文件,包含上面三个帖子:

rtl8139too_refined.c.gz

7.42 KB, 下载次数: 424

论坛徽章:
0
发表于 2007-04-12 13:22 |显示全部楼层
向楼主学习, 准备分析AMD PCNET32网卡, 也以这种refined方式重写

论坛徽章:
0
发表于 2007-04-25 11:58 |显示全部楼层
呵呵,我以前这样做过e100的驱动

论坛徽章:
0
发表于 2007-04-25 16:49 |显示全部楼层
it is really good. i want to rewrite a network device driver too. can you share
your experience, thanks
btw: how to define struct xc_priv

[ 本帖最后由 FreeGnu 于 2007-4-25 17:09 编辑 ]

论坛徽章:
0
发表于 2007-05-12 10:20 |显示全部楼层
楼上说的 这个struct xc_priv结构是从 struct rtl8139来的

只是删除了些用于统计东西

论坛徽章:
0
发表于 2007-07-15 13:06 |显示全部楼层
学习,准备实现zero-copy

论坛徽章:
0
发表于 2007-07-16 23:18 |显示全部楼层
提交到lkml怎么样呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP