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