您的位置:首页 > 运维架构 > Linux

Linux 网卡设备驱动

2008-12-24 21:45 232 查看
Linux 网卡驱动


刺猬@http://blog.csdn.net/littlehedgehog

网上一位前辈写的,时至今日,代码很多编译通不过(主要是Linux 内核变化实在太快),我把代码移植到我的ubuntu 8.10下测试成功,里面也加上了我的注解。不过还有不少东西没有搞懂,手头上也没有相关的硬件资料,就一份Realtek 的datasheet。 TNND,后面要备考备荒,手头的事情只能放一放。

#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,/*我的网卡类型 HOHO~ */
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 napi_struct napi;
struct pci_dev *pdev;
struct net_device *dev;
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 << 8);/*(1<<11) 16k-0x00002980*/
#elif RX_BUF_IDX == 2
static const unsigned int xc_rx_config =
(1 << 12) | (1 << 7) | (7 << 13) | (7 << 8);/*(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*/

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);
}

/* Setting to 1 forces the RTL8139D(L) to a software reset state
which disables the transmitter and receiver, reinitializes the FIFOs,
resets the system buffer pointer to the initial value (Tx buffer is at
TSAD0, Rx buffer is empty).
*/
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);
skb_copy_to_linear_data (skb, &tp->rx_bufs[offset + 4], data_size);
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;

/* 这里需要保持双字对齐,不过加上4干什么?*/
cur_rx = (cur_rx + packet_size + 4 + 3) & ~3; /*更新接收offset*/
iowrite16((u16)(cur_rx - 16), ioaddr+RxBufPtr); /*更新当前包读取地址*/

status = ioread16(ioaddr+IntrStatus) & RxAckBits;
/* 在datasheet里面我看到说往isr写没有任何效果 难道我又错了*/
/* 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;
}

/* 轮询, 还好不是轮fuck 这里的budget是接受数据包的最大量 */
static int xc_poll(struct napi_struct *napi, int budget)
{

struct xc_priv *tp = container_of(napi, struct xc_priv, napi);
struct net_device *dev = tp->dev;
int work_done = 0;
unsigned long flags = 0;
void __iomem *ioaddr = tp->ioaddr;

if (budget <= 0)
return -1;

spin_lock(&tp->rx_lock);
if (likely(ioread16(ioaddr+IntrStatus) & RxAckBits))
{
work_done = xc_rx(dev, tp, budget);
}

/* 这里加锁且禁用中断 貌似仅仅加锁已经足够了 毕竟我们不在中断中 */
if (budget > work_done)
{
spin_lock_irqsave(&tp->lock, flags);
iowrite16(xc_intr_mask, ioaddr+IntrMask);
__netif_rx_complete(dev, napi); /* 这里我们摘下napi中poll_list 并且清除NAPI_STATE_SCHED 的标志 */
spin_unlock_irqrestore(&tp->lock, flags);
}
spin_unlock(&tp->rx_lock);

return work_done;
}

/* 发送: 发送过程包括两部分,第一部分是把上层协议层传递下来的 第二部分就是把发送命令写入我们选定的寄存器 */
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; /* 这里我们要选择一个发送寄存器 注意这里的cur_tx标记的是当前选取的发送寄存器(发送寄存器有四个)*/
unsigned int len = skb->len;

/* 这里我们由于指定了发送缓冲区只能是1536 octet */

if (skb->len < 1536)
{
if (len < ETH_ZLEN)
memset(tp->tx_buf[entry], 0, ETH_ZLEN);
/* 把skb中的内容拷贝至发送缓冲区 */
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)));
dev->trans_start = jiffies; /*设置发送开始时间*/
tp->cur_tx++; /*设置下一个发送要用的register ,也就是直接递增cur_tx */
wmb();
if (tp->cur_tx - 4 == tp->dirty_tx) /* 如果发送缓冲区都满了 关闭发送队列 */
netif_stop_queue(dev);
spin_unlock_irq(&tp->lock);
return 0;
}

/* 这里是发送中断调用的函数, 注意这里并不是发送数据,发送数据是xc_tx所完成的,网卡发送完数据要通知cpu "hey 我这儿工作ok了",这里就是cpu的应答*/
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; /* dirty_tx标记的是还没有来得及发送的数据缓冲区 (cur_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);
}
}

/* linux 允许多个设备共享中断号 中断处理过程是把有相同中断号的中断处理程序依次执行一遍 */
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(0, ioaddr+IntrStatus);

if (status & RxAckBits)
{
/* schedule prepare ! 在这里我们检测两个地方 第一个是napi这个结构里面的state,有两个状态一个是 NAPI_STATE_SCHED 表示poll已被调度;另一个是NAPI——STATE_DISABLE 表示Disable pending ()*/
if (netif_rx_schedule_prep(dev, &tp->napi))
{
/* 关闭接收数据包的中断 这个是NAPI这种数据包接收方式的"规定"*/
iowrite16(xc_norx_intr_mask,ioaddr+IntrStatus);
/* 其实下面这句最终执行的就是 list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list); 也就是把napi里面的poll_list加入CPU的poll_list */
__netif_rx_schedule(dev, &tp->napi);
}
}

/* 如果是发送成功或者发送错误... */
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);

/* 写入mac地址 */
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[i] - tp->tx_bufs),
ioaddr+TxAddr0 + (i * 4));
ioread32(ioaddr+TxAddr0 + (i * 4));
}
/* 初始化 miss counter 寄存器 */
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);
/* 开启中断 注意mask的含义*/
iowrite16(xc_intr_mask,ioaddr+IntrMask);
}

/* 通常在ifconfig调用 */
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, IRQF_SHARED, dev->name, dev);
if (rc)
return rc;

/* 这里申请DMA地址 并且在tx_bufs_dma里返回了申请的总线地址 */
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;
}

napi_enable(&tp->napi);
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[i] = &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);
napi_disable(&tp->napi);

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;
}

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;
//dev->owner = THIS_MODULE;
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
tp->pdev = pdev;
tp->dev = dev;

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网卡被BIOS配置后,某些特性可能会被屏蔽掉。比如,多数BIOS都会清掉“master”位,
* 这导致板卡不能随意向主存中拷贝数据。pci_set_master函数数会检查是否需要设置标志位,
* 如果需要,则会将“master”位置位。
* PS:什么是PCI master?
* 不同于ISA总线,PCI总线的地址总线与数据总线是分时复用的。这样做的好处是,一方面
* 可以节省接插件的管脚数,另一方面便于实现突发数据传输。在做数据传输时,由一个PCI
* 设备做发起者(主控,Initiator或Master),而另一个PCI设备做目标(从设备,Target或Slave)。
* 总线上的所有时序的产生与控制,都由Master来发起。PCI总线在同一时刻只能供一对设备完成传输。
*/
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[i].version)
{
tp->chipset = i;
goto match;
}
tp->chipset = 0;

/* 这里设置为默认的方式 active high
*
* 摘抄自datasheet
*
* The LWACT bit and LWPTN bit in CONFIG4 register
are used to program the LWAKE pin’s output signal. According to the
combination of these two bits, there may be 4 choices of LWAKE signal, i.e.,
active high, active low, positive (high) pulse, and negative (low) pulse. The
output pulse width is about 150ms.
*/
match:
if (tp->chipset >= CH_8139B)
{
u8 ntmp = tmp = ioread8(ioaddr+Config1);
/* Software may use this bit to make sure that the driver has been loaded 这样我们可以确保驱动加载 */
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)
{
int i;
struct xc_priv *tp;
void __iomem *ioaddr;
struct net_device *dev = NULL;
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;

if (!dev->addr_len)
{
printk(KERN_INFO "XC:%i:dev->addr_len is set here/n",dev->addr_len);
dev->addr_len = 6;
}

/*硬件mac地址*/

((u32 *)dev->dev_addr)[0] = ioread32(ioaddr + MAC0) ;
((u16 *)dev->dev_addr)[2] = ioread32(ioaddr + MAC0 + 4);

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;
netif_napi_add(dev, &tp->napi, xc_poll, 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;

/* 如果你的接口可以发送一个报文, 它由几个不同的内存段组成, 你应当设置 NETIF_F_SG
* 如果你的硬件自己做校验, 设置 NETIF_F_HW_CWSUM.
* 设置这个标志, 如果你的设备能够对高端内存进行 DMA.
*/
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 >= 8) ? 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_register_driver(&xc_driver);
}
static void __exit xc_module_exit(void)
{
pci_unregister_driver(&xc_driver);
}
module_init(xc_module_init);
module_exit(xc_module_exit);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: