static struct pci_driver rtl8139_pci_driver = {
.name= DRV_NAME,
.id_table= rtl8139_pci_tbl,
.probe= rtl8139_init_one,
.remove= __devexit_p(rtl8139_remove_one),
#ifdef CONFIG_PM
.suspend= rtl8139_suspend,
.resume= rtl8139_resume,
#endif
};
static int __devinit rtl8139_init_one (struct pci_dev *pdev,const struct pci_device_id *ent)
{
struct net_device *dev = NULL;
struct rtl8139_private *tp;
int i, addr_len, option;
void __iomem *ioaddr;
static int board_idx = -1;
assert (pdev != NULL);
assert (ent != NULL);
board_idx++;
#ifndef MODULE
{
static int printed_version;
if (!printed_version++)
pr_info(RTL8139_DRIVER_NAME "n");
}
#endif
if (pdev->vendor == PCI_VENDOR_ID_REALTEK&&
pdev->device == PCI_DEVICE_ID_REALTEK_8139&& pdev->revision>= 0x20) {
dev_info(&pdev->dev,
"This (id x:x rev x) is an enhanced 8139C+ chip, use8139cpn",
pdev->vendor, pdev->device,pdev->revision);
return -ENODEV;
}
if (pdev->vendor == PCI_VENDOR_ID_REALTEK&&
pdev->device == PCI_DEVICE_ID_REALTEK_8139&&
pdev->subsystem_vendor == PCI_VENDOR_ID_ATHEROS&&
pdev->subsystem_device ==PCI_DEVICE_ID_REALTEK_8139) {
pr_info("8139too: OQO Model 2 detected. Forcing PIOn");
use_io = 1;
}
dev = rtl8139_init_board (pdev);//返回了一个struct net_device对象的指针
if (IS_ERR(dev))
return PTR_ERR(dev);
assert (dev != NULL);
tp = netdev_priv(dev);//获取私有结构的指针
tp->dev = dev;//关联rtl8139_init_board 返回的 net_device对象指针,便于操作
ioaddr = tp->mmio_addr;//获取虚拟io地址,便于操作
assert (ioaddr != NULL);
addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
for (i = 0; i < 3; i++)//macaddr 6 byte, each time2byte ,so three times is ok
((__le16 *) (dev->dev_addr))[i] =
cpu_to_le16(read_eeprom (ioaddr, i + 7, addr_len));
memcpy(dev->perm_addr, dev->dev_addr,dev->addr_len);//保存MAC地址
dev->netdev_ops =&rtl8139_netdev_ops; //关联net_device的操作
dev->ethtool_ops =&rtl8139_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT;
netif_napi_add(dev, &tp->napi,rtl8139_poll,64);
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM |NETIF_F_HIGHDMA;
dev->irq =pdev->irq;//关联irq,方便在request_irq函数中的操作
tp =netdev_priv(dev);
tp->drv_flags =board_info[ent->driver_data].hw_flags;
tp->mmio_addr = ioaddr;
tp->msg_enable =
(debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1<< debug) - 1));
spin_lock_init (&tp->lock);
spin_lock_init (&tp->rx_lock);
INIT_DELAYED_WORK(&tp->thread,rtl8139_thread);
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;
pr_debug("about to register device named %s (%p)...n",dev->name, dev);
i = register_netdev (dev);//注册网络设备
if (i) goto err_out;
pci_set_drvdata (pdev,dev);
pr_info("%s: %s at 0x%lx, %pM, IRQ %dn",
dev->name,
board_info[ent->driver_data].name,
dev->base_addr,
dev->dev_addr,
dev->irq);
pr_debug("%s: Identified 8139 chip type'%s'n",
dev->name,rtl_chip_info[tp->chipset].name);
#ifdef CONFIG_8139TOO_8129
if (tp->drv_flags & HAS_MII_XCVR){
int phy, phy_idx = 0;
for (phy = 0; phy < 32&& phy_idx <sizeof(tp->phys); phy++) {
int mii_status = mdio_read(dev, phy, 1);
if (mii_status != 0xffff&& mii_status !=0x0000) {
u16 advertising = mdio_read(dev, phy, 4);
tp->phys[phy_idx++] = phy;
pr_info("%s: MII transceiver %d status 0x%4.4x advertising%4.4x.n",
dev->name, phy, mii_status, advertising);
}
}
if (phy_idx == 0) {
pr_info("%s: No MII transceivers found! Assuming SYMtransceiver.n",
dev->name);
tp->phys[0] = 32;
}
} else
#endif
tp->phys[0] = 32;
tp->mii.phy_id =tp->phys[0];
option = (board_idx >= MAX_UNITS) ? 0 :media[board_idx];
if (option > 0) {
tp->mii.full_duplex = (option &0x210) ? 1 : 0;
tp->default_port = option &0xFF;
if (tp->default_port)
tp->mii.force_media = 1;
}
if (board_idx < MAX_UNITS&&full_duplex[board_idx] > 0)
tp->mii.full_duplex = full_duplex[board_idx];
if (tp->mii.full_duplex) {
pr_info("%s: Media type forced to Full Duplex.n",dev->name);
tp->mii.force_media = 1;
}
if (tp->default_port) {
pr_info(" Forcing %dMbps %s-duplexoperation.n",
(option & 0x20 ? 100 : 10),
(option & 0x10 ? "full" : "half"));
mdio_write(dev, tp->phys[0], 0,
((option & 0x20) ? 0x2000 : 0)|
((option & 0x10) ? 0x0100 : 0));
}
if (rtl_chip_info[tp->chipset].flags& HasHltClk)
RTL_W8 (HltClk,'H');
return 0;
err_out:
__rtl8139_cleanup_dev (dev);
pci_disable_device (pdev);
return i;
}
static __devinit struct net_device * rtl8139_init_board (structpci_dev *pdev)
{
void __iomem *ioaddr;
struct net_device *dev;
struct rtl8139_private *tp;
u8 tmp8;
int rc, disable_dev_on_err = 0;
unsigned int i;
unsigned long pio_start, pio_end, pio_flags, pio_len;
unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
u32 version;
assert (pdev !=NULL);
dev = alloc_etherdev (sizeof(*tp));
if (dev == NULL) {
dev_err(&pdev->dev, "Unable to allocnew net devicen");
return ERR_PTR(-ENOMEM);
}
SET_NETDEV_DEV(dev,&pdev->dev);
tp = netdev_priv(dev);
tp->pci_dev =pdev;
rc = pci_enable_device (pdev);
if (rc)
gotoerr_out;
pio_start = pci_resource_start (pdev, 0);
pio_end = pci_resource_end (pdev, 0);
pio_flags = pci_resource_flags (pdev, 0);
pio_len = pci_resource_len (pdev, 0);
mmio_start = pci_resource_start (pdev, 1);
mmio_end = pci_resource_end (pdev, 1);
mmio_flags = pci_resource_flags (pdev, 1);
mmio_len = pci_resource_len (pdev,1);
pr_debug("PIO region size == 0xlXn", pio_len);
pr_debug("MMIO region size == 0xlXn", mmio_len);
retry:
if (use_io){
if (!(pio_flags & IORESOURCE_IO)) {
dev_err(&pdev->dev, "region #0 not aPIO resource, abortingn");
rc = -ENODEV;
goto err_out;
}
if (pio_len < RTL_MIN_IO_SIZE) {
dev_err(&pdev->dev, "Invalid PCI I/Oregion size(s), abortingn");
rc = -ENODEV;
goto err_out;
}
} else{
if (!(mmio_flags & IORESOURCE_MEM)) {
dev_err(&pdev->dev, "region #1 notan MMIO resource, abortingn");
rc = -ENODEV;
goto err_out;
}
if (mmio_len < RTL_MIN_IO_SIZE) {
dev_err(&pdev->dev, "Invalid PCI memregion size(s), abortingn");
rc = -ENODEV;
goto err_out;
}
}
rc = pci_request_regions (pdev, DRV_NAME);
if (rc)
goto err_out;
disable_dev_on_err = 1;
pci_set_master(pdev);
if (use_io) {
ioaddr = pci_iomap(pdev, 0, 0);//pci_iounmap(pdev,info->priv);
if (!ioaddr) {
dev_err(&pdev->dev, "cannot map PIO,abortingn");
rc = -EIO;
goto err_out;
}
dev->base_addr = pio_start;
tp->regs_len = pio_len;
} else{
ioaddr = pci_iomap(pdev, 1, 0);
if (ioaddr == NULL) {
dev_err(&pdev->dev, "cannot remapMMIO, trying PIOn");
pci_release_regions(pdev);
use_io = 1;
goto retry;
}
dev->base_addr = (long) ioaddr;
tp->regs_len = mmio_len;
}
tp->mmio_addr = ioaddr;//在rtl8139_private结构中保存该虚拟地址,用于io操作
RTL_W8 (HltClk,'R');
if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
dev_err(&pdev->dev, "Chip notresponding, ignoring boardn");
rc = -EIO;
goto err_out;
}
version = RTL_R32 (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;
}
dev_dbg(&pdev->dev, "unknown chipversion, assuming RTL-8139n");
dev_dbg(&pdev->dev, "TxConfig =0x%lxn", RTL_R32 (TxConfig));
tp->chipset = 0;
match:
pr_debug("chipset id (%d) == index %d, '%s'n",
version, i, rtl_chip_info[i].name);
if (tp->chipset >= CH_8139B) {
u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
pr_debug("PCI PM wakeupn");
if ((rtl_chip_info[tp->chipset].flags& HasLWake)&&
(tmp8 & LWAKE))
new_tmp8 &= ~LWAKE;
new_tmp8 |= Cfg1_PM_Enable;
if (new_tmp8 != tmp8) {
RTL_W8 (Cfg9346, Cfg9346_Unlock);
RTL_W8 (Config1, tmp8);
RTL_W8 (Cfg9346, Cfg9346_Lock);
}
if (rtl_chip_info[tp->chipset].flags& HasLWake) {
tmp8 = RTL_R8 (Config4);
if (tmp8 & LWPTN) {
RTL_W8 (Cfg9346, Cfg9346_Unlock);
RTL_W8 (Config4, tmp8 & ~LWPTN);
RTL_W8 (Cfg9346, Cfg9346_Lock);
}
}
} else {
pr_debug("Old chip wakeupn");
tmp8 = RTL_R8 (Config1);
tmp8 &= ~(SLEEP | PWRDN);
RTL_W8 (Config1, tmp8);
}
rtl8139_chip_reset (ioaddr);
return dev;
err_out:
__rtl8139_cleanup_dev (dev);
if (disable_dev_on_err)
pci_disable_device (pdev);
return ERR_PTR(rc);
}
static int rtl8139_open (struct net_device*dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
int retval;
void __iomem *ioaddr = tp->mmio_addr;
retval = request_irq (dev->irq, rtl8139_interrupt,IRQF_SHARED, dev->name, dev);
if (retval)
return retval;
//dma_alloc_coherent() --获取物理页,并将该物理页的总线地址保存于dma_handle,返回该物理页的虚拟地址
tp->tx_bufs =dma_alloc_coherent(&tp->pci_dev->dev,TX_BUF_TOT_LEN,
&tp->tx_bufs_dma, GFP_KERNEL);
tp->rx_ring =dma_alloc_coherent(&tp->pci_dev->dev,RX_BUF_TOT_LEN,
&tp->rx_ring_dma, GFP_KERNEL);
if (tp->tx_bufs == NULL ||tp->rx_ring == NULL) {
free_irq(dev->irq, dev);
if (tp->tx_bufs)
dma_free_coherent(&tp->pci_dev->dev,TX_BUF_TOT_LEN,
tp->tx_bufs, tp->tx_bufs_dma);
if (tp->rx_ring)
dma_free_coherent(&tp->pci_dev->dev,RX_BUF_TOT_LEN,
tp->rx_ring, tp->rx_ring_dma);
return -ENOMEM;
}
napi_enable(&tp->napi);
tp->mii.full_duplex =tp->mii.force_media;
tp->tx_flag = (TX_FIFO_THRESH<< 11) &0x003f0000;
rtl8139_init_ring (dev);//将发送帧所存放的地址写下来
rtl8139_hw_start (dev);//初始化接收和发送寄存器对于的dma地址
netif_start_queue(dev);//该函数用于告诉上层网络驱动层驱动空间有缓冲区可用,开始发送数据包到驱动层。
if (netif_msg_ifup(tp))
pr_debug("%s: rtl8139_open() ioaddr %#llx IRQ %d"
" GP Pins %2.2x %s-duplex.n", dev->name,
(unsigned long long)pci_resource_start (tp->pci_dev,1),
dev->irq, RTL_R8 (MediaStatus),
tp->mii.full_duplex ? "full" : "half");
rtl8139_start_thread(tp);
return 0;
}
static irqreturn_t rtl8139_interrupt (int irq,void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
u16 status, ackstat;
int link_changed = 0;
int handled = 0;
spin_lock (&tp->lock);
status = RTL_R16(IntrStatus);//从网卡的中断状态寄存器中读出状态值进行分析
if (unlikely((status & rtl8139_intr_mask) ==0))
goto out;
handled =1;
if (unlikely(status == 0xFFFF))
gotoout;
if (unlikely(!netif_running(dev))) {
RTL_W16 (IntrMask, 0);
goto out;
}
if (unlikely(status & RxUnderrun))
link_changed = RTL_R16 (CSCR) &CSCR_LinkChangeBit;
ackstat = status & ~(RxAckBits | TxErr);
if (ackstat)
RTL_W16 (IntrStatus,ackstat);
if (status & RxAckBits){
if (napi_schedule_prep(&tp->napi)){
RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
__napi_schedule(&tp->napi);//转为轮询机制,而非中断机制
}
}
if (unlikely(status & (PCIErr | PCSTimeout |RxUnderrun | RxErr)))
rtl8139_weird_interrupt (dev, tp, ioaddr,status,link_changed);
if (status & (TxOK | TxErr)) {
rtl8139_tx_interrupt (dev, tp, ioaddr);
if (status & TxErr)
RTL_W16 (IntrStatus, TxErr);
}
out:
spin_unlock (&tp->lock);
pr_debug("%s: exiting interrupt, intr_status=%#4.4x.n",
dev->name, RTL_R16 (IntrStatus));
return IRQ_RETVAL(handled);
}
static int rtl8139_poll(struct napi_struct *napi,int budget)
{
struct rtl8139_private *tp = container_of(napi, structrtl8139_private, napi);
struct net_device *dev = tp->dev;
void __iomem *ioaddr = tp->mmio_addr;
int work_done;
spin_lock(&tp->rx_lock);
work_done = 0;
if (likely(RTL_R16(IntrStatus) &RxAckBits))//接收中断
work_done += rtl8139_rx(dev, tp,budget);
if (work_done < budget){//如果一次处理的帧个数小于budget(64)则退出轮询模式
unsigned longflags;
spin_lock_irqsave(&tp->lock,flags);
RTL_W16_F(IntrMask, rtl8139_intr_mask);
__napi_complete(napi); //退出轮询模式
spin_unlock_irqrestore(&tp->lock,flags);
}
spin_unlock(&tp->rx_lock);
return work_done;
}
static int rtl8139_rx(struct net_device *dev, structrtl8139_private *tp,int budget)
{
void __iomem *ioaddr = tp->mmio_addr;
int received = 0;
unsigned char *rx_ring = tp->rx_ring;
unsigned int cur_rx = tp->cur_rx;
unsigned int rx_size = 0;
pr_debug("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
" free to %4.4x, Cmd %2.2x.n", dev->name,(u16)cur_rx,
RTL_R16 (RxBufAddr),
RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
//这个函数是一个大循环,循环条件是只要接收缓存不为空就还可以继续读取数据,循环不会停止,读空了之后就跳出
while (netif_running(dev) &&received < budget
&& (RTL_R8 (ChipCmd)& RxBufEmpty) == 0) {
u32 ring_offset = cur_rx % RX_BUF_LEN; //
u32 rx_status;
unsigned int pkt_size;
struct sk_buff *skb;
rmb();
rx_status = le32_to_cpu (*(__le32 *) (rx_ring +ring_offset));
rx_size = rx_status >> 16;//计算出要接收的包的长度
pkt_size = rx_size - 4;
if (netif_msg_rx_status(tp))
pr_debug("%s: rtl8139_rx() status %4.4x, size%4.4x,"
" cur %4.4x.n", dev->name, rx_status,
rx_size, cur_rx);
#if RTL8139_DEBUG > 2
{
int i;
pr_debug("%s: Frame contents ", dev->name);
for (i = 0; i < 70; i++)
pr_cont(" %2.2x",
rx_ring[ring_offset + i]);
pr_cont(".n");
}
#endif
if (unlikely(rx_size == 0xfff0)) {
if (!tp->fifo_copy_timeout)
tp->fifo_copy_timeout = jiffies + 2;
else if (time_after(jiffies, tp->fifo_copy_timeout)){
pr_debug("%s: hung FIFO. Reset.", dev->name);
rx_size = 0;
goto no_early_rx;
}
if (netif_msg_intr(tp)) {
pr_debug("%s: fifo copy in progress.",
dev->name);
}
tp->xstats.early_rx++;
break;
}
no_early_rx:
tp->fifo_copy_timeout =0;
if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4))||
(rx_size < 8) ||
(!(rx_status & RxStatusOK)))) {
rtl8139_rx_err (rx_status, dev, tp, ioaddr);
received = -1;
goto out;
}
skb = netdev_alloc_skb(dev, pkt_size + NET_IP_ALIGN);
//如果分配成功就把数据从接收缓存中拷贝到这个包中
if (likely(skb)) {
skb_reserve (skb, NET_IP_ALIGN);
#if RX_BUF_IDX == 3
wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
#else//现在我们已经熟知,&rx_ring[ring_offset +4]就是接收缓存,也是源地址,
//而skb->data就是包的数据地址,下面这个函数就是将接收到的数据拷贝到skb->data所指向的位置
skb_copy_to_linear_data (skb, &rx_ring[ring_offset+ 4], pkt_size);
#endif
skb_put (skb, pkt_size);
//当接收到的数据应经复制到skb中head指向的位置之后,需要改变skb->tail 指针
skb->protocol = eth_type_trans (skb, dev);
dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++;
//在netif_receive_skb(skb)函数执行完后,这个包的数据就脱离了网卡驱动范畴,而进入了Linux网络协议栈里面
netif_receive_skb (skb);
} else {
if (net_ratelimit())
pr_warning("%s: Memory squeeze, dropping packet.n",
dev->name);
dev->stats.rx_dropped++;
}
received++;
cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
RTL_W16 (RxBufPtr, (u16) (cur_rx - 16));
rtl8139_isr_ack(tp);
}
if (unlikely(!received || rx_size == 0xfff0))
rtl8139_isr_ack(tp);
pr_debug("%s: Done rtl8139_rx(), current %4.4x BufAddr%4.4x,"
" free to %4.4x, Cmd %2.2x.n", dev->name,cur_rx,
RTL_R16 (RxBufAddr),
RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
tp->cur_rx =cur_rx;
if (tp->fifo_copy_timeout)
received = budget;
out:
return received;
}
static int rtl8139_start_xmit (struct sk_buff*skb, struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
unsigned int entry;
unsigned int len = skb->len;
unsigned longflags;
entry = tp->cur_tx %NUM_TX_DESC;
if (likely(len < TX_BUF_SIZE)) {
if (len < ETH_ZLEN)
memset(tp->tx_buf[entry], 0, ETH_ZLEN);
skb_copy_and_csum_dev(skb,tp->tx_buf[entry]);//把待发送的数据拷贝到发送缓冲区,也就是skb->data指向的空间
dev_kfree_skb(skb);
} else {
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
return 0;
}
spin_lock_irqsave(&tp->lock,flags);
wmb();
RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
tp->tx_flag | max(len, (unsignedint)ETH_ZLEN));
dev->trans_start = jiffies;
tp->cur_tx++;
if ((tp->cur_tx - NUM_TX_DESC) ==tp->dirty_tx)
netif_stop_queue (dev);
spin_unlock_irqrestore(&tp->lock,flags);
if (netif_msg_tx_queued(tp))
pr_debug("%s: Queued Tx packet size %u to slot %d.n",
dev->name, len, entry);
return 0;
}
http://www.cnblogs.com/zhuyp1015/archive/2012/08/04/2623387.html