DM9000网卡驱动接受数据从中断方式改成NAPI方式小记
平台是最最经典的s3c2440了,说了要做这件事情很久了,就是改几行代码,一直没有做。前几天逼了自己一下,终于给做了,拖延症患者伤不起。
以下是需要读者对napi机制有所熟悉:
step1:在board_info结构体里面增加struct napi_struct napi;(这个还用说……)
step2:在dm9000_probe函数中增加netif_napi_add(ndev, &db->napi, dm9000_napi_poll, 64);
dm9000_napi_poll函数实现如下:
static int dm9000_napi_poll(struct napi_struct *napi, int budget)
{
board_info_t *db = container_of(napi, board_info_t, napi);
unsigned long flags;
u8 reg_save; spin_lock_irqsave(&db->lock, flags); reg_save = readb(db->io_addr); dm9000_rx(db->ndev, budget); napi_complete(napi); iow(db, DM9000_IMR, db->imr_all); writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); return 0;
}
step3:在dm9000_open函数中增加napi_enable(&db->napi);//使能 NAPI
在dm9000_stop函数中增加napi_disable(&db->napi);//禁止 NAPI
step4:修改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)//接受中断的话执行napi_schedule
{
napi_schedule(&db->napi);
} /* Trnasmit Interrupt check */
if (int_status & 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 */
if ((int_status & ISR_PRS) == 0)//如果不是接收函数,可以重新使能中断
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;
}
step5:修改接受函数,如下:
static void
dm9000_rx(struct net_device *dev, int budget)
{
board_info_t *db = netdev_priv(dev);
struct dm9000_rxhdr rxhdr;
struct sk_buff *skb;
u8 rxbyte, *rdptr;
bool GoodPacket;
int RxLen, rxTime = 0; /* Check packet ready or not */
do {
ior(db, DM9000_MRCMDX); /* Dummy read */ /* Get most updated data */
rxbyte = readb(db->io_data); /* Status check: this byte must be 0 or 1 */
if (rxbyte & DM9000_PKT_ERR) {
dev_warn(db->dev, "status check fail: %d\n", rxbyte);
iow(db, DM9000_RCR, 0x00); /* Stop Device */
iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
break;
} if (!(rxbyte & DM9000_PKT_RDY))
break; /* A packet ready now & Get status/length */
GoodPacket = true;
writeb(DM9000_MRCMD, db->io_addr); (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); RxLen = le16_to_cpu(rxhdr.RxLen); 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_reserve(skb, 2);
rdptr = (u8 *) skb_put(skb, RxLen - 4); /* Read received packet from RX SRAM */ (db->inblk)(db->io_data, rdptr, RxLen);
dev->stats.rx_bytes += RxLen; /* Pass to upper layer */
skb->protocol = eth_type_trans(skb, dev);
if (db->rx_csum) {
if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb_checksum_none_assert(skb);
}
netif_rx(skb);
dev->stats.rx_packets++;
} else {
/* need to dump the packet's data */ (db->dumpblk)(db->io_data, RxLen);
}
rxTime++;
} while ((rxbyte & DM9000_PKT_RDY)&&(rxTime < budget));
// printk("rxTime:%d\n", rxTime);
}
改完了就可以开始测试了。
不过保险起见,最好在timeout、suspend、resume三个函数中增加响应的enable和disable函数。
性能上面的提升?呵呵~~~~~
移植中犯的一个错误,在中断函数里判断到是接收中断就直接调用完napi_schedule退出了,忽略了进中断的时候可能发送中断也被置位了的情况,结果老是timeout出错,这个是一个要注意的地方。进中断之后,可能是发送和接收中断同时置位了。
接下来就是要把dma机制移植上去,估计要花点时间了这个。
DM9000网卡驱动接受数据从中断方式改成NAPI方式小记的更多相关文章
- 【驱动】DM9000网卡驱动分析
Preface 内核源码版本:linux-2.6.18 网卡驱动·linux内核网络分层结构:http://infohacker.blog.51cto.com/6751239/122114 ...
- Linux网卡驱动移植--Dm9000网卡驱动分析
1. Linux网络体系结构由以下5部分组成 ① 系统调用接口: 位于Linux网络子系统的顶部,为应用程序提供访问内核网络子系统的方法,主要指socket系统调用. ② 协议无关接口: 实现一组基于 ...
- DM9000网卡驱动分析(转)
s3c6410自带的DM9000网卡驱动也是基于platform设备模型. 其定义的设备资源在arch/arm/mach-s3c64xx/mach-smdk6410中.有网卡的resource res ...
- iOS9 http不能访问网络——在Xcode中将https改成http方式
=====================2016-01-29更新=========================== 最近做demo时,发现将https改成http方式略有小变 1. 没有改成ht ...
- [国嵌攻略][136][DM9000网卡驱动深度分析]
网卡初始化 1.分配描述结构,alloc_etherdev 2.获取平台资源,platform_get_resource 2.1.在s3c_dm9k_resource中有相关的资源 2.2.add地址 ...
- DM9000网卡驱动深度分析
一.dm9000_porbe函数分析 不同于u-boot代码,tq2440中的DM9000更加复杂,需要分析的点也很多: /* * Search DM9000 board, allocate spac ...
- mini2440移植uboot-2008.10 (二) DM9000网卡驱动移植
还是利用 mini2440移植uboot-2008.10 (一) 修改好的代码 通过观察可以发现,mini2400使用的网卡芯片是DM9000,在uboot-2008.10源码中已经支持该芯片的驱动 ...
- [国嵌攻略][137][DM9000网卡驱动编程]
DM9000数据发送 DM9000数据发送函数是在/drivers/net/dm9000.c中的dm9000_start_xmit函数 static int dm9000_start_xmit(str ...
- Vmware改成bridge方式联网
1.在使用桥接之前,先在真机的'更改适配器设置中'禁用vmnet1和vmnet8 2.在VMware中定义一个桥接器 3.设置这个Linux虚拟机使用前一个步骤定义的桥接器--进入桥接器选择界面 4. ...
随机推荐
- c# webform网站图片另存代码
好辛苦生成了二维码,然后要实现点击“保存图片”,弹出选择路径进行保存的效果. look: string qrcodeurl = ""; string username = &quo ...
- Marathon
早上,挣扎到十点才起,刚好去吃过饭,来教研室,等待着中午的马拉松. 中午一直是很激动,有些紧张.一直到整个马拉松跑完,我达到了我唯一的目标,保持均匀的呼吸节奏.但我能明显感觉到,我并没有拼尽全力.我不 ...
- String 及其数组的相关问题
由其他类型转String一般用三种方法 方法1:采用 Object.toString()方法 请看下面的例子: Object object = getObject(); System.out.prin ...
- 2016-06-08:Windows中的bat脚本
涉及循环嵌套,启用变量延时,算术运算 @echo off setlocal enabledelayedexpansion %路径以及文件名等变量设置% set x264_exe=E:\demo\c++ ...
- 今天遇到的关于mysql的max_allowed_packet的问题
今天,运维组的同学来找我,说是备份池的文件描述没有显示出来,而且是从20号开始就不能显示,之前的文件描述就能显示,而且20号他们上传备份的数据确实是传过来的.但是是在web界面文件描述显示不出来. 先 ...
- 8天掌握EF的Code First开发系列之2 Code First开发系列之领域建模和管理实体关系
本文出自8天掌握EF的Code First开发系列,经过自己的实践整理出来. 本篇目录 理解Code First及其约定和配置 创建数据表结构 管理实体关系 三种继承模式 本章小结 本人的实验环境是V ...
- webForm练习1(地区导航)
使用LINQ TO SQL类连接数据库. create database mydb go use mydb go CREATE TABLE [dbo].[ChinaStates] ( ) COLLAT ...
- 学习笔记—Fragement +Actionbar
这里实现的是tabhost类型的菜单选项,还有下拉菜单选项的 http://www.cnblogs.com/hanyuan/archive/2012/04/11/android_actionbar_a ...
- ZZ : Ubuntu:永久修改MAC地址
方法一: 1)编辑“/etc/init.d/rc.local”文件(sudo gedit /etc/init.d/rc.local) 2)在此配置文件的最后面加上如(Ubuntu:修改网卡的MAC地址 ...
- oracle中rownum和rowid的区别
rownum和rowid的区别总括: rownum和rowid都是伪列,但是两者的根本是不同的. rownum是根据sql查询出的结果给每行分配一个逻辑编号,所以你的sql不同也就会导致最终rownu ...