【linux驱动分析】之dm9000驱动分析

【linux驱动分析】之dm9000驱动分析(一):dm9000原理及硬件分析


【linux驱动分析】之dm9000驱动分析(一):dm9000原理及硬件分析 

【linux驱动分析】之dm9000驱动分析(二):定义在板文件中的资源和设备以及几个宏 

【linux驱动分析】之dm9000驱动分析(三):sk_buff结构分析 

【linux驱动分析】之dm9000驱动分析(四):net_device结构体 

【linux驱动分析】之dm9000驱动分析(五):另外几个重要的结构体 

【linux驱动分析】之dm9000驱动分析(六):dm9000_init和dm9000_probe的实现 

【linux驱动分析】之dm9000驱动分析(七):dm9000的卸载挂起和恢复以及打开和停止


一、了解几个概念
1、MAC
     MAC是Media Access Control 的缩写,即媒体访问控制子层协议,又翻译为媒体接入控制器。
    该协议位于OSI七层协议中数据链路层的下半部分,主要负责控制与连接物理层的物理介质。在发送数据的时候,MAC协议可以事先判断是否可以发送数据,如果可以发送将给数据加上一些控制信息,最终将数据以及控制信息以规定的格式发送到物理层;在接收数据的时候,MAC协议首先判断输入的信息并是否发生传输错误,如果没有错误,则去掉控制信息发送至LLC层。以太网MAC由IEEE-802.3以太网标准定义。
2、MII
    MII即媒体独立接口, “媒体独立”表明在不对MAC硬件重新设计或替换的情况下,任何类型的PHY设备都可以正常工作。包括分别用于发送器和接收器的两条独立信道。每条信道都有自己的数据、时钟和控制信号。MII数据接口总共需要16个信号,包括TX_ER,TXD<3:0>,TX_EN,TX_CLK,COL,RXD<3:0>,RX_EX,RX_CLK,CRS,RX_DV等。
    MII以4位半字节方式传送数据双向传输,时钟速率25MHz。其工作速率可达100Mb/s。MII管理接口是个双信号接口,一个是时钟信号,另一个是数据信号。通过管理接口,上层能监视和控制PHY。其管理是使用SMI(Serial Management Interface)总线通过读写PHY的寄存器来完成的。PHY里面的部分寄存器是IEEE定义的,这样PHY把自己的目前的状态反映到寄存器里面,MAC通过SMI总线不断的读取PHY的状态寄存器以得知目前PHY的状态,例如连接速度,双工的能力等。当然也可以通过SMI设置PHY的寄存器达到控制的目的,例如流控的打开关闭,自协商模式还是强制模式等。不论是物理连接的MII总线和SMI总线还是PHY的状态寄存器和控制寄存器都是有IEEE的规范的,因此不同公司的MAC和PHY一样可以协调工作。当然为了配合不同公司的PHY的自己特有的一些功能,驱动需要做相应的修改。

3、PHY
    PHY是物理接口收发器,它实现物理层。包括MII/GMII(介质独立接口)子层、PCS(物理编码子层)、PMA(物理介质附加)子层、PMD(物理介质相关)子层、MDI子层。
     100BaseTX采用4B/5B编码。PHY在发送数据的时候,收到MAC过来的数据(对PHY来说,没有帧的概念,对它来说,都是数据而不管什么地址,数据还是CRC),每4bit就增加1bit的检错码,然后把并行数据转化为串行流数据,再按照物理层的编码规则把数据编码,再变为模拟信号把数据送出去。收数据时的流程反之。PHY还有个重要的功能就是实现CSMA/CD的部分功能。它可以检测到网络上是否有数据在传送,如果有数据在传送中就等待,一旦检测到网络空闲,再等待一个随机时间后将送数据出去。如果两个碰巧同时送出了数据,那样必将造成冲突,这时候,冲突检测机构可以检测到冲突,然后各等待一个随机的时间重新发送数据。这个随机时间很有讲究的,并不是一个常数,在不同的时刻计算出来的随机时间都是不同的,而且有多重算法来应付出现概率很低的同两台主机之间的第二次冲突。通信速率通过双方协商,协商的结果是两个设备中能同时支持的最大速度和最好的双工模式。这个技术被称为Auto Negotiation或者NWAY。隔离变压器把PHY送出来的差分信号用差模耦合的线圈耦合滤波以增强信号,并且通过电磁场的转换耦合到连接网线的另外一端。RJ-45中1、2是传送数据的,3、6是接收数据的。新的PHY支持AUTO MDI-X功能(也需要隔离变压器支持)。它可以实现RJ-45接口的1、2上的传送信号线和3、6上的接收信号线的功能自动互相交换

    网卡工作在osi的最后两层,物理层和数据链路层,物理层定义了数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。物理层的芯片称之为PHY。数据链路层则提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能。以太网卡中数据链路层的芯片称之为MAC控制器。很多网卡的这两个部分是做到一起的。他们之间的关系是pci总线接mac总线,mac接phy,phy接网线(当然也不是直接接上的,还有一个变压装置)。
MAC 和PHY 一个是数据链路层 一个是物理层 两者通过MII传送数据。


4、曼彻斯特编码

    曼彻斯特编码又称曼彻斯特相位编码,它通过相位变化来实现每个位(图2)。通常,用一个时钟周期中部的上升沿表示“1”,下降沿表示“0”。周期末端的相位变化可忽略不计,但有时又可能需要将这种相位变化计算在内,这取决于前一位的值。


5、4B/5B编码

    4B/5B编码是一种块编码方式。它将一个4位的块编码成一个5位的块。这就使5位块内永远至少包含2个“1”转换,所以在一个5位块内总能进行时钟同步。该方法需要25%的额外开销。

二、DM9000

1、框图

2、芯片引脚图
MII接口和32位总线模式可以配置
(1)、MII接口

(2)、32位数据总线



【linux驱动分析】之dm9000驱动分析(二):定义在板文件中的资源和设备以及几个宏

硬件平台:友善之臂Tiny6410核心板 + DM9000EP
软件平台:linux-2.6.38
交叉编译器:Friendly ARM提供的arm-linux-gcc 4.5.1
一、源代码(mach-mini6410.c)
   
   
 1 /* Ethernet */
 2 #ifdef CONFIG_DM9000
 3 #define S3C64XX_PA_DM9000    (0x18000000)
 4 #define S3C64XX_SZ_DM9000    SZ_1M
 5 #define S3C64XX_VA_DM9000    S3C_ADDR(0x03b00300)
 6 
 7 static struct resource dm9000_resources[] = {
 8     [0] = {
 9         .start        = S3C64XX_PA_DM9000,
10         .end        = S3C64XX_PA_DM9000 + 3,
11         .flags        = IORESOURCE_MEM,
12     },
13     [1] = {
14         .start        = S3C64XX_PA_DM9000 + 4,
15         .end        = S3C64XX_PA_DM9000 + S3C64XX_SZ_DM9000 - 1,
16         .flags        = IORESOURCE_MEM,
17     },
18     [2] = {
19         .start        = IRQ_EINT(7),
20         .end        = IRQ_EINT(7),
21         .flags        = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
22     },
23 };
24 
25 static struct dm9000_plat_data dm9000_setup = {
26     .flags            = DM9000_PLATF_16BITONLY | DM9000_PLATF_EXT_PHY,
27     .dev_addr        = { 0x08, 0x90, 0x00, 0xa0, 0x90, 0x90 },
28 };
29 
30 static struct platform_device s3c_device_dm9000 = {
31     .name            = "dm9000",
32     .id                = 0,
33     .num_resources    = ARRAY_SIZE(dm9000_resources),
34     .resource        = dm9000_resources,
35     .dev            = {
36         .platform_data = &dm9000_setup,
37     }
38 };
39 
40 static int __init dm9000_set_mac(char *str) {
41     unsigned char addr[6];
42     unsigned int val;
43     int idx = 0;
44     char *p = str, *end;
45 
46     while (*p && idx < 6) {
47         val = simple_strtoul(p, &end, 16);
48         if (end <= p) {
49             /* convert failed */
50             break;
51         } else {
52             addr[idx++] = val;
53             p = end;
54             if (*p == ':'|| *p == '-') {
55                 p++;
56             } else {
57                 break;
58             }
59         }
60     }
61 
62     if (idx == 6) {
63         printk("Setup ethernet address to %pM\n", addr);
64         memcpy(dm9000_setup.param_addr, addr, 6);
65     }
66 
67     return 1;
68 }
69 
70 __setup("ethmac=", dm9000_set_mac);
71 #endif
72 
73 static struct map_desc mini6410_iodesc[] = {
74     {
75         /* LCD support */
76         .virtual    = (unsigned long)S3C_VA_LCD,
77         .pfn        = __phys_to_pfn(S3C_PA_FB),
78         .length     = SZ_16K,
79         .type       = MT_DEVICE,
80     },
81 #ifdef CONFIG_DM9000           /*这里的定义不知道是做什么用的*/
82     {
83         .virtual    = (u32)S3C64XX_VA_DM9000,
84         .pfn        = __phys_to_pfn(S3C64XX_PA_DM9000),
85         .length        = S3C64XX_SZ_DM9000,
86         .type        = MT_DEVICE,
87     },
88 #endif
89 };
DM9000的设备会在
platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices));
里统一注册。

二、下面分析一下上面代码中红色的宏或者函数
1、ARRAY_SIZE
  #define  ARRAY_SIZE(arr)   (sizeof(arr) / sizeof( (arr)[0] )  +  __must_be_array(arr) )
它是定义在include/linux/kernel.h中的一个宏,用来计算数组中元素的个数。
__must_be_array是编译器相关的,用来防止传入的参数不是数组,比如说传入了指针,这样的话可能回编译不通过(猜测)。
2、simple_strtoul
   
   
/**
 * simple_strtoul - convert a string to an unsigned long
 * @cp: The start of the string
 * @endp: A pointer to the end of the parsed string will be placed here
 * @base: The number base to use
 */
unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
simple_strtoul是定义在lib/vsprintf.c中的函数,它的作用是把一个字符串转换为unsigned long型的整数,并返回。
其中的endp参数存放解析后的字符串地址,base参数,是要转换的进制数。
vsprintf.c里还定义了其他好多字符串处理的函数,具体用到时去查。

3、__setup
它是定义在include/linux/init.h中的一个宏:
   
   
#define __setup(str, fn)                    \
    __setup_param(str, fn, fn, 0)

其中:str是关键字,fn是关联处理函数。__setup只是告诉内核在启动时输入串中含有str时,内核要去执行fn。Str必须以“=”符结束以使parse_args更方便解析。紧随“=”后的任何文本都会作为输入传给fn。

例如本例中的: __setup ( " ethmac= " , dm9000_set_mac);
关于__setup的更多分析见《__setup宏的作用》


【linux驱动分析】之dm9000驱动分析(三):sk_buff结构分析

源码分析
sk_buff_head和sk_buff定义在include/linux/skbuff.h中,下面是linux-2.6.38中的定义。
1、在内核中sk_buff是一个网络数据包,它是一个双向链表,而链表头就是sk_buff_head。
而sk_buff的内存布局可以分作3个段,第一个就是sk_buff自身,第二个是linear-data buff,第三个是paged-data buff(也就是skb_shared_info)。
先来看一下sk_buff_head:
struct sk_buff_head {
    /* These two members must be first. */
    struct sk_buff    *next;
    struct sk_buff    *prev;

    __u32        qlen;
    spinlock_t    lock;
};
这里可以看到前两个域是和sk_buff一致的,而且内核的注释是必须放到最前面。这里的原因是: 

这使得两个不同的结构可以放到同一个链表中,尽管sk_buff_head要比sk_buff小巧的多。另外,相同的函数可以同样应用于sk_buff和sk_buff_head。 

然后qlen域表示了当前的sk_buff链上包含多少个skb。 

lock域是自旋锁。 2、sk_buff结构
  1 /** 
  2  *    struct sk_buff - socket buffer
  3  *    @next: Next buffer in list
  4  *    @prev: Previous buffer in list
  5  *    @sk: Socket we are owned by
  6  *    @tstamp: Time we arrived
  7  *    @dev: Device we arrived on/are leaving by
  8  *    @transport_header: Transport layer header
  9  *    @network_header: Network layer header
 10  *    @mac_header: Link layer header
 11  *    @_skb_refdst: destination entry (with norefcount bit)
 12  *    @sp: the security path, used for xfrm
 13  *    @cb: Control buffer. Free for use by every layer. Put private vars here
 14  *    @len: Length of actual data
 15  *    @data_len: Data length
 16  *    @mac_len: Length of link layer header
 17  *    @hdr_len: writable header length of cloned skb
 18  *    @csum: Checksum (must include start/offset pair)
 19  *    @csum_start: Offset from skb->head where checksumming should start
 20  *    @csum_offset: Offset from csum_start where checksum should be stored
 21  *    @local_df: allow local fragmentation
 22  *    @cloned: Head may be cloned (check refcnt to be sure)
 23  *    @nohdr: Payload reference only, must not modify header
 24  *    @pkt_type: Packet class
 25  *    @fclone: skbuff clone status
 26  *    @ip_summed: Driver fed us an IP checksum
 27  *    @priority: Packet queueing priority
 28  *    @users: User count - see {datagram,tcp}.c
 29  *    @protocol: Packet protocol from driver
 30  *    @truesize: Buffer size 
 31  *    @head: Head of buffer
 32  *    @data: Data head pointer
 33  *    @tail: Tail pointer
 34  *    @end: End pointer
 35  *    @destructor: Destruct function
 36  *    @mark: Generic packet mark
 37  *    @nfct: Associated connection, if any
 38  *    @ipvs_property: skbuff is owned by ipvs
 39  *    @peeked: this packet has been seen already, so stats have been
 40  *        done for it, don't do them again
 41  *    @nf_trace: netfilter packet trace flag
 42  *    @nfctinfo: Relationship of this skb to the connection
 43  *    @nfct_reasm: netfilter conntrack re-assembly pointer
 44  *    @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
 45  *    @skb_iif: ifindex of device we arrived on
 46  *    @rxhash: the packet hash computed on receive
 47  *    @queue_mapping: Queue mapping for multiqueue devices
 48  *    @tc_index: Traffic control index
 49  *    @tc_verd: traffic control verdict
 50  *    @ndisc_nodetype: router type (from link layer)
 51  *    @dma_cookie: a cookie to one of several possible DMA operations
 52  *        done by skb DMA functions
 53  *    @secmark: security marking
 54  *    @vlan_tci: vlan tag control information
 55  */
 56 
 57 struct sk_buff {
 58     /* These two members must be first. */
 59     struct sk_buff        *next;
 60     struct sk_buff        *prev;
 61 
 62     //表示这个skb被接收的时间。
 63     ktime_t            tstamp;
 64     //表示从属于那个socket,主要是被4层用到
 65     struct sock        *sk;
 66     /*这个表示一个网络设备,当skb为输出时它表示skb将要输出的设备,当接收时,它表示输入设备。
 67      * 要注意,这个设备有可能会是虚拟设备(在3层以上看来)
 68      */
 69     struct net_device    *dev;
 70 
 71     /*
 72      * This is the control buffer. It is free to use for every
 73      * layer. Please put your private variables there. If you
 74      * want to keep them across layers you have to do a skb_clone()
 75      * first. This is owned by whoever has the skb queued ATM.
 76      */
 77     char            cb[48] __aligned(8);
 78     ///这里其实应该是dst_entry类型,不知道为什么内核要改为ul。这个域主要用于路由子系统。
 79     //这个数据结构保存了一些路由相关信息 
 80     unsigned long        _skb_refdst;
 81 #ifdef CONFIG_XFRM
 82     struct    sec_path    *sp;
 83 #endif
 84     ///这个长度表示当前的skb中的数据的长度,这个长度即包括buf中的数据也包括切片的数据,
 85     //也就是保存在skb_shared_info中的数据。这个值是会随着从一层到另一层而改变的。下面我们会对比这几个长度的。
 86     unsigned int        len,
 87     ///这个长度只表示切片数据的长度,也就是skb_shared_info中的长度
 88                     data_len;
 89     //链路层头部的长度
 90     __u16            mac_len,
 91     //这个主要用于clone的时候,它表示clone的skb的头的长度
 92                 hdr_len;
 93     //接下来是校验相关的域
 94     union {
 95         __wsum        csum;
 96         struct {
 97             __u16    csum_start;
 98             __u16    csum_offset;
 99         };
100     };
101     __u32            priority;
102     kmemcheck_bitfield_begin(flags1);
103     //首先是是否可以本地切片的标志。
104     __u8            local_df:1,
105     //为1说明头可能已被clone
106                 cloned:1,
107     //这个表示校验相关的一个标记,表示硬件驱动是否为我们已经进行了校验
108                 ip_summed:2,
109     //这个域如果为1,则说明这个skb的头域指针已经分配完毕,因此这个时候计算头的长度只需要head和data的差就可以了。
110                 nohdr:1,
111                 nfctinfo:3;
112     //pkt_type主要是表示数据包的类型,比如多播,单播,回环等等
113     __u8            pkt_type:3,
114     //这个域是一个clone标记。主要是在fast clone中被设置,我们后面讲到fast clone时会详细介绍这个域
115                 fclone:2,
116     //ipvs拥有的域
117                 ipvs_property:1,
118     //这个包已经被查看过了
119                 peeked:1,
120     //netfilter使用的域。是一个trace 标记
121                 nf_trace:1;
122     kmemcheck_bitfield_end(flags1);
123     __be16            protocol;
124     //skb的析构函数,一般都是设置为sock_rfree或者sock_wfree
125     void            (*destructor)(struct sk_buff *skb);
126 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
127     struct nf_conntrack    *nfct;
128 #endif
129 #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
130     struct sk_buff        *nfct_reasm;
131 #endif
132 #ifdef CONFIG_BRIDGE_NETFILTER
133     struct nf_bridge_info    *nf_bridge;
134 #endif
135     //接收设备的index
136     int            skb_iif;
137 
138     //流量控制的相关域
139 #ifdef CONFIG_NET_SCHED
140     __u16            tc_index;    /* traffic control index */
141 #ifdef CONFIG_NET_CLS_ACT
142     __u16            tc_verd;    /* traffic control verdict */
143 #endif
144 #endif
145 
146     __u32            rxhash;
147 
148     kmemcheck_bitfield_begin(flags2);
149     //多队列设备的映射,也就是说映射到那个队列
150     __u16            queue_mapping:16;
151 #ifdef CONFIG_IPV6_NDISC_NODETYPE
152     __u8            ndisc_nodetype:2,
153                 deliver_no_wcard:1;
154 #else
155     __u8            deliver_no_wcard:1;
156 #endif
157     __u8            ooo_okay:1;
158     kmemcheck_bitfield_end(flags2);
159 
160     /* 0/13 bit hole */
161 
162 #ifdef CONFIG_NET_DMA
163     dma_cookie_t        dma_cookie;
164 #endif
165 #ifdef CONFIG_NETWORK_SECMARK
166     __u32            secmark;
167 #endif
168     union {
169         //skb的标记
170         __u32        mark;
171         __u32        dropcount;
172     };
173     //vlan的控制tag
174     __u16            vlan_tci;
175     //传输层的头
176     sk_buff_data_t        transport_header;
177     //网络层的头
178     sk_buff_data_t        network_header;
179     //链路层的头
180     sk_buff_data_t        mac_header;
181     /* These elements must be at the end, see alloc_skb() for details.  */
182     sk_buff_data_t        tail;
183     sk_buff_data_t        end;
184     unsigned char        *head,
185                 *data;
186     //这个表示整个skb的大小,包括skb本身,以及数据
187     unsigned int        truesize;
188     //skb的引用计数
189     atomic_t        users;
190 };

【linux驱动分析】之dm9000驱动分析(四):net_device结构体

net_device结构体,定义在include/linux/netdevice.h中,这是一个很复杂的结构体,先把代码清单列出来,再用到的过程中,逐步分析,最后来这里做个总结。
下面的代码是linux-2.6.38中的。
  1 /*
  2  *    The DEVICE structure.
  3  *    Actually, this whole structure is a big mistake.  It mixes I/O
  4  *    data with strictly "high-level" data, and it has to know about
  5  *    almost every data structure used in the INET module.
  6  *
  7  *    FIXME: cleanup struct net_device such that network protocol info
  8  *    moves out.
  9  */
 10 
 11 struct net_device {
 12 
 13     /*
 14      * This is the first field of the "visible" part of this structure
 15      * (i.e. as seen by users in the "Space.c" file).  It is the name
 16      * of the interface.
 17      */
 18     char            name[IFNAMSIZ];
 19 
 20     struct pm_qos_request_list pm_qos_req;
 21 
 22     /* device name hash chain */
 23     struct hlist_node    name_hlist;
 24     /* snmp alias */
 25     char             *ifalias;
 26 
 27     /*
 28      *    I/O specific fields
 29      *    FIXME: Merge these and struct ifmap into one
 30      */
 31     unsigned long        mem_end;    /* shared mem end    */
 32     unsigned long        mem_start;    /* shared mem start    */
 33     unsigned long        base_addr;    /* device I/O address    */
 34     unsigned int        irq;        /* device IRQ number    */
 35 
 36     /*
 37      *    Some hardware also needs these fields, but they are not
 38      *    part of the usual set specified in Space.c.
 39      */
 40 
 41     unsigned char        if_port;    /* Selectable AUI, TP,..*/
 42     unsigned char        dma;        /* DMA channel        */
 43 
 44     unsigned long        state;
 45 
 46     struct list_head    dev_list;
 47     struct list_head    napi_list;
 48     struct list_head    unreg_list;
 49 
 50     /* Net device features */
 51     unsigned long        features;
 52 #define NETIF_F_SG        1    /* Scatter/gather IO. */
 53 #define NETIF_F_IP_CSUM        2    /* Can checksum TCP/UDP over IPv4. */
 54 #define NETIF_F_NO_CSUM        4    /* Does not require checksum. F.e. loopack. */
 55 #define NETIF_F_HW_CSUM        8    /* Can checksum all the packets. */
 56 #define NETIF_F_IPV6_CSUM    16    /* Can checksum TCP/UDP over IPV6 */
 57 #define NETIF_F_HIGHDMA        32    /* Can DMA to high memory. */
 58 #define NETIF_F_FRAGLIST    64    /* Scatter/gather IO. */
 59 #define NETIF_F_HW_VLAN_TX    128    /* Transmit VLAN hw acceleration */
 60 #define NETIF_F_HW_VLAN_RX    256    /* Receive VLAN hw acceleration */
 61 #define NETIF_F_HW_VLAN_FILTER    512    /* Receive filtering on VLAN */
 62 #define NETIF_F_VLAN_CHALLENGED    1024    /* Device cannot handle VLAN packets */
 63 #define NETIF_F_GSO        2048    /* Enable software GSO. */
 64 #define NETIF_F_LLTX        4096    /* LockLess TX - deprecated. Please */
 65                     /* do not use LLTX in new drivers */
 66 #define NETIF_F_NETNS_LOCAL    8192    /* Does not change network namespaces */
 67 #define NETIF_F_GRO        16384    /* Generic receive offload */
 68 #define NETIF_F_LRO        32768    /* large receive offload */
 69 
 70 /* the GSO_MASK reserves bits 16 through 23 */
 71 #define NETIF_F_FCOE_CRC    (1 << 24) /* FCoE CRC32 */
 72 #define NETIF_F_SCTP_CSUM    (1 << 25) /* SCTP checksum offload */
 73 #define NETIF_F_FCOE_MTU    (1 << 26) /* Supports max FCoE MTU, 2158 bytes*/
 74 #define NETIF_F_NTUPLE        (1 << 27) /* N-tuple filters supported */
 75 #define NETIF_F_RXHASH        (1 << 28) /* Receive hashing offload */
 76 
 77     /* Segmentation offload features */
 78 #define NETIF_F_GSO_SHIFT    16
 79 #define NETIF_F_GSO_MASK    0x00ff0000
 80 #define NETIF_F_TSO        (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
 81 #define NETIF_F_UFO        (SKB_GSO_UDP << NETIF_F_GSO_SHIFT)
 82 #define NETIF_F_GSO_ROBUST    (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
 83 #define NETIF_F_TSO_ECN        (SKB_GSO_TCP_ECN << NETIF_F_GSO_SHIFT)
 84 #define NETIF_F_TSO6        (SKB_GSO_TCPV6 << NETIF_F_GSO_SHIFT)
 85 #define NETIF_F_FSO        (SKB_GSO_FCOE << NETIF_F_GSO_SHIFT)
 86 
 87     /* List of features with software fallbacks. */
 88 #define NETIF_F_GSO_SOFTWARE    (NETIF_F_TSO | NETIF_F_TSO_ECN | \
 89                  NETIF_F_TSO6 | NETIF_F_UFO)
 90 
 91 
 92 #define NETIF_F_GEN_CSUM    (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
 93 #define NETIF_F_V4_CSUM        (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
 94 #define NETIF_F_V6_CSUM        (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
 95 #define NETIF_F_ALL_CSUM    (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
 96 
 97     /*
 98      * If one device supports one of these features, then enable them
 99      * for all in netdev_increment_features.
100      */
101 #define NETIF_F_ONE_FOR_ALL    (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \
102                  NETIF_F_SG | NETIF_F_HIGHDMA |        \
103                  NETIF_F_FRAGLIST)
104 
105     /* Interface index. Unique device identifier    */
106     int            ifindex;
107     int            iflink;
108 
109     struct net_device_stats    stats;
110     atomic_long_t        rx_dropped; /* dropped packets by core network
111                          * Do not use this in drivers.
112                          */
113 
114 #ifdef CONFIG_WIRELESS_EXT
115     /* List of functions to handle Wireless Extensions (instead of ioctl).
116      * See <net/iw_handler.h> for details. Jean II */
117     const struct iw_handler_def *    wireless_handlers;
118     /* Instance data managed by the core of Wireless Extensions. */
119     struct iw_public_data *    wireless_data;
120 #endif
121     /* Management operations */
122     const struct net_device_ops *netdev_ops;
123     const struct ethtool_ops *ethtool_ops;
124 
125     /* Hardware header description */
126     const struct header_ops *header_ops;
127 
128     unsigned int        flags;    /* interface flags (a la BSD)    */
129     unsigned short        gflags;
130         unsigned int            priv_flags; /* Like 'flags' but invisible to userspace. */
131     unsigned short        padded;    /* How much padding added by alloc_netdev() */
132 
133     unsigned char        operstate; /* RFC2863 operstate */
134     unsigned char        link_mode; /* mapping policy to operstate */
135 
136     unsigned int        mtu;    /* interface MTU value        */
137     unsigned short        type;    /* interface hardware type    */
138     unsigned short        hard_header_len;    /* hardware hdr length    */
139 
140     /* extra head- and tailroom the hardware may need, but not in all cases
141      * can this be guaranteed, especially tailroom. Some cases also use
142      * LL_MAX_HEADER instead to allocate the skb.
143      */
144     unsigned short        needed_headroom;
145     unsigned short        needed_tailroom;
146 
147     /* Interface address info. */
148     unsigned char        perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
149     unsigned char        addr_assign_type; /* hw address assignment type */
150     unsigned char        addr_len;    /* hardware address length    */
151     unsigned short          dev_id;        /* for shared network cards */
152 
153     spinlock_t        addr_list_lock;
154     struct netdev_hw_addr_list    uc;    /* Unicast mac addresses */
155     struct netdev_hw_addr_list    mc;    /* Multicast mac addresses */
156     int            uc_promisc;
157     unsigned int        promiscuity;
158     unsigned int        allmulti;
159 
160 
161     /* Protocol specific pointers */
162 
163 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
164     struct vlan_group __rcu    *vlgrp;        /* VLAN group */
165 #endif
166 #ifdef CONFIG_NET_DSA
167     void            *dsa_ptr;    /* dsa specific data */
168 #endif
169     void             *atalk_ptr;    /* AppleTalk link     */
170     struct in_device __rcu    *ip_ptr;    /* IPv4 specific data    */
171     struct dn_dev __rcu     *dn_ptr;        /* DECnet specific data */
172     struct inet6_dev __rcu    *ip6_ptr;       /* IPv6 specific data */
173     void            *ec_ptr;    /* Econet specific data    */
174     void            *ax25_ptr;    /* AX.25 specific data */
175     struct wireless_dev    *ieee80211_ptr;    /* IEEE 802.11 specific data,
176                            assign before registering */
177 
178 /*
179  * Cache lines mostly used on receive path (including eth_type_trans())
180  */
181     unsigned long        last_rx;    /* Time of last Rx
182                          * This should not be set in
183                          * drivers, unless really needed,
184                          * because network stack (bonding)
185                          * use it if/when necessary, to
186                          * avoid dirtying this cache line.
187                          */
188 
189     struct net_device    *master; /* Pointer to master device of a group,
190                       * which this device is member of.
191                       */
192 
193     /* Interface address info used in eth_type_trans() */
194     unsigned char        *dev_addr;    /* hw address, (before bcast
195                            because most packets are
196                            unicast) */
197 
198     struct netdev_hw_addr_list    dev_addrs; /* list of device
199                               hw addresses */
200 
201     unsigned char        broadcast[MAX_ADDR_LEN];    /* hw bcast add    */
202 
203 #ifdef CONFIG_RPS
204     struct kset        *queues_kset;
205 
206     struct netdev_rx_queue    *_rx;
207 
208     /* Number of RX queues allocated at register_netdev() time */
209     unsigned int        num_rx_queues;
210 
211     /* Number of RX queues currently active in device */
212     unsigned int        real_num_rx_queues;
213 #endif
214 
215     rx_handler_func_t __rcu    *rx_handler;
216     void __rcu        *rx_handler_data;
217 
218     struct netdev_queue __rcu *ingress_queue;
219 
220 /*
221  * Cache lines mostly used on transmit path
222  */
223     struct netdev_queue    *_tx ____cacheline_aligned_in_smp;
224 
225     /* Number of TX queues allocated at alloc_netdev_mq() time  */
226     unsigned int        num_tx_queues;
227 
228     /* Number of TX queues currently active in device  */
229     unsigned int        real_num_tx_queues;
230 
231     /* root qdisc from userspace point of view */
232     struct Qdisc        *qdisc;
233 
234     unsigned long        tx_queue_len;    /* Max frames per queue allowed */
235     spinlock_t        tx_global_lock;
236 
237 #ifdef CONFIG_XPS
238     struct xps_dev_maps __rcu *xps_maps;
239 #endif
240 
241     /* These may be needed for future network-power-down code. */
242 
243     /*
244      * trans_start here is expensive for high speed devices on SMP,
245      * please use netdev_queue->trans_start instead.
246      */
247     unsigned long        trans_start;    /* Time (in jiffies) of last Tx    */
248 
249     int            watchdog_timeo; /* used by dev_watchdog() */
250     struct timer_list    watchdog_timer;
251 
252     /* Number of references to this device */
253     int __percpu        *pcpu_refcnt;
254 
255     /* delayed register/unregister */
256     struct list_head    todo_list;
257     /* device index hash chain */
258     struct hlist_node    index_hlist;
259 
260     struct list_head    link_watch_list;
261 
262     /* register/unregister state machine */
263     enum { NETREG_UNINITIALIZED=0,
264            NETREG_REGISTERED,    /* completed register_netdevice */
265            NETREG_UNREGISTERING,    /* called unregister_netdevice */
266            NETREG_UNREGISTERED,    /* completed unregister todo */
267            NETREG_RELEASED,        /* called free_netdev */
268            NETREG_DUMMY,        /* dummy device for NAPI poll */
269     } reg_state:16;
270 
271     enum {
272         RTNL_LINK_INITIALIZED,
273         RTNL_LINK_INITIALIZING,
274     } rtnl_link_state:16;
275 
276     /* Called from unregister, can be used to call free_netdev */
277     void (*destructor)(struct net_device *dev);
278 
279 #ifdef CONFIG_NETPOLL
280     struct netpoll_info    *npinfo;
281 #endif
282 
283 #ifdef CONFIG_NET_NS
284     /* Network namespace this network device is inside */
285     struct net        *nd_net;
286 #endif
287 
288     /* mid-layer private */
289     union {
290         void                *ml_priv;
291         struct pcpu_lstats __percpu    *lstats; /* loopback stats */
292         struct pcpu_tstats __percpu    *tstats; /* tunnel stats */
293         struct pcpu_dstats __percpu    *dstats; /* dummy stats */
294     };
295     /* GARP */
296     struct garp_port __rcu    *garp_port;
297 
298     /* class/net/name entry */
299     struct device        dev;
300     /* space for optional device, statistics, and wireless sysfs groups */
301     const struct attribute_group *sysfs_groups[4];
302 
303     /* rtnetlink link ops */
304     const struct rtnl_link_ops *rtnl_link_ops;
305 
306     /* VLAN feature mask */
307     unsigned long vlan_features;
308 
309     /* for setting kernel sock attribute on TCP connection setup */
310 #define GSO_MAX_SIZE        65536
311     unsigned int        gso_max_size;
312 
313 #ifdef CONFIG_DCB
314     /* Data Center Bridging netlink ops */
315     const struct dcbnl_rtnl_ops *dcbnl_ops;
316 #endif
317 
318 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
319     /* max exchange id for FCoE LRO by ddp */
320     unsigned int        fcoe_ddp_xid;
321 #endif
322     /* n-tuple filter list attached to this device */
323     struct ethtool_rx_ntuple_list ethtool_ntuple_list;
324 
325     /* phy device may attach itself for hardware timestamping */
326     struct phy_device *phydev;
327 };



【linux驱动分析】之dm9000驱动分析(五):另外几个重要的结构体


除了sk_buff和net_device,dm9000驱动中用到的另外几个重要的结构体

一、platform_driver
定义在include/linux/platform_device.h中,代码如下:
1 struct platform_driver {
2     int (*probe)(struct platform_device *);
3     int (*remove)(struct platform_device *);
4     void (*shutdown)(struct platform_device *);
5     int (*suspend)(struct platform_device *, pm_message_t state);
6     int (*resume)(struct platform_device *);
7     struct device_driver driver;
8     const struct platform_device_id *id_table;
9 };
dm9000.c中的初始化:
1 static struct platform_driver dm9000_driver = {
2     .driver    = {
3         .name    = "dm9000",
4         .owner     = THIS_MODULE,
5         .pm     = &dm9000_drv_pm_ops,
6     },
7     .probe   = dm9000_probe,
8     .remove  = __devexit_p(dm9000_drv_remove),
9 };
二、net_device_ops
操作网络设备的函数,定义在include/linux/netdevice.h中,它有很多成员,这里只列出dm9000驱动用到的:
 1 static const struct net_device_ops dm9000_netdev_ops = {
 2     .ndo_open        = dm9000_open,
 3     .ndo_stop        = dm9000_stop,
 4     .ndo_start_xmit        = dm9000_start_xmit,
 5     .ndo_tx_timeout        = dm9000_timeout,
 6     .ndo_set_multicast_list    = dm9000_hash_table,
 7     .ndo_do_ioctl        = dm9000_ioctl,
 8     .ndo_change_mtu        = eth_change_mtu,
 9     .ndo_validate_addr    = eth_validate_addr,
10     .ndo_set_mac_address    = eth_mac_addr,
11 #ifdef CONFIG_NET_POLL_CONTROLLER
12     .ndo_poll_controller    = dm9000_poll_controller,
13 #endif
14 };

三、ethtool_ops
ethtool_ops定义在include/linux/ethtool.h中,它有很多成员,这里只列出dm9000驱动用到的:
 1 static const struct ethtool_ops dm9000_ethtool_ops = {
 2     .get_drvinfo        = dm9000_get_drvinfo,
 3     .get_settings        = dm9000_get_settings,
 4     .set_settings        = dm9000_set_settings,
 5     .get_msglevel        = dm9000_get_msglevel,
 6     .set_msglevel        = dm9000_set_msglevel,
 7     .nway_reset        = dm9000_nway_reset,
 8     .get_link        = dm9000_get_link,
 9     .get_wol        = dm9000_get_wol,
10     .set_wol        = dm9000_set_wol,
11      .get_eeprom_len        = dm9000_get_eeprom_len,
12      .get_eeprom        = dm9000_get_eeprom,
13      .set_eeprom        = dm9000_set_eeprom,
14     .get_rx_csum        = dm9000_get_rx_csum,
15     .set_rx_csum        = dm9000_set_rx_csum,
16     .get_tx_csum        = ethtool_op_get_tx_csum,
17     .set_tx_csum        = dm9000_set_tx_csum,
18 };
四、board_info
用来保存芯片相关的一些信息。
 1 /* Structure/enum declaration ------------------------------- */
 2 typedef struct board_info {
 3 
 4     void __iomem    *io_addr;    /* Register I/O base address */
 5     void __iomem    *io_data;    /* Data I/O address */
 6     u16         irq;        /* IRQ */
 7 
 8     u16        tx_pkt_cnt;
 9     u16        queue_pkt_len;
10     u16        queue_start_addr;
11     u16        queue_ip_summed;
12     u16        dbug_cnt;
13     u8        io_mode;        /* 0:word, 2:byte */
14     u8        phy_addr;
15     u8        imr_all;
16 
17     unsigned int    flags;
18     unsigned int    in_suspend :1;
19     unsigned int    wake_supported :1;
20     int        debug_level;
21 
22     enum dm9000_type type;
23 
24     void (*inblk)(void __iomem *port, void *data, int length);
25     void (*outblk)(void __iomem *port, void *data, int length);
26     void (*dumpblk)(void __iomem *port, int length);
27 
28     struct device    *dev;         /* parent device */
29 
30     struct resource    *addr_res;   /* resources found */
31     struct resource *data_res;
32     struct resource    *addr_req;   /* resources requested */
33     struct resource *data_req;
34     struct resource *irq_res;
35 
36     int         irq_wake;
37 
38     struct mutex     addr_lock;    /* phy and eeprom access lock */
39 
40     struct delayed_work phy_poll;
41     struct net_device  *ndev;
42 
43     spinlock_t    lock;
44 
45     struct mii_if_info mii;
46     u32        msg_enable;
47     u32        wake_state;
48 
49     int        rx_csum;
50     int        can_csum;
51     int        ip_summed;
52 } board_info_t;


【linux驱动分析】之dm9000驱动分析(六):dm9000_init和dm9000_probe的实现


一、dm9000_init
打印出驱动的版本号,注册dm9000_driver驱动,将驱动添加到总线上,执行match,如果匹配,将会执行probe函数。
1 static int __init
2 dm9000_init(void)
3 {
4     printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);
5 
6     return platform_driver_register(&dm9000_driver);
7 }

二、dm9000_probe函数
  
  
  1 /*
  2  * Search DM9000 board, allocate space and register it
  3  */
  4 static int __devinit
  5 dm9000_probe(struct platform_device *pdev)
  6 {
  7     /* 把mach-mini6410.c中定义的dm9000_plat_data传递过来 */
  8     struct dm9000_plat_data *pdata = pdev->dev.platform_data;
  9     struct board_info *db;    /* Point a board information structure */
 10     struct net_device *ndev;
 11     const unsigned char *mac_src;
 12     int ret = 0;
 13     int iosize;
 14     int i;
 15     u32 id_val;
 16 
 17     /* Init network device */
 18     /* 分配一个名为eth%d的网络设备,同时分配一个私有数据区,数据区是32字节对齐 */
 19     ndev = alloc_etherdev(sizeof(struct board_info));
 20     if (!ndev) {
 21         dev_err(&pdev->dev, "could not allocate device.\n");
 22         return -ENOMEM;
 23     }
 24     /* 把网络设备的基类dev的父指针设为平台设备的基类dev */
 25     SET_NETDEV_DEV(ndev, &pdev->dev);
 26 
 27     dev_dbg(&pdev->dev, "dm9000_probe()\n");
 28 
 29     /* setup board info structure */
 30     /* 设置私有数据,下面会具体分析这个函数 */
 31     db = netdev_priv(ndev);
 32     /* 给私有数据赋值 */
 33     db->dev = &pdev->dev;
 34     db->ndev = ndev;
 35     
 36     /* 初始化一个自旋锁和一个互斥体 */
 37     spin_lock_init(&db->lock);
 38     mutex_init(&db->addr_lock);
 39     
 40     /* 往工作队列插入一个工作,随后我们调用schedule_delayed_work就会执行传递的函数
 41      * 关于工作队列会有专门一篇文章来学习总结
 42      */
 43     INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
 44 
 45     /* 获得资源,这个函数会在下面讲解 */
 46     db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 47     db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 48     db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 49 
 50     if (db->addr_res == NULL || db->data_res == NULL ||
 51         db->irq_res == NULL) {
 52         dev_err(db->dev, "insufficient resources\n");
 53         ret = -ENOENT;
 54         goto out;
 55     }
 56     
 57     /* 获取中断号,这个中断号是不存在的,因为resource里只有一个中断号 */
 58     db->irq_wake = platform_get_irq(pdev, 1);
 59     if (db->irq_wake >= 0) {
 60         dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
 61         
 62         /* 为ndev申请中断,中断服务程序为dm9000_wol_interrupt,关于中断也会有一篇文章来学习总结 */
 63         ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
 64                   IRQF_SHARED, dev_name(db->dev), ndev);
 65         if (ret) {
 66             dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret);
 67         } else {
 68 
 69             /* test to see if irq is really wakeup capable */
 70             ret = set_irq_wake(db->irq_wake, 1);
 71             if (ret) {
 72                 dev_err(db->dev, "irq %d cannot set wakeup (%d)\n",
 73                     db->irq_wake, ret);
 74                 ret = 0;
 75             } else {
 76                 set_irq_wake(db->irq_wake, 0);
 77                 db->wake_supported = 1;
 78             }
 79         }
 80     }
 81     /* 返回dm9000内存资源的大小,下面一句是申请内存,关于内存的申请和分配也会有一篇文章 */
 82     iosize = resource_size(db->addr_res);
 83     db->addr_req = request_mem_region(db->addr_res->start, iosize,
 84                       pdev->name);
 85 
 86     if (db->addr_req == NULL) {
 87         dev_err(db->dev, "cannot claim address reg area\n");
 88         ret = -EIO;
 89         goto out;
 90     }
 91     /* 存放地址的内存空间开始地址,地址寄存器,一共占3个地址,
 92      * 分别是0x18000000,0x18000001,0x18000002,0x18000003,
 93      * 这也是一个巧妙之处,dm9000芯片的cmd引脚接的是arm11的addr2,
 94      * 所以写“0地址”代表送地址,读写4地址表示读写数据
 95      * */
 96     db->io_addr = ioremap(db->addr_res->start, iosize);
 97 
 98     if (db->io_addr == NULL) {
 99         dev_err(db->dev, "failed to ioremap address reg\n");
100         ret = -EINVAL;
101         goto out;
102     }
103 
104     iosize = resource_size(db->data_res);
105     db->data_req = request_mem_region(db->data_res->start, iosize,
106                       pdev->name);
107 
108     if (db->data_req == NULL) {
109         dev_err(db->dev, "cannot claim data reg area\n");
110         ret = -EIO;
111         goto out;
112     }
113     /* 数据寄存器的地址,1MB的空间 */
114     db->io_data = ioremap(db->data_res->start, iosize);
115 
116     if (db->io_data == NULL) {
117         dev_err(db->dev, "failed to ioremap data reg\n");
118         ret = -EINVAL;
119         goto out;
120     }
121 
122     /* fill in parameters for net-dev structure */
123     ndev->base_addr = (unsigned long)db->io_addr;
124     ndev->irq    = db->irq_res->start;
125 
126     /* ensure at least we have a default set of IO routines */
127     /* iosize是一个很大的值,这里是先保证有个默认值位宽,32位 */
128     dm9000_set_io(db, iosize);
129 
130     /* check to see if anything is being over-ridden */
131     if (pdata != NULL) {
132         /* check to see if the driver wants to over-ride the
133          * default IO width */
134 
135         if (pdata->flags & DM9000_PLATF_8BITONLY)
136             dm9000_set_io(db, 1);
137         /*
138          * 我们这里设置的是16位,他会做下面几件事:
139          * db->dumpblk = dm9000_dumpblk_16bit;
140          * db->outblk  = dm9000_outblk_16bit;
141          * db->inblk   = dm9000_inblk_16bit;
142          */
143         if (pdata->flags & DM9000_PLATF_16BITONLY)
144             dm9000_set_io(db, 2);
145 
146         if (pdata->flags & DM9000_PLATF_32BITONLY)
147             dm9000_set_io(db, 4);
148 
149         /* check to see if there are any IO routine
150          * over-rides */
151 
152         if (pdata->inblk != NULL)
153             db->inblk = pdata->inblk;
154 
155         if (pdata->outblk != NULL)
156             db->outblk = pdata->outblk;
157 
158         if (pdata->dumpblk != NULL)
159             db->dumpblk = pdata->dumpblk;
160 
161         db->flags = pdata->flags;
162     }
163 
164 #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
165     db->flags |= DM9000_PLATF_SIMPLE_PHY;
166 #endif
167     /*
168      * dm9000_reset函数是执行下面两句话,中间有延时,这里省略了
169      * writeb(DM9000_NCR, db->io_addr); //先写NCR寄存器的地址到“0地址”(写到0地址就代表写地址)
170      * writeb(NCR_RST, db->io_data);    //再给“4地址”写NCR_RST(0x01),即NCR = 1;
171      * 读写“4地址”就相当于发送数据,cmd引脚连的是addr2,dm9000地址线数据线复用
172      * */
173     dm9000_reset(db);
174 
175     /* try multiple times, DM9000 sometimes gets the read wrong */
176     /* 下面所做的是读出dm9000的供应商ID和产品ID */
177     for (i = 0; i < 8; i++) {
178         /* ior是从reg读出数据,类型是u8,它的原理与上面分析reset函数的原理是一样的 */
179         id_val  = ior(db, DM9000_VIDL);
180         id_val |= (u32)ior(db, DM9000_VIDH) << 8;
181         id_val |= (u32)ior(db, DM9000_PIDL) << 16;
182         id_val |= (u32)ior(db, DM9000_PIDH) << 24;
183 
184         if (id_val == DM9000_ID)
185             break;
186         dev_err(db->dev, "read wrong id 0x%08x\n", id_val);
187     }
188 
189     if (id_val != DM9000_ID) {
190         dev_err(db->dev, "wrong id: 0x%08x\n", id_val);
191         ret = -ENODEV;
192         goto out;
193     }
194 
195     /* Identify what type of DM9000 we are working on */
196     /* 读出芯片版本寄存器,判断dm9000的型号,默认是dm9000E */
197     id_val = ior(db, DM9000_CHIPR);
198     dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);
199 
200     switch (id_val) {
201     case CHIPR_DM9000A:
202         db->type = TYPE_DM9000A;
203         break;
204     case CHIPR_DM9000B:
205         db->type = TYPE_DM9000B;
206         break;
207     default:
208         dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
209         db->type = TYPE_DM9000E;
210     }
211 
212     /* dm9000a/b are capable of hardware checksum offload */
213     if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
214         db->can_csum = 1;
215         db->rx_csum = 1;
216         ndev->features |= NETIF_F_IP_CSUM;
217     }
218 
219     /* from this point we assume that we have found a DM9000 */
220 
221     /* driver system function */
222     /* 这个函数是初始化ndev的一些成员 */
223     ether_setup(ndev);
224 
225     /* 下面也是初始化ndev的一些成员 */
226     ndev->netdev_ops    = &dm9000_netdev_ops;
227     ndev->watchdog_timeo    = msecs_to_jiffies(watchdog);
228     ndev->ethtool_ops    = &dm9000_ethtool_ops;
229 
230     db->msg_enable       = NETIF_MSG_LINK;
231     db->mii.phy_id_mask  = 0x1f;
232     db->mii.reg_num_mask = 0x1f;
233     db->mii.force_media  = 0;
234     db->mii.full_duplex  = 0;
235     db->mii.dev         = ndev;
236     db->mii.mdio_read    = dm9000_phy_read;
237     db->mii.mdio_write   = dm9000_phy_write;
238 
239     mac_src = "eeprom";
240     /* node address是在网络中的一个电脑或终端的号码或名字,
241      * 这里从eeprom读取,由于我们没有,所以它读回来的是6个FF
242      * */
243     /* try reading the node address from the attached EEPROM */
244     for (i = 0; i < 6; i += 2)
245         dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
246 
247     /* try MAC address passed by kernel command line */
248     /* 这个函数是友善之臂添加的,它在mach-mini6410里添加了这样一句话__setup("ethmac=", dm9000_set_mac);
249      * 内核启动时,遇到"ethmac="回去执行dm9000_set_mac函数,所以就实现了mac从内核传递过来
250      * 这也是一个很巧妙的设计,需要写一篇文章学习总结一下
251      * */
252     if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
253         mac_src = "param data";
254         memcpy(ndev->dev_addr, pdata->param_addr, 6);
255     }
256     /* 下面是读取mac的几种方法,当前这一种是从dm9000的Physical Address Register读取 */
257     if (!is_valid_ether_addr(ndev->dev_addr)) {
258         /* try reading from mac */
259         mac_src = "chip";
260         for (i = 0; i < 6; i++)
261             ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
262     }
263     /* 从pdata里的dev_addr读取 */
264     if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
265         mac_src = "platform data";
266         memcpy(ndev->dev_addr, pdata->dev_addr, 6);
267     }
268     /* 没有读到有效的mac地址,提示用ifconfig命令设置 */
269     if (!is_valid_ether_addr(ndev->dev_addr))
270         dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
271              "set using ifconfig\n", ndev->name);
272 
273     /* 
274      * 这里由于ndev是我们定义的一个局部变量,所以要ndev传递给平台设备pdev
275      * 即pdev->dev->p->driver_data = ndev;
276      * 要使用是通过platform_get_drvdata获得
277      * */
278     platform_set_drvdata(pdev, ndev);
279     /* net_device结构体初始化好后,剩余的工作就是把该结构传递给register_netdev函数,
280      * 当调用register_netdev后就可以用驱动程序操作设备了,所以
281      * 必须在初始化一切事情后再注册
282      * */
283     ret = register_netdev(ndev);
284 
285     if (ret == 0)
286         printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
287                ndev->name, dm9000_type_to_char(db->type),
288                db->io_addr, db->io_data, ndev->irq,
289                ndev->dev_addr, mac_src);
290     return 0;
291 
292 out:
293     dev_err(db->dev, "not found (%d).\n", ret);
294 
295     dm9000_release_board(pdev, db);
296     free_netdev(ndev);
297 
298     return ret;
299 }
300 /*********** probe函数大功告成 *************/
301 

三、总结probe函数分析是留下的问题
在上面用红色标记出来了要分析的东西
1、分析netdev_priv
在执行 ndev = alloc_etherdev(sizeof(struct board_info));时,先分配了一个net_device结构,又分配了一个board_info结构体,作为ndev的私有数据,然后执行了db = netdev_priv( ndev );来获得私有数据的开始地址,并在以后做初始化。
在probe函数最后,通过platform_set_drvdata函数把ndev结构传给了平台设备,以供使用,那么我猜想这里把board_info也传过去了,以后也可以用,获得它的地址的方法是通过下面的函数。
303 /**
304  *    netdev_priv - access network device private data
305  *    @dev: network device
306  *
307  * Get network device private data
308  */
309 static inline void *netdev_priv(const struct net_device *dev)
310 {
311     return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
312 }

2、platform_get_resource函数分析
46     db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
47     db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
48     db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
platform_data的关系是这样的:platform device->dev->platform_data
对于dm9000驱动来说是这样实现的:
8     struct dm9000_plat_data *pdata = pdev->dev.platform_data;
static struct dm9000_plat_data dm9000_setup = {
	.flags		= DM9000_PLATF_16BITONLY | DM9000_PLATF_EXT_PHY,
	.dev_addr       = { 0x08, 0x90, 0x00, 0xa0, 0x90, 0x90 },
}; 

3、以后要写文章总结的东西
(1)、关于工作队列的要总结一下
43     INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);

(2)、关于内核中断的原理和操作方法
63         ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
64                   IRQF_SHARED, dev_name(db->dev), ndev);

(3)、关于内核内存分配和操作方法
83     db->addr_req = request_mem_region(db->addr_res->start, iosize,
84                       pdev->name);
(4)、关于__setup的作用
__setup("ethmac=", dm9000_set_mac);



【linux驱动分析】之dm9000驱动分析(七):dm9000的卸载挂起和恢复以及打开和停止


分析dm9000的卸载,挂起和恢复,以及dm9000的打开和停止。涉及到的函数为:
 1 static int __devexit
 2   dm9000_drv_remove(struct platform_device *pdev)
 3 static int
 4  dm9000_drv_suspend(struct device *dev)
 5 static int
 6  dm9000_drv_resume(struct device *dev)
 7 static int
 8  dm9000_open(struct net_device *dev)
 9 static int
10  dm9000_stop(struct net_device *ndev)
一、卸载驱动
驱动中可以看到,在模块卸载时执行
platform_driver_unregister(&dm9000_driver);
在卸载platform_driver时会执行remove函数,remove函数的功能是把设备从内核中移除,释放内存区域。下面给出dm9000_drv_remove函数的代码:
   
   
 1 static int __devexit
 2 dm9000_drv_remove(struct platform_device *pdev)
 3 {
 4     struct net_device *ndev = platform_get_drvdata(pdev);
 5 
 6     platform_set_drvdata(pdev, NULL);
 7 
 8     unregister_netdev(ndev);
 9     dm9000_release_board(pdev, netdev_priv(ndev));
10     free_netdev(ndev);        /* free device structure */
11 
12     dev_dbg(&pdev->dev, "released and freed device\n");
13     return 0;
14 }
15 
16 
17 /* dm9000_release_board
18  *
19  * release a board, and any mapped resources
20  */
21 
22 static void
23 dm9000_release_board(struct platform_device *pdev, struct board_info *db)
24 {
25     /* unmap our resources */
26 
27     iounmap(db->io_addr);
28     iounmap(db->io_data);
29 
30     /* release the resources */
31 
32     release_resource(db->data_req);
33     kfree(db->data_req);
34 
35     release_resource(db->addr_req);
36     kfree(db->addr_req);
37 }
二、关于电源管理的设备的挂起和恢复函数
   
   

suspend函数并不真正把设备从内核中移除,而只是标志设备为removed状态,并设置挂起标志位为1,最后关闭设备。

resume函数将挂起的设备复位并初始化,软后将设备标志为attached状态,并设置挂起标志位为0。

 1 static int
 2 dm9000_drv_suspend(struct device *dev)
 3 {
 4     struct platform_device *pdev = to_platform_device(dev);
 5     struct net_device *ndev = platform_get_drvdata(pdev);
 6     board_info_t *db;
 7 
 8     if (ndev) {
 9         db = netdev_priv(ndev);
10         db->in_suspend = 1;
11 
12         if (!netif_running(ndev))
13             return 0;
14 
15         netif_device_detach(ndev);
16 
17         /* only shutdown if not using WoL */
18         if (!db->wake_state)
19             dm9000_shutdown(ndev);
20     }
21     return 0;
22 }
23 
24 static int
25 dm9000_drv_resume(struct device *dev)
26 {
27     struct platform_device *pdev = to_platform_device(dev);
28     struct net_device *ndev = platform_get_drvdata(pdev);
29     board_info_t *db = netdev_priv(ndev);
30 
31     if (ndev) {
32         if (netif_running(ndev)) {
33             /* reset if we were not in wake mode to ensure if
34              * the device was powered off it is in a known state */
35             if (!db->wake_state) {
36                 dm9000_reset(db);
37                 dm9000_init_dm9000(ndev);
38             }
39 
40             netif_device_attach(ndev);
41         }
42 
43         db->in_suspend = 0;
44     }
45     return 0;
46 }
三、dm9000的打开和停止

1、打开函数dm9000_open
 1 /*
 2  *  Open the interface.
 3  *  The interface is opened whenever "ifconfig" actives it.
 4  */
 5 static int
 6 dm9000_open(struct net_device *dev)
 7 {
 8     board_info_t *db = netdev_priv(dev);
 9     unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
10 
11     /* db结构体中的成员msg_enble,在probe函数中赋值为NETIF_MSG_LINK */
12     if (netif_msg_ifup(db))
13         dev_dbg(db->dev, "enabling %s\n", dev->name);
14 
15     /* If there is no IRQ type specified, default to something that
16      * may work, and tell the user that this is a problem */
17 
18     if (irqflags == IRQF_TRIGGER_NONE)
19         dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
20 
21     irqflags |= IRQF_SHARED;
22     /* 申请中断,中断函数dm9000_interrupt */
23     if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
24         return -EAGAIN;
25 
26     /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
27     iow(db, DM9000_GPR, 0);    /* REG_1F bit0 activate phyxcer */
28     mdelay(1); /* delay needs by DM9000B */
29 
30     /* Initialize DM9000 board */
31     dm9000_reset(db);
32     /* dm9000初始化,下面会对这个函数做详细分析 */
33     dm9000_init_dm9000(dev);
34 
35     /* Init driver variable */
36     db->dbug_cnt = 0;
37 
38     /* 检查mii接口 
39      * Returns 1 if the duplex mode changed, 0 if not.
40      * If the media type is forced, always returns 0.
41      * */
42     mii_check_media(&db->mii, netif_msg_link(db), 1);
43     /* 开启网络接口数据发送队列 */
44     netif_start_queue(dev);
45     /*延时一段时间执行dm9000_poll_work,原来在probe函数里把这个函数加入了工作队列,现在来调度执行*/
46     dm9000_schedule_poll(db);
47 
48     return 0;
49 }
2、dm9000_init_dm9000函数
 1 /*
 2  * Initialize dm9000 board
 3  */
 4 static void
 5 dm9000_init_dm9000(struct net_device *dev)
 6 {
 7     board_info_t *db = netdev_priv(dev);
 8     unsigned int imr;
 9     unsigned int ncr;
10 
11     dm9000_dbg(db, 1, "entering %s\n", __func__);
12 
13     /* I/O mode */
14     db->io_mode = ior(db, DM9000_ISR) >> 6;    /* ISR bit7:6 keeps I/O mode */
15 
16     /* Checksum mode */
17     dm9000_set_rx_csum_unlocked(dev, db->rx_csum);
18 
19     iow(db, DM9000_GPCR, GPCR_GEP_CNTL);    /* Let GPIO0 output */
20 
21     ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;
22 
23     /* if wol is needed, then always set NCR_WAKEEN otherwise we end
24      * up dumping the wake events if we disable this. There is already
25      * a wake-mask in DM9000_WCR */
26     if (db->wake_supported)
27         ncr |= NCR_WAKEEN;
28 
29     iow(db, DM9000_NCR, ncr);
30 
31     /* Program operating register */
32     iow(db, DM9000_TCR, 0);            /* TX Polling clear */
33     iow(db, DM9000_BPTR, 0x3f);    /* Less 3Kb, 200us */
34     iow(db, DM9000_FCR, 0xff);    /* Flow Control */
35     iow(db, DM9000_SMCR, 0);        /* Special Mode */
36     /* clear TX status */
37     iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
38     iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */
39 
40     /* Set address filter table */
41     dm9000_hash_table_unlocked(dev);
42 
43     imr = IMR_PAR | IMR_PTM | IMR_PRM;
44     if (db->type != TYPE_DM9000E)
45         imr |= IMR_LNKCHNG;
46 
47     db->imr_all = imr;
48 
49     /* Enable TX/RX interrupt mask */
50     iow(db, DM9000_IMR, imr);
51 
52     /* Init Driver variable */
53     db->tx_pkt_cnt = 0;
54     db->queue_pkt_len = 0;
55     dev->trans_start = jiffies;
56 }
3、停止函数dm9000_stop
它会做与dm9000_stop相反的事情。
 1 /*
 2  * Stop the interface.
 3  * The interface is stopped when it is brought.
 4  */
 5 static int
 6 dm9000_stop(struct net_device *ndev)
 7 {
 8     board_info_t *db = netdev_priv(ndev);
 9 
10     if (netif_msg_ifdown(db))
11         dev_dbg(db->dev, "shutting down %s\n", ndev->name);
12 
13     cancel_delayed_work_sync(&db->phy_poll);
14 
15     netif_stop_queue(ndev);
16     netif_carrier_off(ndev);
17 
18     /* free interrupt */
19     free_irq(ndev->irq, ndev);
20 
21     dm9000_shutdown(ndev);
22 
23     return 0;
24 }


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值