一、dm9000_porbe函数分析
不同于u-boot代码,tq2440中的DM9000更加复杂,需要分析的点也很多:
-
/*
-
* Search DM9000 board, allocate space and register it
-
*/
-
static int __devinit
-
dm9000_probe(struct platform_device *pdev)
-
{
-
struct dm9000_plat_data *pdata = pdev->dev.platform_data;
-
struct board_info *db; /* Point a board information structure */
-
struct net_device *ndev;
-
const unsigned char *mac_src;
-
int ret = 0;
-
int iosize;
-
int i;
-
u32 id_val;
-
-
#if defined(CONFIG_ARCH_S3C2410)
-
unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;
-
unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4;
-
#endif
-
-
/* Init network device */
-
ndev = alloc_etherdev(sizeof(struct board_info)); //分配netdev结构
-
if (!ndev) {
-
dev_err(&pdev->dev, "could not allocate device.\n");
-
return -ENOMEM;
-
}
-
-
SET_NETDEV_DEV(ndev, &pdev->dev);
-
-
dev_dbg(&pdev->dev, "dm9000_probe()\n"); //不管
-
-
#if defined(CONFIG_ARCH_S3C2410) //2410可以不管
-
// *((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
-
*((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 ;
-
*((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
-
#endif
-
-
/* setup board info structure */
-
db = netdev_priv(ndev);
-
memset(db, 0, sizeof(*db));
-
-
db->dev = &pdev->dev;
-
db->ndev = ndev;
-
-
spin_lock_init(&db->lock);
-
mutex_init(&db->addr_lock);
-
-
INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
-
-
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取平台资源,对应的platform_driver
-
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-
db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-
-
..................
-
}
从这里可以引出之前的知识点:平台设备和平台驱动的相关知识。在dm9000.c中有:
-
static struct platform_driver dm9000_driver = {
-
.driver = {
-
.name = "dm9000", //这个平台驱动通过name和tq2440中的dm9000的驱动设备结构对接
-
.owner = THIS_MODULE,
-
},
-
.probe = dm9000_probe,
-
.remove = __devexit_p(dm9000_drv_remove),
-
.suspend = dm9000_drv_suspend,
-
.resume = dm9000_drv_resume,
-
};
在arch/arm/mach-tq2440.c:
-
struct platform_device s3c_device_dm9000 = {
-
.name = "dm9000", //这里有同样的name来实现
-
.id = 0,
-
.num_resources = ARRAY_SIZE(s3c_dm9k_resource),
-
.resource = s3c_dm9k_resource, //这里保存着dm9000硬件的资源
-
.dev = {
-
.platform_data = &s3c_dm9k_platdata,
-
}
-
};
同样在此文件中:
-
static struct resource s3c_dm9k_resource[] = {
-
[0] = { //用的片选4
-
.start = S3C2410_CS4, //这里的起始地址是0x20000000和网上一些0x20000300不一样。wu'suo
-
.end = S3C2410_CS4 + 3, //.end为什么尾地址是+3?因为一个地址需要四个字节。这是根据网卡来定义的
-
.flags = IORESOURCE_MEM,
-
},
-
[1] = { //0x20000004~0x20000007?
-
.start = S3C2410_CS4 + 4, //这里的4意味着地址线2等于1,设置了cmd为高位,是数据内容
-
.end = S3C2410_CS4 + 4 + 3,
-
.flags = IORESOURCE_MEM,
-
},
-
[2] = {
-
.start = IRQ_EINT7, //对应的中断信息
-
.end = IRQ_EINT7,
-
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
-
}
-
-
};
回来继续看dm9000.c中的probe函数:
-
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-
db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-
-
if (db->addr_res == NULL || db->data_res == NULL ||
-
db->irq_res == NULL) {
-
dev_err(db->dev, "insufficient resources\n");
-
ret = -ENOENT;
-
goto out;
-
}
-
-
iosize = res_size(db->addr_res);
-
db->addr_req = request_mem_region(db->addr_res->start, iosize,
-
pdev->name);
-
-
if (db->addr_req == NULL) {
-
dev_err(db->dev, "cannot claim address reg area\n");
-
ret = -EIO;
-
goto out;
-
}
-
-
db->io_addr = ioremap(db->addr_res->start, iosize); //将地址信息重映射
-
-
if (db->io_addr == NULL) {
-
dev_err(db->dev, "failed to ioremap address reg\n");
-
ret = -EINVAL;
-
goto out;
-
}
-
-
iosize = res_size(db->data_res);
-
db->data_req = request_mem_region(db->data_res->start, iosize,
-
pdev->name);
-
-
if (db->data_req == NULL) {
-
dev_err(db->dev, "cannot claim data reg area\n");
-
ret = -EIO;
-
goto out;
-
}
-
-
db->io_data = ioremap(db->data_res->start, iosize); //将数据信息重映射
-
-
if (db->io_data == NULL) {
-
dev_err(db->dev, "failed to ioremap data reg\n");
-
ret = -EINVAL;
-
goto out;
-
}
-
-
.........................
-
-
id_val = ior(db, DM9000_CHIPR); //读取芯片信息
-
// dev_dbg(db->dev, "dm9000 revision 0x%02x io_mode %02x \n", id_val, db->io_mode);
-
printk(KERN_INFO "dm9000 revision 0x%02x io_mode %02x \n", id_val, db->io_mode);
-
-
switch (id_val) {
-
case CHIPR_DM9000A:
-
db->type = TYPE_DM9000A;
-
break;
-
case CHIPR_DM9000B:
-
db->type = TYPE_DM9000B;
-
break;
-
case CHIPR_DM9000C:
-
db->type = TYPE_DM9000C;
-
break;
-
default:
-
dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
-
db->type = TYPE_DM9000E;
-
}
-
-
/* from this point we assume that we have found a DM9000 */
-
-
/* driver system function */ //下面在设置dm9000的操作函数集了
-
ether_setup(ndev);
-
-
ndev->open = &dm9000_open;
-
ndev->hard_start_xmit = &dm9000_start_xmit;
-
ndev->tx_timeout = &dm9000_timeout;
-
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
-
ndev->stop = &dm9000_stop;
-
ndev->set_multicast_list = &dm9000_hash_table;
-
ndev->ethtool_ops = &dm9000_ethtool_ops;
-
ndev->do_ioctl = &dm9000_ioctl;
-
-
#ifdef CONFIG_NET_POLL_CONTROLLER
-
ndev->poll_controller = &dm9000_poll_controller;
-
#endif
-
-
db->msg_enable = NETIF_MSG_LINK;
-
db->mii.phy_id_mask = 0x1f;
-
db->mii.reg_num_mask = 0x1f;
-
db->mii.force_media = 0;
-
db->mii.full_duplex = 0;
-
db->mii.dev = ndev;
-
db->mii.mdio_read = dm9000_phy_read;
-
db->mii.mdio_write = dm9000_phy_write;
-
-
#if defined(CONFIG_ARCH_S3C2410)
-
printk("Now use the default MAC address: 10:23:45:67:89:ab\n");
-
mac_src = "EmbedSky";
-
ndev->dev_addr[0] = 0x10;
-
ndev->dev_addr[1] = 0x23;
-
ndev->dev_addr[2] = 0x45;
-
ndev->dev_addr[3] = 0x67;
-
ndev->dev_addr[4] = 0x89;
-
ndev->dev_addr[5] = 0xab;
-
#else
-
mac_src = "eeprom";
-
-
/* try reading the node address from the attached EEPROM */ //读取MAC地址,从EEPROM中
-
for (i = 0; i < 6; i += 2)
-
dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
-
-
if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
-
mac_src = "platform data";
-
memcpy(ndev->dev_addr, pdata->dev_addr, 6);
-
}
-
-
if (!is_valid_ether_addr(ndev->dev_addr)) {
-
/* try reading from mac */
-
-
mac_src = "chip";
-
for (i = 0; i < 6; i++)
-
ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
-
}
-
-
if (!is_valid_ether_addr(ndev->dev_addr))
-
dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
-
"set using ifconfig\n", ndev->name);
-
#endif
-
-
platform_set_drvdata(pdev, ndev);
-
ret = register_netdev(ndev); //注册网卡驱动
-
-
if (ret == 0)
-
printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
-
ndev->name, dm9000_type_to_char(db->type),
-
db->io_addr, db->io_data, ndev->irq,
-
ndev->dev_addr, mac_src);
-
return 0;
-
-
out:
-
#if defined(CONFIG_ARCH_S3C2410)
-
*(volatile unsigned int *)S3C2410_BWSCON = oldval_bwscon;
-
*(volatile unsigned int *)S3C2410_BANKCON4 = oldval_bankcon4;
-
#endif
-
dev_err(db->dev, "not found (%d).\n", ret);
-
-
dm9000_release_board(pdev, db);
-
free_netdev(ndev);
-
-
return ret;
-
}
二、DM9000_OPEN函数分析
在probe中没有太多的dm9000的初始化代码,都写在了open中(这个open函数在ifconfig eth0 192.168.1.1时调用):
-
/*
-
* Open the interface.
-
* The interface is opened whenever "ifconfig" actives it.
-
*/
-
static int
-
dm9000_open(struct net_device *dev)
-
{
-
board_info_t *db = netdev_priv(dev);
-
unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
-
-
if (netif_msg_ifup(db))
-
dev_dbg(db->dev, "enabling %s\n", dev->name);
-
-
/* If there is no IRQ type specified, default to something that
-
* may work, and tell the user that this is a problem */
-
-
if (irqflags == IRQF_TRIGGER_NONE)
-
dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
-
-
irqflags |= IRQF_SHARED;
-
-
if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev)) //注册网卡驱动的中断处理函数
-
return -EAGAIN;
-
-
/* Initialize DM9000 board */
-
// dm9000_reset(db);
-
dm9000_init_dm9000(dev); //网卡初始化在这里
-
-
/* Init driver variable */
-
db->dbug_cnt = 0;
-
-
mii_check_media(&db->mii, netif_msg_link(db), 1);
-
netif_start_queue(dev); //启动发送队列
-
-
dm9000_schedule_poll(db);
-
-
return 0;
-
}
DM9000初始化:
①分配net_device结构
②从platform_device中获取地址,中断号
③把获取到的地址映射为虚拟地址
④读取芯片类型
⑤设置操作函数集
⑥注册网卡驱动
三、dm9000_start_xmit发送函数分析
dm9000_start_xmit:
-
/*
-
* Hardware start transmission.
-
* Send a packet to media from the upper layer.
-
*/
-
static int
-
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
-
{
-
unsigned long flags;
-
board_info_t *db = netdev_priv(dev);
-
int save_mwr, check_mwr, calc_mwr;
-
-
dm9000_dbg(db, 3, "%s:\n", __func__);
-
-
if ((db->tx_pkt_cnt > 0) || !netif_carrier_ok(dev))
-
return 1;
-
-
spin_lock_irqsave(&db->lock, flags);
-
-
netif_stop_queue(dev); //通知协议栈,暂停向驱动传送数据
-
db->tx_pkt_cnt++;
-
dev->stats.tx_bytes += skb->len;
-
dev->stats.tx_packets++;
-
-
save_mwr = (ior(db, 0xfb) << 8) | ior(db, 0xfa);
-
calc_mwr = save_mwr + skb->len;
-
if(skb->len & 0x01) calc_mwr++;
-
if(calc_mwr > 0x0bff ) calc_mwr -= 0x0c00;
-
-
/* Set TX length to DM9000 */ //获取发送长度
-
iow(db, DM9000_TXPLL, skb->len);
-
iow(db, DM9000_TXPLH, skb->len >> 8);
-
-
/* Move data to DM9000 TX RAM */ //将要发送的数据发送入缓存
-
writeb(DM9000_MWCMD, db->io_addr);
-
(db->outblk)(db->io_data, skb->data, skb->len); //skb->data,skb->len分别指向结构体数据的头和尾
-
-
/* Issue TX polling command */
-
iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ //清除发送位
-
-
dev->trans_start = jiffies; /* save the time stamp */
-
-
check_mwr = (ior(db, 0xfb) << 8) | ior(db, 0xfa);
-
if(calc_mwr != check_mwr)
-
{
-
printk(KERN_INFO "TX: fifo error %04x %04x %04x %04x\n", save_mwr, skb->len, calc_mwr, check_mwr);
-
iow(db, 0xfb, (calc_mwr >> 8) & 0xff);
-
iow(db, 0xfa, calc_mwr & 0xff);
-
}
-
-
spin_unlock_irqrestore(&db->lock, flags);
-
-
/* free this SKB */
-
dev_kfree_skb(skb); //释放SKB结构
-
-
return 0;
-
}
发送完成产生中断(dm9000_interrupt):
-
static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
-
{
-
struct net_device *dev = dev_id;
-
board_info_t *db = netdev_priv(dev);
-
int int_status;
-
unsigned long flags;
-
u8 reg_save;
-
-
dm9000_dbg(db, 3, "entering %s\n", __func__);
-
-
/* A real interrupt coming */
-
-
/* holders of db->lock must always block IRQs */
-
spin_lock_irqsave(&db->lock, flags);
-
-
/* Save previous register address */
-
reg_save = readb(db->io_addr);
-
-
/* Disable all interrupts */
-
iow(db, DM9000_IMR, IMR_PAR);
-
-
/* Got DM9000 interrupt status */
-
int_status = ior(db, DM9000_ISR); /* Got ISR */
-
iow(db, DM9000_ISR, int_status); /* Clear ISR status */
-
-
if (netif_msg_intr(db))
-
dev_dbg(db->dev, "interrupt status %02x\n", int_status);
-
-
/* Received the coming packet */
-
if (int_status & ISR_PRS)
-
dm9000_rx(dev); //接收中断
-
-
int_status |= ior(db, DM9000_ISR); /* Got ISR */
-
-
/* Trnasmit Interrupt check */
-
if (int_status & ISR_PTS)
-
{
-
iow(db, DM9000_ISR, ISR_PTS);
-
dm9000_tx_done(dev, db); //发送中断
-
}
-
-
if (db->type != TYPE_DM9000E) {
-
if (int_status & ISR_LNKCHNG) {
-
/* fire a link-change request */
-
schedule_delayed_work(&db->phy_poll, 1);
-
}
-
}
-
-
/* Re-enable interrupt mask */
-
iow(db, DM9000_IMR, db->imr_all);
-
-
/* Restore previous register address */
-
writeb(reg_save, db->io_addr);
-
-
spin_unlock_irqrestore(&db->lock, flags);
-
-
return IRQ_HANDLED;
-
}
发送函数完成后进入中断dm9000_tx_done:
-
/*
-
* DM9000 interrupt handler
-
* receive the packet to upper layer, free the transmitted packet
-
*/
-
-
static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
-
{
-
int tx_status = ior(db, DM9000_TCR); /* Got TX status */ //获取中断状态
-
-
if(tx_status & TCR_TXREQ) //查看发送是否出错
-
{
-
dev->stats.rx_fifo_errors++; //错误计数加1
-
}
-
else
-
{
-
db->tx_pkt_cnt = 0;
-
dev->trans_start = 0;
-
netif_wake_queue(dev); //调用netif_wake_queue(),通知协议栈发送数据
-
}
-
}
dm9000_rx():
-
/*
-
* Received a packet and pass to upper layer
-
*/
-
static void
-
dm9000_rx(struct net_device *dev)
-
{
-
board_info_t *db = netdev_priv(dev);
-
struct dm9000_rxhdr rxhdr;
-
struct sk_buff *skb;
-
u8 rxbyte, *rdptr;
-
bool GoodPacket;
-
int RxLen;
-
int save_mrr, check_mrr, calc_mrr;
-
-
/* Check packet ready or not */
-
do {
-
ior(db, DM9000_MRCMDX); /* Dummy read */ //空读
-
save_mrr = (ior(db, 0xf5) << 8) | ior(db, 0xf4);
-
/* Get most updated data */
-
rxbyte = ior(db, DM9000_MRCMDX); //查看接收状态
-
-
if(DM9000_PKT_RDY != rxbyte) //是否已经ready
-
{
-
/* Status check: this byte must be 0 or 1 */
-
if (rxbyte) {
-
// dev_warn(db->dev, "status check fail: %d\n", rxbyte);
-
printk(KERN_INFO "status check fail: %d\n", rxbyte);
-
iow(db, DM9000_RCR, 0x00); /* Stop Device */
-
iow(db, DM9000_IMR, IMR_PAR); /* Stop INT request */
-
-
dm9000_init_dm9000(dev);
-
}
-
return;
-
}
-
-
/* A packet ready now & Get status/length */
-
GoodPacket = true;
-
writeb(DM9000_MRCMD, db->io_addr); //
-
(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); //dm9000_rxhdr结构中有rx_len,接收长度
-
-
calc_mrr = save_mrr + 4;
-
if(calc_mrr > 0x3fff) calc_mrr -= 0x3400;
-
-
check_mrr = (ior(db, 0xf5) << 8) | ior(db, 0xf4);
-
if(calc_mrr != check_mrr)
-
{
-
printk(KERN_INFO "RX: 4 byte error %04x %04x %04x \n", save_mrr, calc_mrr, check_mrr);
-
iow(db, 0xf5, (save_mrr >> 8) & 0xff);
-
iow(db, 0xf4, save_mrr & 0xff);
-
continue;
-
}
-
-
writeb(DM9000_MRCMD, db->io_addr);
-
-
RxLen = le16_to_cpu(rxhdr.RxLen);
-
-
calc_mrr = save_mrr + 4 + RxLen;
-
if(RxLen & 0x01) calc_mrr++;
-
if(calc_mrr > 0x3fff) calc_mrr -= 0x3400;
-
-
if (netif_msg_rx_status(db))
-
dev_dbg(db->dev, "RX: status %02x, length %04x\n",
-
rxhdr.RxStatus, RxLen);
-
-
/* Packet Status check */ //判断长度
-
if (RxLen < 0x40) {
-
GoodPacket = false;
-
if (netif_msg_rx_err(db))
-
dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
-
}
-
-
if (RxLen > DM9000_PKT_MAX) {
-
dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
-
}
-
-
/* rxhdr.RxStatus is identical to RSR register. */ //读取状态看有没有出错
-
if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
-
RSR_PLE | RSR_RWTO |
-
RSR_LCS | RSR_RF)) {
-
GoodPacket = false;
-
if (rxhdr.RxStatus & RSR_FOE) {
-
if (netif_msg_rx_err(db))
-
dev_dbg(db->dev, "fifo error\n");
-
dev->stats.rx_fifo_errors++;
-
}
-
if (rxhdr.RxStatus & RSR_CE) {
-
if (netif_msg_rx_err(db))
-
dev_dbg(db->dev, "crc error\n");
-
dev->stats.rx_crc_errors++;
-
}
-
if (rxhdr.RxStatus & RSR_RF) {
-
if (netif_msg_rx_err(db))
-
dev_dbg(db->dev, "length error\n");
-
dev->stats.rx_length_errors++;
-
}
-
}
-
-
/* Move data from DM9000 */
-
if (GoodPacket
-
&& ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { //分配skb=接收到的数据长度+4
-
skb_reserve(skb, 2); //skb中的ip包需要4字节对齐,所以skb要保留多2个字节。(以太网包格式)
-
rdptr = (u8 *) skb_put(skb, RxLen - 4); //skb的tail指针,数据包长度减4
-
-
/* Read received packet from RX SRAM */
-
-
(db->inblk)(db->io_data, rdptr, RxLen); //读取io_data地址到rdptr中
-
dev->stats.rx_bytes += RxLen;
-
-
/* Pass to upper layer */
-
skb->protocol = eth_type_trans(skb, dev);
-
netif_rx(skb); //把准备好的skb提交给上层协议
-
dev->stats.rx_packets++;
-
-
check_mrr = (ior(db, 0xf5) << 8) | ior(db, 0xf4);
-
if(calc_mrr != check_mrr)
-
{
-
// dev_dbg(db->dev, "RX: fifo error %04x %04x %04x %04x\n", save_mrr, RxLen, calc_mrr, check_mrr);
-
printk(KERN_INFO "RX: fifo error %04x %04x %04x %04x\n", save_mrr, RxLen, calc_mrr, check_mrr);
-
iow(db, 0xf5, (calc_mrr >> 8) & 0xff);
-
iow(db, 0xf4, calc_mrr & 0xff);
-
}
-
-
} else {
-
/* need to dump the packet's data */
-
iow(db, 0xf5, (calc_mrr >> 8) & 0xff);
-
iow(db, 0xf4, calc_mrr & 0xff);
-
}
-
-
} while (rxbyte == DM9000_PKT_RDY);
-
}
阅读(753) | 评论(0) | 转发(0) |