http://liu1227787871.blog.163.com/blog/#m=0&t=1&c=fks_084071083082080067086080080095086086084064082085087074083
(五)mini2440网卡驱动DM9000之dm9000_stop
static int dm9000_stop(struct net_device *ndev){
board_info_t *db = netdev_priv(ndev);
if (netif_msg_ifdown(db))//检测ndev是否停止
dev_dbg(db->dev, "shutting down %s\n", ndev->name);
cancel_delayed_work_sync(&db->phy_poll);/*杀死延时工作队列phy_poll*/
netif_stop_queue(ndev); /*停止发送数据包*/
netif_carrier_off(ndev);/*clear carrier*/
/* free interrupt */
free_irq(ndev->irq, ndev);
dm9000_shutdown(ndev);
return 0;
}
注:关于netif的函数在netdevice.h中,以后要认真读一下,目前还不会分析。只知道大概的意思
(六)mini2440网卡驱动DM9000之dm9000_start_xmit
/* 调用时机:当网卡有数据需要发送的时候,该函数被调用 */
static int
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
board_info_t *db = netdev_priv(dev);
dm9000_dbg(db, 3, "%s:\n", __func__);
if (db->tx_pkt_cnt > 1)//只能存放两个数据包,如果已经有两个就退出,原因见注释
return 1;
spin_lock_irqsave(&db->lock, flags);/*详见注视*/
/* Move data to DM9000 TX RAM ,详见注释*/
writeb(DM9000_MWCMD, db->io_addr);/*MWCMD:/*将io_addr写入寄存器MWCMD (Memory data write
command with addressincrement Register)中;进行
这个command操作后,向io_data写入的数据会传输到
dm9000内部TX SRAM中;
*/
(db->outblk)(db->io_data, skb->data, skb->len); /*将内核网络套接字结构体sk_buff的数据skb->data写入
db->io_data中*/
dev->stats.tx_bytes += skb->len; /*写完后将结构体net_device成员stats.tx_bytes加上刚刚
发送的字节数*/
db->tx_pkt_cnt++;
/* TX control: First packet immediately send, second packet queue */
if (db->tx_pkt_cnt == 1) {
/* Set TX length to DM9000 */
iow(db, DM9000_TXPLL, skb->len);
iow(db, DM9000_TXPLH, skb->len >> 8);
/* Issue TX polling command */
iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete *//*这个命令之后TX Buffer中的数据被发送出去*/
dev->trans_start = jiffies; /* save the time stamp */
} else {
/*如果发送的是第二个数据包(表明队列中此时有包发送),则将其加入队列中:将skb->len和
skb->ip_summed(控制校验操作)赋值给board_info_t中有关队列的相关成员。调用函数netif_stop_queue(dev),通
知内核现在queue已满,不能再将发送数据传到队列中,注:第二个包的发送将在tx_done中实现,这是因为当第一个数据发送完之后会产生一个中断,在中断中如果判断出事发送完成产生的中断,则会调用tx_done对应的函数,对这个函数的分析在中断函数分析中有详细讲解*/
db->queue_pkt_len = skb->len;
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&db->lock, flags);/*释放自旋锁*/
/* free this SKB */
dev_kfree_skb(skb);
return 0;
}
(1)锁机制:spin_lock(spinlock_t *my_spinlock)--->试图获取锁my_spinlock,如果锁已被别的进程持有,必须等待并不断测试锁的状态直到锁被释放。锁释放后可立即获取。
spin_lock_irqsave(spinlock_t *my_spinlock,unsigned long flags)--->与spin_lock()功能类似。额外的它自动屏蔽本地中断,并将CPU的当前状态寄存器值保存到变量flags中。
二者的区别所在: spin_lock_irqsave屏蔽了本地中断,更加安全,如果用 spin_lock的话可能会照成死锁。比如:进程A与中断运行在同一块CPU上,并且进程A与中断处理程序都spin_lock(&lock)试图获取锁。那么好让我们看看会发生什么事情,进程A正在运行,并且获取了锁,此时产生中断的话,进程A会被置位TASK_INTERRUPT状态(即进程A会被中断),但是它还持有锁啊,它还没有释放锁呢,可是中断处理程序中也要试图获取锁啊,获取不了怎么办?那就忙等待。这样进程A无法运行,中断处理函数也无法运行,就产生了死锁。而使用spin_lock_irqsave的话,由于屏蔽了本地中断,所以就不发生死锁。
(2)Tx Buffer与Rx Buffer:在DM9000内部SRAM中,地址0x0000~0x0BFF是TX Buffer, 地址0x0C00~0x3FFF是RX Buffer。在发送一个包之前,包中的有效数据必须先被存储到TX Buffer中,接下来通过设置发送控制寄存器TCR的bit[0]位来将Tx Buffer中的数据发送出去。那么如何将数据存储到Tx Buffer中呢?首先让WMCMD指向映射过来的db->io_addr,接着将要发送到TX Buffer中的数据写到db->io_addr所指向的db->io_data区域。
(2)Tx Buffer只能存放两个数据包的原因:Tx Buffer中有两个发送索引,依次为indexI和indexII。首先,如果有数据需要发送,则先通过indexI将数据写入Tx Buffer,然后设置发送控制寄存器相应的位将indexI发送。在indexI发送时,还有数据需要发送的话,就将数据通过indexII写入Tx Buffer,当indexI发送结束后,就会依次将indexII发送出去。但我们同时要明白,虽然Tx Buffer中可以存放两个数据包,但是同一时间只能有一个数据包处于发送状态。
http://liu1227787871.blog.163.com/blog/#m=0&t=1&c=fks_084071083082080067086080080095086086084064082085087074083
(五)mini2440网卡驱动DM9000之dm9000_stop
static int dm9000_stop(struct net_device *ndev){
board_info_t *db = netdev_priv(ndev);
if (netif_msg_ifdown(db))//检测ndev是否停止
dev_dbg(db->dev, "shutting down %s\n", ndev->name);
cancel_delayed_work_sync(&db->phy_poll);/*杀死延时工作队列phy_poll*/
netif_stop_queue(ndev); /*停止发送数据包*/
netif_carrier_off(ndev);/*clear carrier*/
/* free interrupt */
free_irq(ndev->irq, ndev);
dm9000_shutdown(ndev);
return 0;
}
注:关于netif的函数在netdevice.h中,以后要认真读一下,目前还不会分析。只知道大概的意思
http://liu1227787871.blog.163.com/blog/#m=0&t=1&c=fks_084071083082080067086080080095086086084064082085087074083
(五)mini2440网卡驱动DM9000之dm9000_stop
static int dm9000_stop(struct net_device *ndev){
board_info_t *db = netdev_priv(ndev);
if (netif_msg_ifdown(db))//检测ndev是否停止
dev_dbg(db->dev, "shutting down %s\n", ndev->name);
cancel_delayed_work_sync(&db->phy_poll);/*杀死延时工作队列phy_poll*/
netif_stop_queue(ndev); /*停止发送数据包*/
netif_carrier_off(ndev);/*clear carrier*/
/* free interrupt */
free_irq(ndev->irq, ndev);
dm9000_shutdown(ndev);
return 0;
}
(六)mini2440网卡驱动DM9000之dm9000_start_xmit
/* 调用时机:当网卡有数据需要发送的时候,该函数被调用 */
static int
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
board_info_t *db = netdev_priv(dev);
dm9000_dbg(db, 3, "%s:\n", __func__);
if (db->tx_pkt_cnt > 1)//只能存放两个数据包,如果已经有两个就退出,原因见注释
return 1;
spin_lock_irqsave(&db->lock, flags);/*详见注视*/
/* Move data to DM9000 TX RAM ,详见注释*/
writeb(DM9000_MWCMD, db->io_addr);/*MWCMD:/*将io_addr写入寄存器MWCMD (Memory data write
command with addressincrement Register)中;进行
这个command操作后,向io_data写入的数据会传输到
dm9000内部TX SRAM中;
*/
(db->outblk)(db->io_data, skb->data, skb->len); /*将内核网络套接字结构体sk_buff的数据skb->data写入
db->io_data中*/
dev->stats.tx_bytes += skb->len; /*写完后将结构体net_device成员stats.tx_bytes加上刚刚
发送的字节数*/
db->tx_pkt_cnt++;
/* TX control: First packet immediately send, second packet queue */
if (db->tx_pkt_cnt == 1) {
/* Set TX length to DM9000 */
iow(db, DM9000_TXPLL, skb->len);
iow(db, DM9000_TXPLH, skb->len >> 8);
/* Issue TX polling command */
iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete *//*这个命令之后TX Buffer中的数据被发送出去*/
dev->trans_start = jiffies; /* save the time stamp */
} else {
/*如果发送的是第二个数据包(表明队列中此时有包发送),则将其加入队列中:将skb->len和
skb->ip_summed(控制校验操作)赋值给board_info_t中有关队列的相关成员。调用函数netif_stop_queue(dev),通
知内核现在queue已满,不能再将发送数据传到队列中,注:第二个包的发送将在tx_done中实现,这是因为当第一个数据发送完之后会产生一个中断,在中断中如果判断出事发送完成产生的中断,则会调用tx_done对应的函数,对这个函数的分析在中断函数分析中有详细讲解*/
db->queue_pkt_len = skb->len;
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&db->lock, flags);/*释放自旋锁*/
/* free this SKB */
dev_kfree_skb(skb);
return 0;
}
(1)锁机制:spin_lock(spinlock_t *my_spinlock)--->试图获取锁my_spinlock,如果锁已被别的进程持有,必须等待并不断测试锁的状态直到锁被释放。锁释放后可立即获取。
spin_lock_irqsave(spinlock_t *my_spinlock,unsigned long flags)--->与spin_lock()功能类似。额外的它自动屏蔽本地中断,并将CPU的当前状态寄存器值保存到变量flags中。
二者的区别所在: spin_lock_irqsave屏蔽了本地中断,更加安全,如果用 spin_lock的话可能会照成死锁。比如:进程A与中断运行在同一块CPU上,并且进程A与中断处理程序都spin_lock(&lock)试图获取锁。那么好让我们看看会发生什么事情,进程A正在运行,并且获取了锁,此时产生中断的话,进程A会被置位TASK_INTERRUPT状态(即进程A会被中断),但是它还持有锁啊,它还没有释放锁呢,可是中断处理程序中也要试图获取锁啊,获取不了怎么办?那就忙等待。这样进程A无法运行,中断处理函数也无法运行,就产生了死锁。而使用spin_lock_irqsave的话,由于屏蔽了本地中断,所以就不发生死锁。
(2)Tx Buffer与Rx Buffer:在DM9000内部SRAM中,地址0x0000~0x0BFF是TX Buffer, 地址0x0C00~0x3FFF是RX Buffer。在发送一个包之前,包中的有效数据必须先被存储到TX Buffer中,接下来通过设置发送控制寄存器TCR的bit[0]位来将Tx Buffer中的数据发送出去。那么如何将数据存储到Tx Buffer中呢?首先让WMCMD指向映射过来的db->io_addr,接着将要发送到TX Buffer中的数据写到db->io_addr所指向的db->io_data区域。
(2)Tx Buffer只能存放两个数据包的原因:Tx Buffer中有两个发送索引,依次为indexI和indexII。首先,如果有数据需要发送,则先通过indexI将数据写入Tx Buffer,然后设置发送控制寄存器相应的位将indexI发送。在indexI发送时,还有数据需要发送的话,就将数据通过indexII写入Tx Buffer,当indexI发送结束后,就会依次将indexII发送出去。但我们同时要明白,虽然Tx Buffer中可以存放两个数据包,但是同一时间只能有一个数据包处于发送状态。
(七)mini2440网卡驱动DM9000之dm9000_timeout
/* 当watchdog超时时调用该函数。主要的功能是保存寄存器地址,停止队列,重启并初始化DM9000,唤醒队列,恢复寄存器地址*/
/usr/src/linux-2.6.19/include/linux/skbuff.h
static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
{
----unsigned char *tmp = skb->tail;
----SKB_LINEAR_ASSERT(skb);
----skb->tail += len;
----skb->len += len;
----if (unlikely(skb->tail>skb->end))
--------skb_over_panic(skb, len, current_text_addr());
---- return tmp;
}
+------------+ +------------+
| | | |
| | | |
| | | |
| | | |
| | | |
|------------|<-- tail |------------| <-- tail
| | | |
| | | |
| | |------------| <-- tail + len
| | | |
+------------+ +------------+
__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
skb->mac.raw = skb->data;
skb_pull(skb, ETH_HLEN);
eth = eth_hdr(skb);
if (is_multicast_ether_addr(eth->h_dest)) {
if (!compare_ether_addr(eth->h_dest, dev->broadcast))
skb->pkt_type = PACKET_BROADCAST;
else
skb->pkt_type = PACKET_MULTICAST;
}
else if (1 /*dev->flags&IFF_PROMISC */ ) {
if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr)))
skb->pkt_type = PACKET_OTHERHOST;
}
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
rawp = skb->data;
if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);
return htons(ETH_P_802_2);
}