Linux下网卡驱动程序的研究-毕业论文_第1页
Linux下网卡驱动程序的研究-毕业论文_第2页
Linux下网卡驱动程序的研究-毕业论文_第3页
Linux下网卡驱动程序的研究-毕业论文_第4页
Linux下网卡驱动程序的研究-毕业论文_第5页
免费预览已结束,剩余43页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

本科毕业论文本科毕业论文 (科研训练、毕业设计) 题题 目:目:Linux 下网卡驱动程序的研究下网卡驱动程序的研究 姓 名: 学 院:软件学院 系:软件工程 专 业:软件工程 年 级: 学 号: 指导教师(校内): 职称: 指导教师(校外): 职称: 年 月 I Linux 下网卡驱动程序的研究下网卡驱动程序的研究 摘要 此网卡驱动研究开发是遵循 POSIX 通用 Linux 设备标准,基于 BCM6338 芯片, 在 Linux 操作系统平台下,实现 BCM6338 芯片的基于 MII 接口的网络接口的驱动。 本文引言部分简要介绍了 Linux 操作系统、内核模块、Linux 设备驱动等基本概念,并 阐述了驱动程序的基本框架。 系统实现部分首先明确实现目标,接着阐述驱动开发的硬件平台,并分析了 BCM6338 芯片网络接口原理。然后从 Linux 网络子系统的四个层次,并分析网卡驱动的作用。接着详 细地分析与设计了网络接口驱动的实现原理和实现方法。网络接口驱动的设计大体包括以下 十一部分:加载模块、卸载模块、探测设备、初始化设备、打开设备、关闭设备、发送报文、 接收报文、检测连接状态、获取统计信息和支持多播。 最后,阐述编译环境和编译方法,并通过测试结果表明此网卡驱动能使 BCM6338 芯片 的网络接口部分正常工作。 关键词 网卡驱动; Linux; NAPI; 模块编程; BCM6338 II III Research of Network Interface Card Driver in Linux Abstract This research and development are to develop the network interface driver of BCM6338 chip which is based on POSIX-generic Linux equipment standard. The network interface part of BCM6338 chip is based MII Interface. In this paper, the introduction part expounds on Linux operating system, kernel modules, Linux device drivers, basic framework of driver development and other basic concepts. The mplementation part firstly make clear the development objective, and then expounds the hardware platform of development and analyze the principles of network interface on BCM6338 chip. Secondly, The paper explains the four layers of linux network subsystem and the function of network interface card driver. Then a detailed analysis and design of the network interface driver are presented. Network Driver Interface driver design will include the following 11 parts: loading module, unloading module, detecting equipment, equipment initialization, openning the equipment, shutting down equipment, sending messages, receiving messages, detecting connection status, getting statistical information and supporting multicast. In-depth analysis of various parts of the methods to achieve, principle and attention to detail. Finally, The paper describes compilation environment and compilation method, and the test results are showed to indicate that the network interface card driver works well. Keywords Network Interface Card Driver; Linux; NAPI; Module Programming; BCM6338 IV V 目录 第一章 引言1 1.1 Linux 简介1 1.2 内核模块 1 1.3 Linux 设备驱动.2 1.4 设备驱动框架 .3 第二章 分析与设计 .5 2.1 实现目标 5 2.2 硬件平台 5 2.2.1 BCM6338 平台描述 .5 2.2.2 BCM6338 网络接口原理7 2.3 Linux 网络子系统 .8 2.3.1 网络子系统的结构8 2.3.2 网络设备接口部分9 2.3.3 网络接口核心部分9 2.3.4 网络接口协议族部分 10 2.3.5 网络接口 Socket 部分 10 2.4 网卡驱动的作用11 2.5 网卡驱动设计 .11 2.5.1 主要数据结构.11 2.5.2 加载模块 14 2.5.3 卸载模块 14 2.5.4 探测设备 15 2.5.5 初始化设备.16 2.5.6 打开设备 17 2.5.7 关闭设备 17 2.5.8 发送报文 18 2.5.9 接收报文 20 2.5.10 检测连接状态.21 VI 2.5.11 获取统计信息.22 2.5.12 支持多播 22 第三章 编译与测试 .23 3.1 搭建编译环境 .23 3.1.1 安装 Linux 操作系统.23 3.1.2 安装交叉编译工具链 23 3.2 模块 Makefile 设计 .23 3.3 测试24 3.3.1 测试一:主机 ping 开发板24 3.3.2 测试二:开发板 ping 主机24 3.3.3 测试三:浏览 BCM6338 芯片的配置管理网站.24 第四章 结论24 致谢.24 参考文献 .24 VII Contents Chapter 1 Introduction 1 1.1 Introduction to Linux 1 1.2 Kernel Module1 1.3 Linux Device Driver2 1.4 Device Driver Skeleton3 Chapter 2 System Implementation .5 2.1 Implement Object.5 2.2 Hardware Environment5 2.2.1BCM6338 Platform.5 2.2.2BCM6338 Network Interface 7 2.3 Linux Network Subsystem.8 2.3.1 The Structure of Linux Network Subsystem8 2.3.2 Network Device Driver Layer.9 2.3.3 Network Interface Core Layer9 2.3.4 Network Interface Protocol Layer10 2.3.5 Network Interface Socket Layer 10 2.4 The Function Of Network Interface Card Driver 11 2.5 Network Interface Card Driver Design.11 2.5.1 Main Data Structure.14 2.5.2 Load Module14 2.5.3 Unload Module 14 2.5.4 Probe Device.15 2.5.5 Initialize Device16 2.5.6 Open Device17 2.5.7 Close Device .17 2.5.8 Send Packet18 2.5.9 Receive Packet20 VIII 2.5.10 Detect Link Status .21 2.5.11 Get Statistic Information22 2.5.12 Support Mutilcast.22 Chapter 3 Compilation and Test.22 3.1 Build Compilation Environment22 3.1.1 Install Linus OS .22 3.1.2 Install Cross Compilation Tool Chain 22 3.2 Module Makefile Design 22 3.3 Test24 3.3.1 Test One:The host pings BCM6338 chip24 3.3.2 The BCM6338 chip pings the host 24 3.3.3 Browse the web pages of Bcm6338 chip 25 Chapter 4 Conclusion .24 Acknowledgement 24 References .24 1 第一章第一章 引言引言 1.1 Linux 简介简介 Linux 是一套免费使用和自由传播的类 Unix 操作系统,它主要用于基于 Intel x86 系列 CPU 的计算机上。这个系统是由世界各地的成千上万的程序员设计和实现的。其目的是建 立不受任何商品化软件的版权制约的、全世界都能自由使用的 Unix 兼容产品。 Linux 最早由一位名叫 Linus Torvalds 的计算机爱好者开发,当时他是芬兰赫尔辛基大 学的学生。他的目的是设计一个代替 Minix(由一位名叫 Andrew Tannebaum 的计算机教授 编写的一个操作系统示范教学程序)的操作系统,这个操作系统可用于 386、486 或奔腾处 理器的个人计算机上,并且具有 Unix 操作系统的全部功能。Linux 以它的高效性和灵活性著 称。它能够在个人计算机上实现全部的 Unix 特性,具有多任务、多用户的能力。Linux 可在 GNU(“不是 UNIX”工程的缩写)公共许可权限下免费获得,是一个符合 POSIX 标准的操作 系统。Linux 操作系统软件包不仅包括完整的 Linux 操作系统,而且还包括了文本编辑器、 高级语言编译器等应用软件。它还包括带有多个窗口管理器的 X-Windows 图形用户界面, 如同我们使用 Windows NT 一样,允许我们使用窗口、图标和菜单对系统进行操作。 由于 Linux 是一套自由软件,用户可以无偿地得到它及其源代码,可以无偿地获得大量 的应用程序,而且可以任意地修改和补充它们1。 1.2 内核模块内核模块 每块可以在运行时添加到内核的代码,被称为一个模块。每个模块由目标代码组成没有 (连接成一个完整可执行文件),可以动态连接到运行中的内核中,通过 insmod 程序, 以及通过 rmmod 程序去连接。 内核是由负责特定任务的不同类别的模块组成的。一个模块是根据它提供的功能来说它 属于一个特别类别的。内核的划分见图 1-12。 2 图 1-1 内核的划分 1.3 Linux 设备驱动设备驱动 应用程序要对硬件设备进行操作,必须通过硬件设备的驱动程序。设备驱动程序为应用 程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以 象操作普通文件一样对硬件设备进行操作。用户的操作通过一套标准化的调用来进行,同时 这些调用与特别的驱动是独立的,设备驱动的工作就是将这些调用映射到作用于实际硬件的 和设备相关的操作上。 Linux 设备驱动程序是一个可动态加载的模块,可以与内核的其他部分分开建立,并在 需要的时候“加载”,这样模块化的加载、卸载使得内核灵活而且简单。 Linux 系统的设备分为字符设备(char device),块设备(block device)和网络设备 (network device)三种。 字符设备是指存取时没有缓存的设备,一个字符( char ) 设备是一种可以当作一个字节 流来存取的设备(如同一个文件) ,字符设备通过文件系统结点来存取,与文件系统不同的 是大部分字符设备仅仅是数据通道,只能顺序存取。 3 块设备的读写都有缓存来支持,并且块设备必须能够随机存取(random access),字符 设备则没有这个要求。 网络设备是一个能够与其他主机交换数据的设备。通常,一个接口是一个硬件设备,也 可能是一个纯粹的软件设备,一个网络接口负责发送和接收数据报文。 1.4 设备驱动框架设备驱动框架 驱动程序主要由模块装载函数、若干功能函数、模块卸载函数及若干数据结构、宏定义 等其他辅助代码。 module_init: 在模块加载函数中完成探测设备、注册设备、初始化设备等铺垫工作。 module_exit: 在模块卸载函数中完成对申请空间及占用设备号等资源的释放。 功能函数:功能函数: 提供对设备的操作接口给上层调用。 4 5 第二章第二章 分析与设计分析与设计 2.1 实现目标实现目标 基于 BCM6338 芯片平台,实现其网络接口在 Linux 操作系统下的网卡驱动程序。主要 完成网络接口原理分析,实现基于 MII 总线驱动的网络接口设备的初始化,设置接收中断处 理函数,并提供报文发送函数接口、设备状态信息查询接口及设备信息管理设置接口等。 这个网络接口驱动程序应该是完整的模块化的,符合 POSIX 通用 Linux 设备标准,能 够正确地初始化网络接口设备,并使能网络接口设备的正常工作。 2.2 硬件硬件平台平台 2.2.1 BCM6338 平台描述平台描述 BCM6338 处理器是一款高性能 ADSL2+ bridge/router 芯片,可以用它实现高性价比的 ADSL bridge 和 router。它整合了一个高性能 256MHz MIPS32 处理器、ADSL2+ AFE、ETH 和 USB PHY、硬件 ATM SAR、ETH MAC 以及 LED 指示输出和 GPIO 等,支 持全速率、符合 ITU 和 ANSI 规定的 ADSL 连接3。 ADSL PHY 除了支持基本的 DMT(离散多音)功能外,还支持 fast 和 interleave 两种 ADSL 帧格式和 I。432 ATM 物理层协议。为了支持桥和路由功能 ,它集成了一个 256MHz 的 MIPS32 CPU 和存储器管理单元 、16KB 指令缓存、8KB 数据缓存。 为了支持桥和路由功能,为 MIPS32 CPU 配置了 MMU、16KB 指令缓存、8KB 数据缓 存,并具有指令预取功能。存储界面采用 16bit、133MHz 容量从 2MB 到 256MB 的外置 SDRAM。应用于内部系统总线的一些措施提高了总线的利用率和效率。系统总线支持多 DMA 引擎,这些 DMA 引擎分别用于 ATM SAR、IU-DMA 控制器(支持 ETH 和 USB) 、内 存到内存拷贝和 PCI 块。 ETH MAC 通过 MII 与内置的、支持 Auto-MDIX 的 ETH PHY 相连。MII 接口可用于和 外部的 MII 设备,例如多口 ETH Switch 相连。16 位的 SDRAM 接口由外部的 SDRAM 和 并行 FLASH 共享。除此之外,BCM6338 整合了一个 USB1.1 界面(包括 MAC 和收发器) 、 一个 SPI 界面(可以连接 2 个 SPI 器件)用于从串行 FALSH 启动或用于控制外部设备、一 个可编程的 ADSL 同步时钟、8 个 GPIO、2 个外部中断源、LED 输出和计时器。此外还有 6 一个串行通讯口和一个 EJTAG 口用于调试。 BCM6338 的原理框图如图 2-1。 图 2-1 BCM6338 的原理框图 主要地,BCM6338 的特性具体有以下几点: 1)采用 256-MHz MIPS32 内核,兼容 R4KC 指令集,带 MMU 和 24-KB cache; 2)整合 ADSL/2/+/RE 收发器和 AFE; 3)支持 Annex A、B、C、I、J、K、L 和 ANNEX M; 4)10/100 Mbps 以太网 MAC 和具有端口自动翻转功能的 PHY; 5)硬件 ATM 信元拆装引擎(ATM SAR) ; 6)USB 1.1 驱动器; 7)133-MHz 16-bit SDRAM 界面; 8)16-bit 并行 Flash 界面; 9)用于支持串行 Flash 引导或用于控制外部以太网 switch 的 SPI 界面; 10) 226-pin PBGA 封装,1.00mm 脚距; 11) 产品的下行速率达:8Mbps(ADSL) ,12Mbps(ADSL2) ,24Mbps(ADSL2+) ; 12) 上行速率达:640Kbps(ADSL) ,1024Kbps(ADSL2/+) 。 7 2.2.2 BCM6338 网络接口原理网络接口原理 BCM6338 有两个 EMAC,EMAC1 和 EMAC2。通过介质无关接口 MII,每个 EMAC 都提供物理介质访问到内置的网卡或通过 MII 接口外接的网络收发器。除了基本的以太网访 问功能外,每个 MAC 还提供遵循 MIB 统计标准 RFC1757,RFC1643 和 IEEE802。3 的统 计计数器。 每个 EMAC 提供对数据收发的控制及协议函数。在数据包发送的过程中,数据包首先 从发送队列中传给收发器,并在头部增加前导帧,在尾部增加校验和。当收发器接收到数据 包时,首先检验数据包的目的地址和数据包的正确性,若均正确的话,则数据包被送到接收 队列中。 图 2-2 BCM6338 网络接口内部结构 IUDMA IUDMA 负责网络接口与系统内存之间的数据传输。IUDMA 控制器允许将多个缓冲区串 在一起以组成数据包。在 BCM6338,两个 EMAC 都连接到拥有四管道第 DMA。 接收接收 EMAC 接收 EMAC 接收到数据时,把数据存放在一个 256 字节的 FIFO 队列中。然后由 IUDMA 负责将数据传送到内存中,交给上层处理。 8 发送发送 EMAC 发送器中包含一个发送队列 FIFO,它一端连接系统总线,另一端连接 MII 接口。一个 要发送的数据包首先有 IUDMA 从系统内存传送到发送队列中,然后有发送 EMAC 将数据包 从发送队列传送到 MII 接口。 MII 接口接口 MII 接口提供介质无关的数据传输,确保任何类型的 PHY 与网络控制器的数据包传输, 或对 PHY 的内部寄存器操作均与介质无关。BCM6348 有两个 MII 接口。每个 MII 接口提供 18 个信号。6 个信号的数据接口支持在 MAC 和任何物理介质之间 10/100Mbps 的数据传 输。2 个信号的管理接口支持对内置网卡和外接网络设备的管理设置。默认情况下, EMAC1 通过 MII1 与内置的网卡相连。 发送器和发送控制部分发送器和发送控制部分 发送器和接收控制部分负责帧的发送。由图 2-2 可以看出,发送器接受来自 4B/5B 编 码转换器的数据,并在发送控制部分允许的条件下将数据发送到媒体。发送的数据称为 TxD。发送控制部分判定是否进行发送,这种判定基于发送 EMAC 通过 MII 接口传来的控制 信号和CSMA/CD 介质访问策略来进行。 接收器和接收控制部分接收器和接收控制部分 接收器和接收控制部分负责帧的接收。这一部分产生网络是否有载波存在的信号,产生 的依据是从 RxD 中获得。因此,网络上来的信号一方面馈送给接收器,另一方面要馈送给 接收控制部分。接收控制部分根据接收 EMAC 通过 MII 接口传来的控制信号和媒体上接收 的信号判定是否使接收器工作。 2.3 Linux 网络子系统网络子系统 2.3.1 网络子系统的结构网络子系统的结构 Linux 的网络子系统分为四部份:网络设备接口部份,网络接口核心部份,网络协议族 部份,以及网络接口 socket 层4。 网络设备接口部份主要负责从物理介质接收和发送数据。实现的文件在 linu/driver/net 目录下面。 网络接口核心部份是整个网络接口的关键部位,它为网络协议提供统一的发送接口,屏 9 蔽各种各样的物理介质,同时有负责把来自下层的包向合适的协议配送。它是网络接口的中 枢部份。它的主要实现文件在 linux/net/core 目录下,其中 linux/net/core/dev.c 为主要管理 文件。 网络协议族部份是各种具体协议实现的部份。Linux 支持 TCP/IP,IPX,X.25,AppleTalk 等的协议,各种具体协议实现的源码在 linux/net/目录下相 应的名称。在这里主要讨论 TCP/IP(IPv4)协议,实现的源码在 linux/net/ipv4,其中 linux/net/ipv4/af_inet.c 是主要的管理文件。 网络接口 Socket 层为用户提供的网络服务的编程接口。主要的源码在 linux/net/socket.c。 2.3.2 网络设备接口部分网络设备接口部分 物理层上有许多不同类型的网络接口设备。网络设备接口要负责具体物理介质的控制, 从物理介质接收以及发送数据,并对物理介质进行诸如最大数据包之类的各种设置。 驱动程序怎么样和上层建立联系的呢? 由下往上的关系,是通过驱动程序调用上层的 netif_rx()函数实现的,驱动程序通过这 个函数把接到的数据交给上层,所有的网卡驱动程序都需要调用这个函数的,这是网络接口 核心层和网络接口设备联系的桥梁。 由上往下的关系就复杂点。网络接口核心层需要知道有多少网络设备可以用,每个设备 的函数的入口地址等都要知道。网络接口核心层会维持一个 dev_base 指针,保存了网络接 口核心层所知道的所有设备。对于网络接口核心层来说,所有的设备都是一个 net_device 结构,这是从网络接口核心层的角度看到的一个抽象的设备。 如果网络接口核心层需要由下层发送数据的时候,在 dev_base 找到设备以后,就直接 调用回调函数 dev-hard_start_xmit()来让下层发数据包。 驱动程序要让网络接口核心层知道自己的存在,当然要加入 dev_base 所指向的指针链, 然后把自己的回调函数以及各种参数和 net_device 里的相应的域对应起来。加入 dev_base 所指向的指针链是通过函数 register_netdev()建立的。 而把自己的函数以和 net_device 里的相应的域及各种参数关系的建立是在模块初始化 和探测设备时进行的。 10 2.3.3 网络接口核心部分网络接口核心部分 由刚才的讨论可知,网络接口核心层知道驱动程序以及驱动程序的函数的入口是通过 *dev_base 指向的设备链的,而下层是通过调用这一层的函数 netif_rx()把数据传递个这一 层的。 网络接口核心层的上层是具体的网络协议,下层是驱动程序,我们已经解决了下层的关 系,但和上层的关系没有解决。先来讨论一下网络接口核心层和网络协议族部份的关系。 网络协议,例如 IP,ARP 等的协议要发送数据包的时候会把数据包传递给这层,那么 这种传递是通过什么函数来发生的呢?网络接口核心层通过 dev_queue_xmit()这个函数向 上层提供统一的发送接口,也就是说无论是 IP,还是 ARP 协议,通过这个函数把要发送的 数据传递给这一层,想发送数据的时候就调用这个函数就可以了。 在接收方面。网络接口核心层通过的函数 netif_rx()接收了下层发送来的数据,这时候 当然要把数据包往上层派送。所有的协议族的下层协议都需要接收数据,TCP/IP 的 IP 协议 和 ARP 协议,SPX/IPX 的 IPX 协议,AppleTalk 的 DDP 和 AARP 协议等都需要直接从网 络接口核心层接收数据,网络接口核心层接收数据是如何把包发给这些协议的呢? 这时的情形和下层的情况很相似,网络接口核心层的下面可能有许多的网卡的驱动程序, 为了知道怎么向这些驱动程序发数据,是通过*dev_base 这个指针指向的链解决的,现在解 决和上层的关系是通过 static struct packet_ptype_base 这个数组解决的。这个数组包含了 需要接收数据包的协议,以及它们的接收函数的入口。 如果有协议想把自己添加到这个数组,可以调用 dev_add_pack()函数,从数组删除是 通过 dev_remove_pack()函数进行的。 2.3.4 网络接口协议族部分网络接口协议族部分 协议层是真正实现是在这一层。根据不同的协议,在这一层内部,也可以分成不同的子 层。 以 TCP/IP 协议为例。IP 和 ARP 协议是需要直接和网络设备接口打交道的协议,也就 是需要从网络核心模块(core) 接收数据和发送数据。而其它协议如 TCP,UDP,IGMP,ICMP 则需要直接利用 IP 协议的,需要从 IP 协议接收数据,以及利用 IP 协议发送数据,同时还 要向上层 Socket 层提供直接的调用接口。 11 2.3.5 网络接口网络接口 Socket 部分部分 系统调用 socket,bind,connect,accept,send,release 等是在 Linux/net/socket.c 里面实现的,系统调用实现的函数是相应的函数名加上 sys_的前缀。 下面重点阐述 socket 系统调用。如 Socket(AF_INET,SOCK_STREAM,0)调用了 sys_socket(),sys_socket()接着调用 socket_creat(),socket_creat()就要根据用户提供的协议 族参数在 net_families里寻找合适的协议族,如果协议族没有被安装就要请求安装该协议族 的模块,然后就调用该协议族的 create()函数的处理句柄。根据参数 AF_INET,inet_creat() 就被调用了,在 inet_creat()根据服务类型在 inetswSOCK_MAX选择合适的协议,并把协 议的操作集赋给 socket 就是了,根据 SOCK_STREAM,TCP 协议被选中。 2.4 网卡驱动的作用网卡驱动的作用 网卡驱动在网络子系统中向上衔接网络接口核心层,向下屏蔽物理设备的差异性,向上 为网络接口核心层提供统一的接口。网卡驱动向下对物理设备进行操作,实现设备初始化、 数据收发和设备管理等功能。网卡驱动在网络子系统中的角色如图 2-3 所示。 图 2-3 网卡驱动在网络子系统中的角色 2.5 网卡驱动设计网卡驱动设计 2.5.1 主要数据结构主要数据结构 数据结构数据结构 BcmEnet_devctrl 但是为了系统的安全,有些设备信息不能向上层公开,驱动程序设计了一个网络接口设 备私有数据结构,用于存储网络接口设备的私有信息,方便驱动程序读取和设置网络接口设 备的信息。 typedef struct BcmEnet_devctrl struct net_device *dev; /* 指向网络接口设备的指针 */ 12 struct net_device *next_dev; /* 指向下一个网络接口设备的指针 */ int unit; /* 网络接口设备索引号 */ struct timer_list timer; /* used by Tx reclaim */ int linkstatus_polltimer; int linkstatus_phyport; int linkstatus_holder; struct net_device_stats stats; /* 网络接口设备统计信息 */ IOCTL_MIB_INFO MibInfo; volatile EmacRegisters *emac; /* EMAC 寄存器组基地址 */ volatile DmaRegs *dmaCtrl;/* DMA 寄存器组基地址 */ volatile DmaChannelCfg *txDma; /* 发送 DMA 管道控制寄存器地址 */ volatile DmaDesc *txBds; /* 发送内存块环形队列描述符首地址 */ struct sk_buff *txSkbNR_TX_BDS; /* 待发送数据包环形队列 */ int txFreeBds; /* 空闲的缓冲区个数 */ int txHeadIndex; int txTailIndex; volatile DmaChannelCfg *rxDma; /* 接收 DMA 管道控制寄存器地址 */ volatile DmaDesc *rxBds; /* 接收内存块环形队列描述符首地址 */ int rxAssignedBds; /* 已被分配的缓冲区个数 */ int rxHeadIndex; int rxTailIndex; unsigned char *buf_poolNR_RX_BDS; /* 接收缓冲区池 */ uint16 chipId; uint16 chipRev; int rxIrq; /* DMA 接收完成中断*/ 13 emac_pm_addr_t pmAddrMAX_PMADDR; /* 物理地址 */ struct tasklet_struct task; int linkState; /* 连接状态 */ ethsw_info_t ethSwitch; /* 外部交换机 */ ETHERNET_MAC_INFO EnetInfo; unsigned int vid; struct sk_buff *freeSkbList; unsigned char skbs(NR_RX_BDS * SKB_ALIGNED_SIZE) + 0x10; BcmEnet_devctrl; 数据结构数据结构 EmacRegisters 为了在驱动程序中,对 EMAC 寄存器的操作更方便些,设计了一个 EMAC 寄存器组数 据结构,其成员变量的先后顺序是按照对应的寄存器的地址从低到高排列的。这样,就不必 去记忆各寄存器的地址是多少了。类似的还有数据结构 DmaRegs 和 DmaChannelCfg,在 本文中不一一列出了。 typedef struct EmacRegisters uint32 rxControl; /* (00) 接收控制寄存器 */ uint32 rxMaxLength; /* (04) 接收长度上限寄存器 */ uint32 txMaxLength; /* (08) 发送长度上限寄存器 */ uint32 unused11; uint32 mdioFreq; /* (10) MDIO 频率 */ uint32 mdioData; /* (14) MDIO 数据 */ uint32 intMask; /* (18) 中断屏蔽寄存器*/ uint32 intStatus; /* (1c) 中断状态寄存器*/ uint32 unused23; uint32 config; /* (2c) EMAC 配置寄存器 */ uint32 txControl; /* (30) 发送控制寄存器*/ uint32 txThreshold; /* (34) 发送限制寄存器 */ uint32 mibControl; /* (38) MIB 控制寄存器*/ uint32 unused37; uint32 pm0DataLo; /* (58) perfect match 0 data lo */ uint32 pm0DataHi; /* (5C) perfect match 0 data hi (15:0) */ 14 uint32 pm1DataLo; /* (60) perfect match 1 data lo */ uint32 pm1DataHi; /* (64) perfect match 1 data hi (15:0) */ uint32 pm2DataLo; /* (68) perfect match 2 data lo */ uint32 pm2DataHi; /* (6C) perfect match 2 data hi (15:0) */ uint32 pm3DataLo; /* (70) perfect match 3 data lo */ uint32 pm3DataHi; /* (74) perfect match 3 data hi (15:0) */ uint32 unused498; /* (78-1fc) */ EmacTxMib tx_mib; /* (200) emac tx mib */ uint32 unused58; /* (260-27c) */ EmacRxMib rx_mib; /* (280) rx mib */ EmacRegisters; 2.5.2 加载模块加载模块 当一个模块被装载到正在运行的内核中时,它要请求资源并探测设备,进行初始化。驱 动程序通过 module_init()函数指定模块初始化函数5。 module_init(bcmenet_module_init); 当模块被加载时,内核调用模块初始化函数 bcmenet_module_init()。接着模块初始化 函数调用网卡设备探测函数 bcm63xx_enet_probe()。 static int _init bcmenet_module_init(void) return bcm63xx_enet_probe(); 2.5.3 卸载模块卸载模块 模块清理函数只是注销接口, 进行任何需要的内部清理, 释放 net_device 结构回系统。 驱动程序通过 module_exit()指定模块清理函数。 module_exit(bcmenet_module_cleanup); 当模块被卸载时,内核调用模块清理函数 bcmenet_module_cleanup()。 static void _exit bcmenet_module_cleanup(void) BcmEnet_devctrl *pDevCtrl; struct net_device *next_dev; 15 while (eth_root_dev) next_dev = NULL; pDevCtrl = (BcmEnet_devctrl *) netdev_priv(eth_root_dev); if (pDevCtrl) next_dev = pDevCtrl-next_dev; bcm63xx_uninit_dev(pDevCtrl); eth_root_dev = next_dev; 对所有的网卡设备,首先关闭网卡设备,包括关闭 DMA,关闭接收中断,释放未发送的 数据包,释放 ring-buffer 描述符存储空间,释放报文接收缓冲区等。接着通过调用 unregister_netdev(pDevCtrl-dev)从系统中去除网卡设备的接口,最后调用 free_netdev(pDevCtrl-dev)释放 net_device 数据结构。 2.5.4 探测设备探测设备 探测设备函数首先调用 BpGetEthernetMacInfo 函数获得所有网卡信息,然后为每个网 卡分配 net_device 数据结构和 BcmEnet_devctrl 数据结构。 dev = alloc_etherdev(sizeof(*pDevCtrl); 每个接口由一个结构 net_device 项来描述,它在 里定义。 net_device 数据结构存储一些网卡的共有属性和公共接口6。BcmEnet_devctrl 数据结构存 储着网卡的“私有信息”和“私有接口”。 BcmEnet_devctrl 数据结构的指针可通过 net_device 数据结构的指针推算而得。方法如 下: pDevCtrl = netdev_priv(dev); 另外,BcmEnet_devctrl 数据结构可通过本身的一个成员变量 dev 与 net_device 数据 结构进行绑定。 pDevCtrl-dev = dev; 接着,探测设备函数调用设备初始化函数 bcm63xx_init_dev(pDevCtrl)进行初始化每一 设备。 然后,根据探测的设备信息或默认值,初始化 net_device 数据结构和 BcmEnet_devctrl 16 数据结构的部分成员变量,设置网络设备的物理地址,分配设备名等,并将网络接口驱动的 功能函数入口地址赋值给 net_device 的公共接口。 net_device 数据结构主要的公共接口绑 定情况如下: dev-open = bcm63xx_enet_open; dev-stop = bcm63xx_enet_close; dev-hard_start_xmit = bcm63xx_enet_xmit; dev-tx_timeout = bcm63xx_enet_timeout; dev-get_stats = bcm63xx_enet_query; dev-set_mac_address = bcm_set_mac_addr; dev-set_multicast_list = bcm_set_multicast_list; dev-do_ioctl = dev-poll = bcm63xx_enet_poll; 最后,探测设备函数还然后调用 register_netdev(dev)函数注册该网络设备到系统全局 设备列表中。 2.5.5 初始化设备初始化设备 初始化设备函数首先设置网卡设备的发送 DMA 管道、接收 DMA 管道和接收中断号, 并屏蔽接收中断,设置接收中断处理函数。接着分配发送队列的所有描述符存储空间和接收 队列的描述符存储空间和缓冲区空间。 然后初始化 IUDMA,包括以下步骤: 1)IUDMA 管道的状态信息所存储的内存块必须全部初始化为 0。 2)如果每个 IUDMA 管道的最大传输长度不正确,则必须被初始化为默认值。如果支 持流控制的话,流控制寄存器和缓冲区寄存器必须写入正确的值。 3)设置每个 IUDMA 管道的基地址。 4)屏蔽每个 IUDMA 的中断。 5)设置开启某些 IUDMA 管道和关闭某些不必要的 IUDMA 管道。 最后,初始化 EMAC(介质访问控制器),包括以下步骤。 1)设置 EMAC 的接收器配置寄存器(地址为:0xFFFE6000),以设置它的工作模式。 2)设置接收数据包长度上限寄存器(地址为:0xFFFE6004)。 17 3)设置发送数据包长度上限寄存器(地址为:0xFFFE6008)。 4)设置报文发送水印寄存器(地址为:0xFFFE6034)。 5)设置 EMAC 的中断屏蔽寄存器(地址为:0xFFFE6018),屏蔽所有 EMAC 中断。 2.5.6 打开设备打开设备 打开设备函数,首先通过设备 EMAC 的以太网控制寄存器(地址为:0xFFFE602C),使 能 EMAC。接着设置 IUDMA 的控制寄存器(地址为:0xFFFE7000),使能 IUDMA。然后设 置接收 DMA 管道的控制寄存器(地址为:0xFFFE7100、0xFFFE7110、0xFFFE7120 或 0xFFFE7130),使能接收 DMA 管道。再然后开启接收中断(中断号为:23),使驱动能够相 应数据包的到来,进行处理。最后调用函数 netif_start_queue(dev) 开启报文发送队列。 static int bcm63xx_enet_open(struct net_device * dev) BcmEnet_devctrl *pDevCtrl = netdev_priv(dev); ASSERT(pDevCtrl != NULL); pDevCtrl-emac-config |= EMAC_ENABLE; pDevCtrl-dmaCtrl-controller_cfg |= DMA_MASTER_EN; pDevCtrl-rxDma-cfg |= DMA_ENABLE; BcmHalInterruptEnable(pDevCtrl-rxIrq); netif_start_queue(dev); return 0; 2.5.7 关闭设备关闭设备 关闭设备函数,首先通过调用函数 netif_stop_queue(dev)关闭报文发送队列。接着调 用函数 BcmHalInterruptDisable(pDevCtrl-rxIrq),关闭接收中断(中断号为:23),放弃所有 数据包。然后设置接收 DMA 管道的控制寄存器(地址为: 0xFFFE7100、0xFFFE7110、0xFFFE7120 或 0xFFFE7130),关闭接收 DMA 管道。在对 接收 DMA 管道的控制寄存器的写操作过程中,接收 DMA 管道可能正在传送数据,写操作 18 必须得等到数据传输结束才能完成,所以程序必须循环检测是否写操作成功,如果不成功则 继续进行写操作。最后设置 EMAC 的以太网控制寄存器(地址为:0xFFFE602C),关闭 EMAC。在对 EMAC 的以太网控制寄存器的写操作过程中,写操作必须得等到 EMAC 关闭 后才能完成,所以程序必须循环检测是否写操作成功,如果不

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论