免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2884 | 回复: 6
打印 上一主题 下一主题

有关Linux DM9000网卡驱动问题求助!!! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-06-08 20:38 |只看该作者 |倒序浏览
    最近一个星期在学习Linux DM9000驱动程序的编写,遇到了如下两个问题,希望前辈们指导我一下,在此谢谢了!!!

问题一:在dm9000的探测函数 dm9000_probe 里有一个宏 SET_NETDEV_DEV(ndev, &pdev->dev); 不知道这个宏起到了什么作用???
           我在网上查资料说这个宏起到了生成sys链接的作用,但是我将这个宏注释掉后再编译进内核,发现一样可以生成sys链接。

问题二:对于设置DM9000组播(多播)地址的函数 dm9000_hash_table 如下图




           该函数中有一条语句为 hash_table[3] = 0x8000;  内核中解释为广播地址,我顿时迷糊了,不是设置组播地址吗,为什么会有广播地址???

           

论坛徽章:
0
2 [报告]
发表于 2013-06-27 13:08 |只看该作者
第一问题:
SET_NETDEV_DEV(ndev, &pdev->dev); 不是生成sys链接的作用,只是让ndev中truct class_device 的struct device * dev;   指向platform_device 中的device。
/sys/devices/platform中的dm9000是由系统添加platform_device时生成的。
/sys/class/net/eth0是在linux-3.2.0源码/net/core/net-sysfs.c生成的
int netdev_register_sysfs(struct net_device *net)
{
        struct class_device *class_dev = &(net->class_dev);
        int i;
        struct class_device_attribute *attr;
        int ret;

        class_dev->class = &net_class;
        class_dev->class_data = net;

        strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE);
        if ((ret = class_device_register(class_dev)))
                goto out;
       ...
class_device_register(class_dev);经过一系列磨难,最终会调用
/* Class Device Stuff */

int class_device_create_file(struct class_device * class_dev,
                             const struct class_device_attribute * attr)
{
        int error = -EINVAL;
        if (class_dev)
                error = sysfs_create_file(&class_dev->kobj, &attr->attr);
        return error;
}
没有对class_dev->dev的判断,所以你去掉SET_NETDEV_DEV(ndev, &pdev->dev); ,还是有。
可以看出net core已做了这件事,不是驱动决定的。
可以看出SET_NETDEV_DEV(ndev, &pdev->dev); 只是让eth0和dm9000在/sys中联系在一起。
有什么做用呢,看一个函数
static int class_device_dev_link(struct class_device * class_dev)
{
        if (class_dev->dev)
                return sysfs_create_link(&class_dev->kobj,
                                         &class_dev->dev->kobj, "device";
        return 0;
}
//ldd3
int sysfs_create_link(struct kobject *kobj, struct kobject *target, char
*name);
这个函数创建一个连接(称为 name)指向目标的 sysfs 入口作为一个 kobj 的
属性. 它是一个相对连接, 因此它不管 sysfs 在任何特殊的系统中安装在哪里
都可用.
从表面上有SET_NETDEV_DEV(ndev, &pdev->dev); 的驱动
有/sys/class/net/eth0/device
没有SET_NETDEV_DEV(ndev, &pdev->dev); 的驱动则没有
具体生成device干吗,我不在继续,事实是我不知道!。第一个问题到这。

第二个问题:
对我这个从硬件开始学嵌入式的人来说真的有点难,还好有百度。一句话:

多播是第一个字节的最低位为1的所有地址,例如01-12-0f-00-00-02。广播地址是全1的48位地址,也属于多播地址。但是广播又是多播中的特例,就像是正方形属于长方形,但是正方形有长方形没有的特点。

论坛徽章:
0
3 [报告]
发表于 2013-07-25 10:14 |只看该作者
回复 2# wwxxxxll

      感谢你的帮助,在家里一直都没有网,所以到现在才回复。
      第一个问题,确实如你所说的,SET_NETDEV_DEV(ndev, &pdev->dev)只是让eth0和dm9000在/sys中联系在一起,我在开发板上验证了的。
      但是第二个问题,我并不是对多播与广播区别不明白,我想问的是 hash_table[3] = 0x8000这行代码在设置多播地址中起到了什么作用???

   

论坛徽章:
0
4 [报告]
发表于 2013-07-25 11:49 |只看该作者
本帖最后由 wwxxxxll 于 2013-07-25 12:17 编辑




那个crc在lib/crc32.h中,你自己研究一下,
那个循环和我的linux-3.2.36的内核不太一样,应该要循环64次
因为hash_val的计算有&0x3f,所以它只能是0~63
假设hash_val正好是0~63
hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);

会让hash_table[0~3]的都为0xffff
广播地址是的第一个字节全1的地址
如果是这样的话那就是255.255.255.255就是UDP的广播地址
那0x8000就没意义
所以可能hash_val不能为是63,所以要先让hash_table[3]最高位为1,也就是0x8000。
我只是猜测,我没看那个crc函数
你可以分析代码,
也可以直接把hash_val在循环中打印一下看看,有结果的话,贴出来给我看看,我最近有点忙,没时间做

回复 3# 星闪夜空


   

论坛徽章:
0
5 [报告]
发表于 2013-07-27 09:44 |只看该作者
回复 4# wwxxxxll

1、首先请看我在dm9000_hash_table函数中加的打印信息(用红色字体标注)

static void dm9000_hash_table(struct net_device *dev)
{
        board_info_t *db = (board_info_t *) dev->priv;
        struct dev_mc_list *mcptr = dev->mc_list;  /*得到多播MAC地址结构体*/
        int mc_cnt = dev->mc_count;   /*得到多播MAC地址的数目*/
        printk("mc_cnt:%d\n",mc_cnt);  /*打印出多播MAC地址的数目*/
        u32 hash_val;
        u16 i, oft, hash_table[4];
        unsigned long flags;

        printk("dm9000_hash_table()\n";

        spin_lock_irqsave(&db->lock,flags);  /*在获得自旋锁之前禁止中断,而先前的中断状态保存在flags中*/

        for (i = 0, oft = 0x10; i < 6; i++, oft++)   /*设置MAC地址*/
            iow(db, oft, dev->dev_addr);

        for (i = 0; i < 4; i++)   /*初始化hash table为0*/
            hash_table = 0x0;

        /* broadcast address */
        hash_table[3] = 0x8000;

        /*从组播列表中取出组播地址放入hash_table数组中*/
        for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
                hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f;
                hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
                printk("hash_val:%d\n",hash_val);
        }

        for(i=0;i<4;i++)
            printk("hash_table[%d]:%x\n",i,hash_table);


        /*将组播地址写入组播地址寄存器中*/
        for (i = 0, oft = 0x16; i < 4; i++) {
                iow(db, oft++, hash_table & 0xff);
                iow(db, oft++, (hash_table >> & 0xff);
        }

        spin_unlock_irqrestore(&db->lock,flags);
}

2、再看输出的结果(如下图所示)



    通过上图可知,hash_val=62,则hash_val % 16=14,hash_val / 16=3,由于之前执令hash_table[3] = 0x8000,所以执行 hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16)这段代码后,hash_table[3] = 0xc000;而hash_table[0~2]=0没有任何的变化,所以hash_table中存储的值为 0000-0000-0000-c000(十六进制),即为多播MAC地址,其第1字节的最低位为0,但是多播MAC地址的第1字节最低位不是应该为1吗???




   

论坛徽章:
0
6 [报告]
发表于 2013-07-30 12:33 |只看该作者
本帖最后由 wwxxxxll 于 2013-07-31 10:39 编辑

不好意思,我不能准确的回答你了,
不会是网络地址个cpu地址相反吧。
我瞎猜的,不要当真!
有兴趣加入我们
QQ:2379374402
linux驱动群:163617970

论坛徽章:
0
7 [报告]
发表于 2013-11-05 13:44 |只看该作者
我公司是DAVICOM正规代理商,有原厂技术支持,关于DM9000和DM9161技术方面的问题可以来信来电我们将详细为您解答联络方式:mike.lee@qftek.com.cn电话:18929384326   李生
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP