Hi3520d 网卡驱动源码分析

一、ioremap_nocache

跟体系结构有关

二、kzalloc 与kmalloc

kzalloc调用kmalloc,在此基础上申请内存出初始化0

GFP_KERNEL:可以休眠,函数可重入

GFP_ATOMIC:不可以休眠,一般放在终端上下文申请

三、网卡驱动Src: src/drivers/net/hieth-sf/net.c

1、驱动模块

module_init(hieth_init);

module_exit(hieth_exit);

2、驱动模块init

ret =platform_device_register(&hieth_platform_device);

ret =platform_driver_register(&hieth_platform_driver);

3、平台驱动数据

static struct platform_driver hieth_platform_driver= {

.probe         = hieth_plat_driver_probe,(见第5小节)

.remove         =hieth_plat_driver_remove,

.suspend        =hieth_plat_driver_suspend,

.resume         =hieth_plat_driver_resume,

.driver         = {

.owner  = THIS_MODULE,

.name   = HIETH_DRIVER_NAME,

.bus    = &platform_bus_type,

},

};

4、平台设备数据

static struct platform_devicehieth_platform_device = {

.name = HIETH_DRIVER_NAME,

.id   = 0,

.dev = {

.platform_data  = NULL,

.dma_mask = (u64 *)~0,

.coherent_dma_mask = (u64)~0,

.release =hieth_platform_device_release,

},

.num_resources = ARRAY_SIZE(hieth_resources),

.resource = hieth_resources,

};

5、驱动探针hieth_plat_driver_probe

A. 网卡系统初始化: hieth_sys_init();

B.mdio bus初始化: hieth_mdiobus_driver_init();

C. 网卡私有probe: hieth_platdev_probe_port();(见第四节)

D. 注册网卡中断: request_irq(hieth_net_isr);(见第九节)

四、网卡私有probe:hieth_platdev_probe_port

1、申请网络设备

struct net_device *netdev = NULL;

struct hieth_netdev_local *ld;

netdev = alloc_etherdev(sizeof(*ld))

其中:alloc_etherdev  defined alloc_etherdev_mqs调用alloc_netdev_mqs

针对alloc_netdev_mqs函数:

(1)使用kzalloc申请网卡设备,总大小:sizeof(struct net_device) + sizeof_priv(= sizeof(hieth_netdev_loca))。也就是说网卡设备数据结构后面紧跟着私有网卡数据结构,后续使用通过net_priv(dev)获取私有数据

(2)硬件地址MAC,组播地址等初始化

dev_addr_init(),dev_mc_init(),dev_uc_init(),

(3)ether_setup对网卡设备部分成员初始化

(4)申请收发队列数

netif_alloc_netdev_queues和 netif_alloc_rx_queues为每个队列申请队列头,此处收发各只有1个队列,发送队列的长度为1000

(5)拷贝网卡名dev->name  = eth%d

(6)私有数据定义

structhieth_netdev_local:

struct sk_buff_head rx_head;    /*received pkgs*/

struct sk_buff_head rx_hw;  /*rx pkgs in hw*/

struct sk_buff_head tx_hw;  /*tx pkgs in hw*/

int tx_hw_cnt;

2、网卡设备成员进行设置

netdev->watchdog_timeo  = 3*HZ; 网卡传输超时(发送)以jffies为单位

超时后最终会调用hieth_net_timeout这个进行超时处理

netdev->netdev_ops      = &hieth_netdev_ops; 网卡设备操作函数初始化(见第五节)

netdev->ethtool_ops     = &hieth_ethtools_ops; 控制网络接口参数所需函数初始化(见第八节)

3、映射网络地址控制器IO空间

ld->iobase = (unsignedlong)ioremap_nocache(CONFIG_HIETH_IOBASE, CONFIG_HIETH_IOSIZE);

4、网络端口复位和初始化

/* reset and init port */

hieth_port_reset(ld, ld->port);

hieth_port_init(ld, ld->port);

5、硬件发送队列深度

ld->depth.hw_xmitq =CONFIG_HIETH_HWQ_XMIT_DEPTH; (=12)

接收则为:64 - 12 = 52

6、同PHY建立连接phy_connect()

phydev->adjust_link= hieth_adjust_link;

其中接口:获取link , duplex,speed等信息,另外打印是up还是down

7、skb队列头初始化

skb_queue_head_init(&ld->rx_head);

skb_queue_head_init(&ld->rx_hw);

skb_queue_head_init(&ld->tx_hw);

8、申请接收队列缓冲区hieth_init_skb_buffers

调用dev_alloc_skb()原子分配,大小为:1024* 2KB,即skb接收池共1024个skb,每个skb是2KB

Skb申请后对部分参数初始化:atomic_set(&skb->users,1);

9、注册网卡设备

register_netdev(netdev);

五、网卡操作函数

static const struct net_device_opshieth_netdev_ops = {

.ndo_open       =hieth_net_open, (见第六节)

.ndo_stop       = hieth_net_close,

.ndo_start_xmit     =hieth_net_hard_start_xmit,(见第七节)

.ndo_tx_timeout     =hieth_net_timeout,

.ndo_do_ioctl       =hieth_net_ioctl,

.ndo_set_mac_address    =hieth_net_set_mac_address,

.ndo_get_stats      = hieth_net_get_stats,

};

六、hieth_net_open打开网卡

1、基本流程

(1)初始化网卡数据接收函数,使用tasklet机制

ld->bf_recv.func = hieth_bfproc_recv(见第3小节); bf_recv在中断中被调用

bf_recv为tasklet,

(2)hieth_set_hwq_depth(ld);

硬件接收和发送帧队列深度设置,发送12个,接收52个。

注:软件至少需要申请与硬件接收深度相同个数的缓冲区,和硬件通过DMA一一映射。

(3)netif_carrier_off(dev);设备载波丢失

(4)hieth_feed_hw(ld);(见第2小节),填充硬件接收队列,硬件接收到的数据直接放入skb(DMA映射)

(5)启动队列netif_start_queue(dev);

(6)启动PHY,and 开启中断

(7)      监控定时器ld->monitor.function = hieth_monitor_func;(100ms)(见第4小节)

(8)支持EEE的相关设置

2、hieth_feed_hw,缓冲区skb首地址依次写入硬件接收队列

将skb通过DMA直接映射给硬件使用(目的减少数据拷贝)

(1).检测是否可配置输入队列帧首地址

(2).从接收队列缓冲池中查找空闲的skb

hieth_platdev_alloc_skb()中atomic_inc(&skb->users)

这时skb->users=2,这样网络层就不会释放skb。

(3).将该空闲skb通过DMA映射提供给网卡接收数据DMA_FROM_DEVICE

(4).将缓冲区skb首地址写入输入帧首地址寄存器IQ_ADDR

(5).将skb放入接收硬件接收队列中,便于管理

注意:这是一个while循环直到不可配置为止,将硬件可配置队列(52个)填满为止。

(6)dma_map_single注释:流式DMA映射

映射一块处理器的虚拟地址,这样可以让外设访问。该函数返回内存的物理地址。

DMA_NONE    仅用于调试目的
DMA_TO_DEVICE    数据从内存传输到设备,可认为是写操作。
DMA_FROM_DEVICE    数据从设备传输到内存,可认为是读操作。
DMA_BIDIRECTIONAL    不清楚传输方向则可用该类型。

疑问1:写寄存器不断覆盖,是否只有最后一次有效。

解答1:每写一次就加入硬件管理队列,直至写满为止(根据是否可以配置输入队列地址来判断)

疑问2:dma映射后没有找到unmap

3、数据接收函数hieth_bfproc_recv(中断调用bf_recv)

(1)hieth_hw_recv_tryup将硬件队列数据映射到内存

A.查询中断状态是否有帧等待CPU接收

B.获取帧长度

C.从硬件队列获取数据后,添加到接收队列头

skb = skb_dequeue(&ld->rx_hw);

skb_queue_tail(&ld->rx_head, skb);

(2)从接收队列头获取skb

(3)对接收到数据进行简单判断

(4)传递给上层协议处理netif_rx(skb);

注意:循环操作

疑问:skb源自缓冲池,只在probe时申请,如果释放了又没有申请,为啥还可以使用。

答案:结合4.8小节和6.2小节控制skb->users来达到目的,只有当skb->users时free_skb才会释放skb。

4、hieth_monitor_func定时监控函数

(1)填充硬件接收队列

hieth_feed_hw(ld);

(2)释放队列已经发送的skb

hieth_xmit_release_skb(ld);

七、数据发送hieth_net_hard_start_xmit(由中断启动)

1、 释放队列已经发送的skb  hieth_xmit_release_skb(ld);

(1)检查输出队列出队index是否小于硬件发送队里数

如果小于,说明已经有发送完成的,那么就需要进行skb释放

(2)从硬件队列删除已发送skb

skb_dequeue(&ld->tx_hw);

(3)释放skb

注意:循环操作

2、用户数据skb进行dma映射DMA_TO_DEVICE

3、发送用户数据hieth_xmit_real_send(ld,skb);

(1)检查是否可以配置输出队列

(2)将输出帧skb首地址写入寄存器

(3)将输出帧skb加入硬件发送队列。

4、清中断,启动硬件发送

在未发送完成前,告诉内核停止发送队列:netif_stop_queue(dev);

使能中断,发送完成后进入中断:hieth_irq_enable(ld,UD_BIT_NAME(HIETH_INT_TXQUE_RDY));

注:当硬件发送完成后会产生中断,中断里会告知内核重新启动发送,禁止中断见(9.2节)

八、网卡设备设备操作函数

staticstruct ethtool_ops hieth_ethtools_ops = {

.get_drvinfo            = hieth_ethtools_get_drvinfo,

.get_link               = hieth_ethtools_get_link,

.get_settings           = hieth_ethtools_get_settings,

.set_settings           = hieth_ethtools_set_settings,

};

九、注册网卡中断: request_irq(hieth_net_isr)

中断的主要目的就是接收和处理网卡数据,传递给协议层。

ret= request_irq(CONFIG_HIETH_IRQNUM, hieth_net_isr, IRQF_SHARED,"hieth", hieth_devs_save);

中断号:56,

IRQF_SHARED:与其他设备共享中断号主要是上行和下行端口

中断处理函数:hieth_net_isr

网卡设备:hieth_devs_save,定义如下:struct net_device*hieth_devs_save[2]指向上行和下行口

1、hieth_net_isr

(1)屏蔽所有中断

(2)读取中断状态

(3)中断处理hieth_net_isr_proc(见第2个小节)

(4)清楚中断状态

(5)       开启使能各个中断掩码

2、中断处理hieth_net_isr_proc

产生中断的情况:新报文到,或者外出报文发送完成

(1)处理接收到的数据

根据处理器,收到8个数据包后产生一个中断,如果没有8个数据包则根据超时产生中断。

将网卡数据映射到内存skb,见6.3节:

hieth_hw_recv_tryup(ld)

然后启动tasklet机制,启动后半部操作:

tasklet_schedule(&ld->bf_recv);具体操作函数见6.3

(2)硬件发送完成,中断禁止,告之内核可以重启启动发送队列

hieth_irq_disable(ld,UD_BIT_NAME(HIETH_INT_TXQUE_RDY));

netif_wake_queue(hieth_devs_save[ld->port]);

发送数据见第七节,最后会启动中断。

十、总结

该驱动通过中断来处理帧的接收和发送。接收时有底层申请好缓冲池,循环利用从不释放。没有使用NAPI机制。比较简单的网络数据处理。

Hi3520d 网卡驱动源码分析相关推荐

  1. linux网卡驱动源码分析(一)

    linux网卡驱动源码分析(一) linux struct linux内核 网络 descriptor resources 转自http://blog.csdn.net/ustc_dylan/arti ...

  2. linux网卡驱动源码分析

    转自http://blog.csdn.net/ustc_dylan/article/details/6329375 网络驱动是一种典型的PCI设备驱动,无论在嵌入式平台还是在PC领域,网络相关的项目开 ...

  3. PCI设备驱动与虚拟网卡驱动源码分析

    虚拟网卡驱动例程 #include<linux/module.h> #include<linux/sched.h> #include<linux/kernel.h> ...

  4. (转)Linux设备驱动之HID驱动 源码分析

    //Linux设备驱动之HID驱动 源码分析 http://blog.chinaunix.net/uid-20543183-id-1930836.html HID是Human Interface De ...

  5. LCD驱动源码分析(s3cfb.c)

    1.驱动源码分析大致思路 (1)分析LCD驱动首先需要分析内核的帧缓冲子系统,因为LCD驱动就是按照帧缓冲子系统提供的注册接口来注册的: (2)内核帧缓冲子系统参考博客:<Linux 帧缓冲子系 ...

  6. 通用USB设备驱动源码分析

    通用USB设备驱动源码分析 Author:aaron 前段时间写了篇<qualcomm usb modem驱动小结>的文章, 描述了自己如何为高通的一个usb modem设备写驱动的过程, ...

  7. linux打印源码,Linux打印机驱动源码分析.pdf

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp计算机&nbsp>&nbsplinux/Unix相关 Linux打印机驱动源码分析.pdf1 ...

  8. hisi3516dv300芯片基于hwmon驱动框架的温度获取驱动源码分析

    1.内核hwmon驱动框架 参考博客:<内核hwmon驱动框架详解以及海思芯片温度驱动分析>: 2.驱动实现的效果 /sys/devices/virtual/hwmon/hwmon0 # ...

  9. 字符设备驱动基础篇1——简单的驱动源码分析

    以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6575074.html module_test.c代码 #inc ...

  10. 我的内核学习笔记10:Intel GPIO驱动源码分析

    本文对Intel e3800的GPIO驱动源码进行分析. 一.概述 1.1 内核配置 Intel e3800的GPIO在Linux内核中使用的驱动名为gpio_ich(为了行文方便,将对应的设备称为& ...

最新文章

  1. 【题解】 bzoj2748 [HAOI2012]音量调节 (动态规划)
  2. 【LeetCode】172 - Factorial Trailing Zeroes
  3. 做靠谱的程序员--《程序员修炼之道》读书报告
  4. 索引原理及项目中如何使用索引实例分析
  5. 【Packet Tracer 实验笔记5】
  6. ACM之八数码问题----BFS搜索----数独游戏的模拟(下)
  7. Python写数据结构:栈(顺序存储结构)
  8. 边工作边刷题:70天一遍leetcode: day 26
  9. c4d导出html,C4D动力学如何导出fbx或者其他格式?
  10. 矩阵运算--特征矩阵
  11. 在OpenCV里车牌识别的方法1
  12. “终于懂了” 系列,安卓工程师的面试题
  13. 猿类必备:Zeplin 用法介绍
  14. mac 解压rar压缩文件
  15. 白蛋白纳米粒|莫西沙星小鼠血清白蛋白MSA纳米粒|利多卡因大鼠血清白蛋白RSA纳米粒
  16. SATA硬盘和U盘能否热插拨
  17. 百度谷歌一起搜 - 百Google度 - Chrome插件
  18. android 手机 平板同屏,酷乐视Q6投影仪Android手机/平板同屏方法汇总
  19. 浅析新媒体运营工作内容
  20. 操作系统分类——批处理、分时、实时

热门文章

  1. 从日志中截取某个时间段的日志分析
  2. DOS批处理中对含有特殊字符的文件名的处理方法
  3. 线程的sleep()方法和yield()方法有什么区别?
  4. 如何JOPtionPane的showConfirmDialog对话框button设置监视器
  5. 一个asp.net聊天是源码
  6. grasshopper插件_【Grasshopper 的奇技淫巧】 —— 插件(二)
  7. HDU 6096 树套树
  8. 逻辑卷管理和磁盘配额
  9. 正则表达式-grep命令
  10. UVALive - 7147 (数学)