Mini2440 DM9000 驱动分析(一)

硬件特性

Mini2440开发板上DM9000的电气连接和Mach-mini2440.c文件的关系:

PW_RST 连接到复位按键,复位按键按下,低电平触发重新初始化,初始化完成后5us后可以使用(The DM9000 is ready after 5us when this pin deasserted )

CMD 连接到s3c2440 的ADD2 pin

INT 连接到s3c2440 的EINT7/GPF7,将中断控制端口

LINK_ACT 连接到网络接口的GLEDK pin,连接到LINK LED,这样网卡上面的灯才可以亮

LINK_O、WAKEUP、SPEED100# 这三个pin并联之后连接的网络接口的YLEDK pin

AEN 连接到s3c2440 的nGCS4/GPA15 pin

IOR# 连接到s3c2440 的nOE pin

IOW# 连接到s3c2440 的 nWE pin

IOWAIT 直接通过电阻借电源,即高电平

TXO-、TXO+、RX-、RX+ 直接接到网络端口用于数据收发

SD0-15 连接到s3c2440 的DATA0-15

其中片选信号AEN使用了nGCS4,所以网卡的内存区域在BANK4,也就是从地址0x20000000开始。

DM9000的TXD[2:0]作为strap pin在电路图中是空接的,所以IO base是300H。

中断使用了EINT7。

代码如下:

 

/* DM9000AEP 10/100 ethernet controller */

#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)

static struct resource mini2440_dm9k_resource[] = {

[0] = {

.start = MACH_MINI2440_DM9K_BASE,

.end = MACH_MINI2440_DM9K_BASE + 3,

.flags = IORESOURCE_MEM

},

[1] = {

.start = MACH_MINI2440_DM9K_BASE + 4,

.end = MACH_MINI2440_DM9K_BASE + 7,

.flags = IORESOURCE_MEM

},

[2] = {

.start = IRQ_EINT7,

.end = IRQ_EINT7,

.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,

}

};

/*

* * The DM9000 has no eeprom, and it's MAC address is set by

* * the bootloader before starting the kernel.

* */

static struct dm9000_plat_data mini2440_dm9k_pdata = {

.flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),

};

static struct platform_device mini2440_device_eth = {

.name = "dm9000",

.id = -1,

.num_resources = ARRAY_SIZE(mini2440_dm9k_resource),

.resource = mini2440_dm9k_resource,

.dev = {

.platform_data = &mini2440_dm9k_pdata,

},

};

 

研究net driver首先就要先了解一下网络驱动编写的一个基本架构

两个重要的结构体简单介绍:sk_buff和net_device

sk_buff

如果把网络传输看成是运送货物的话,那么sk_buff就是这个“货物”了,所有经手这个货物的人都要干点什么事儿,要么加个包装,要么印个戳儿等等。收货的时候就要拆掉这些包装,得到我们需要的货物(payload data)。没有货物你还运输什么呢?由此可见sk_buff的重要性了。

关于sk_buff的详细介绍和几个操作它的函数,参考:“linux内核sk_buff的结构分析” http://www.linuxidc.com/Linux/2011-07/39163.htm,写得非常明白了。赞一个~

net_device

又是一个庞大的结构体。好吧,我承认我从来就没有看全过这个结构体。它在内核中就是指代了一个网络设备。驱动程序需要在探测的时候分配并初始化这个结构体,然后使用register_netdev来注册它,这样就可以把操作硬件的函数与内核挂接在一起。

对于我们来说probe是一切一切的开始,看看dm9000驱动probe需要用要的结构体

board_info

 

/* Structure/enum declaration ------------------------------- */

typedef struct board_info {

void __iomem *io_addr; /* Register I/O base address */

void __iomem *io_data; /* Data I/O address */

u16 irq; /* IRQ */

u16 tx_pkt_cnt;

u16 queue_pkt_len;

u16 queue_start_addr;

u16 queue_ip_summed;

u16 dbug_cnt;

u8 io_mode; /* 0:word, 2:byte */

u8 phy_addr;

u8 imr_all;

unsigned int flags;

unsigned int in_suspend :1;

int debug_level;

enum dm9000_type type;

void (*inblk)(void __iomem *port, void *data, int length);

void (*outblk)(void __iomem *port, void *data, int length);

void (*dumpblk)(void __iomem *port, int length);

struct device *dev; /* parent device */

struct resource *addr_res; /* resources found */

struct resource *data_res;

struct resource *addr_req; /* resources requested */

struct resource *data_req;

struct resource *irq_res;

struct mutex addr_lock; /* phy and eeprom access lock */

struct delayed_work phy_poll;

struct net_device *ndev;

spinlock_t lock;

struct mii_if_info mii;

u32 msg_enable;

int rx_csum;

int can_csum;

int ip_summed;

} board_info_t;

 

其中有两个很重要的结构体 net_device 和 mii_if_info

mii_if_info

 

struct mii_if_info {

int phy_id;

int advertising;

int phy_id_mask;

int reg_num_mask;

unsigned int full_duplex : 1; /* is full duplex? */

unsigned int force_media : 1; /* is autoneg. disabled? */

unsigned int supports_gmii : 1; /* are GMII registers supported? */

struct net_device *dev;

int (*mdio_read) (struct net_device *dev, int phy_id, int location);

void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);

};

 

net_device 

 

/*

* The DEVICE structure.

* Actually, this whole structure is a big mistake. It mixes I/O

* data with strictly "high-level" data, and it has to know about

* almost every data structure used in the INET module.

*

* FIXME: cleanup struct net_device such that network protocol info

* moves out.

*/

struct net_device

{

/*

* This is the first field of the "visible" part of this structure

* (i.e. as seen by users in the "Space.c" file). It is the name

* the interface.

*/

char name[IFNAMSIZ];

/* device name hash chain */

struct hlist_node name_hlist;

/* snmp alias */

char *ifalias;

/*

* I/O specific fields

* FIXME: Merge these and struct ifmap into one

*/

unsigned long mem_end; /* shared mem end */

unsigned long mem_start; /* shared mem start */

unsigned long base_addr; /* device I/O address */

unsigned int irq; /* device IRQ number */

/*

* Some hardware also needs these fields, but they are not

* part of the usual set specified in Space.c.

*/

unsigned char if_port; /* Selectable AUI, TP,..*/

unsigned char dma; /* DMA channel */

unsigned long state;

struct list_head dev_list;

struct list_head napi_list;

/* Net device features */

unsigned long features;

#define NETIF_F_SG 1 /* Scatter/gather IO. */

#define NETIF_F_IP_CSUM 2 /* Can checksum TCP/UDP over IPv4. */

#define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */

#define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */

#define NETIF_F_IPV6_CSUM 16 /* Can checksum TCP/UDP over IPV6 */

#define NETIF_F_HIGHDMA 32 /* Can DMA to high memory. */

#define NETIF_F_FRAGLIST 64 /* Scatter/gather IO. */

#define NETIF_F_HW_VLAN_TX 128 /* Transmit VLAN hw acceleration */

#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */

#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */

#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */

#define NETIF_F_GSO 2048 /* Enable software GSO. */

#define NETIF_F_LLTX 4096 /* LockLess TX - deprecated. Please */

/* do not use LLTX in new drivers */

#define NETIF_F_NETNS_LOCAL 8192 /* Does not change network namespaces */

#define NETIF_F_GRO 16384 /* Generic receive offload */

#define NETIF_F_LRO 32768 /* large receive offload */

/* the GSO_MASK reserves bits 16 through 23 */

#define NETIF_F_FCOE_CRC (1 << 24) /* FCoE CRC32 */

#define NETIF_F_SCTP_CSUM (1 << 25) /* SCTP checksum offload */

#define NETIF_F_FCOE_MTU (1 << 26) /* Supports max FCoE MTU, 2158 bytes*/

/* Segmentation offload features */

#define NETIF_F_GSO_SHIFT 16

#define NETIF_F_GSO_MASK 0x00ff0000

#define NETIF_F_TSO (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)

#define NETIF_F_UFO (SKB_GSO_UDP << NETIF_F_GSO_SHIFT)

#define NETIF_F_GSO_ROBUST (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)

#define NETIF_F_TSO_ECN (SKB_GSO_TCP_ECN << NETIF_F_GSO_SHIFT)

#define NETIF_F_TSO6 (SKB_GSO_TCPV6 << NETIF_F_GSO_SHIFT)

#define NETIF_F_FSO (SKB_GSO_FCOE << NETIF_F_GSO_SHIFT)

/* List of features with software fallbacks. */

#define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6)

#define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)

#define NETIF_F_V4_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)

#define NETIF_F_V6_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)

#define NETIF_F_ALL_CSUM (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)

/*

* If one device supports one of these features, then enable them

* for all in netdev_increment_features.

*/

#define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \

NETIF_F_SG | NETIF_F_HIGHDMA | \

NETIF_F_FRAGLIST)

/* Interface index. Unique device identifier */

int ifindex;

int iflink;

struct net_device_stats stats;

#ifdef CONFIG_WIRELESS_EXT

/* List of functions to handle Wireless Extensions (instead of ioctl).

* See for details. Jean II */

const struct iw_handler_def * wireless_handlers;

/* Instance data managed by the core of Wireless Extensions. */

struct iw_public_data * wireless_data;

#endif

/* Management operations */

const struct net_device_ops *netdev_ops;

const struct ethtool_ops *ethtool_ops;

/* Hardware header description */

const struct header_ops *header_ops;

unsigned int flags; /* interface flags (a la BSD) */

unsigned short gflags;

unsigned short priv_flags; /* Like 'flags' but invisible to userspace. */

unsigned short padded; /* How much padding added by alloc_netdev() */

unsigned char operstate; /* RFC2863 operstate */

unsigned char link_mode; /* mapping policy to operstate */

unsigned mtu; /* interface MTU value */

unsigned short type; /* interface hardware type */

unsigned short hard_header_len; /* hardware hdr length */

/* extra head- and tailroom the hardware may need, but not in all cases

* can this be guaranteed, especially tailroom. Some cases also use

* LL_MAX_HEADER instead to allocate the skb.

*/

unsigned short needed_headroom;

unsigned short needed_tailroom;

struct net_device *master; /* Pointer to master device of a group,

* which this device is member of.

*/

/* Interface address info. */

unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */

unsigned char addr_len; /* hardware address length */

unsigned short dev_id; /* for shared network cards */

struct netdev_hw_addr_list uc; /* Secondary unicast

mac addresses */

int uc_promisc;

spinlock_t addr_list_lock;

struct dev_addr_list *mc_list; /* Multicast mac addresses */

int mc_count; /* Number of installed mcasts */

unsigned int promiscuity;

unsigned int allmulti;

/* Protocol specific pointers */

#ifdef CONFIG_NET_DSA

void *dsa_ptr; /* dsa specific data */

#endif

void *atalk_ptr; /* AppleTalk link */

void *ip_ptr; /* IPv4 specific data */

void *dn_ptr; /* DECnet specific data */

void *ip6_ptr; /* IPv6 specific data */

void *ec_ptr; /* Econet specific data */

void *ax25_ptr; /* AX.25 specific data */

struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data,

assign before registering */

/*

* Cache line mostly used on receive path (including eth_type_trans())

*/

unsigned long last_rx; /* Time of last Rx */

/* Interface address info used in eth_type_trans() */

unsigned char *dev_addr; /* hw address, (before bcast

because most packets are

unicast) */

struct netdev_hw_addr_list dev_addrs; /* list of device

hw addresses */

unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */

struct netdev_queue rx_queue;

struct netdev_queue *_tx ____cacheline_aligned_in_smp;

/* Number of TX queues allocated at alloc_netdev_mq() time */

unsigned int num_tx_queues;

/* Number of TX queues currently active in device */

unsigned int real_num_tx_queues;

/* root qdisc from userspace point of view */

struct Qdisc *qdisc;

unsigned long tx_queue_len; /* Max frames per queue allowed */

spinlock_t tx_global_lock;

/*

* One part is mostly used on xmit path (device)

*/

/* These may be needed for future network-power-down code. */

/*

* trans_start here is expensive for high speed devices on SMP,

* please use netdev_queue->trans_start instead.

*/

unsigned long trans_start; /* Time (in jiffies) of last Tx */

int watchdog_timeo; /* used by dev_watchdog() */

struct timer_list watchdog_timer;

/* Number of references to this device */

atomic_t refcnt ____cacheline_aligned_in_smp;

/* delayed register/unregister */

struct list_head todo_list;

/* device index hash chain */

struct hlist_node index_hlist;

struct net_device *link_watch_next;

/* register/unregister state machine */

enum { NETREG_UNINITIALIZED=0,

NETREG_REGISTERED, /* completed register_netdevice */

NETREG_UNREGISTERING, /* called unregister_netdevice */

NETREG_UNREGISTERED, /* completed unregister todo */

NETREG_RELEASED, /* called free_netdev */

NETREG_DUMMY, /* dummy device for NAPI poll */

} reg_state;

/* Called from unregister, can be used to call free_netdev */

void (*destructor)(struct net_device *dev);

#ifdef CONFIG_NETPOLL

struct netpoll_info *npinfo;

#endif

#ifdef CONFIG_NET_NS

/* Network namespace this network device is inside */

struct net *nd_net;

#endif

/* mid-layer private */

void *ml_priv;

/* bridge stuff */

struct net_bridge_port *br_port;

/* macvlan */

struct macvlan_port *macvlan_port;

/* GARP */

struct garp_port *garp_port;

/* class/net/name entry */

struct device dev;

/* space for optional statistics and wireless sysfs groups */

const struct attribute_group *sysfs_groups[3];

/* rtnetlink link ops */

const struct rtnl_link_ops *rtnl_link_ops;

/* VLAN feature mask */

unsigned long vlan_features;

/* for setting kernel sock attribute on TCP connection setup */

#define GSO_MAX_SIZE 65536

unsigned int gso_max_size;

#ifdef CONFIG_DCB

/* Data Center Bridging netlink ops */

struct dcbnl_rtnl_ops *dcbnl_ops;

#endif

#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)

/* max exchange id for FCoE LRO by ddp */

unsigned int fcoe_ddp_xid;

#endif

};

确实是如此庞大的一个结构体,让人畏惧的感觉,饭要一口一口吃啊O(∩_∩)O~

 

另外,还是认识一下另一个上面提到的庞大结构体吧,sk_buff

 

/**

* struct sk_buff - socket buffer

* @next: Next buffer in list

* @prev: Previous buffer in list

* @sk: Socket we are owned by

* @tstamp: Time we arrived

* @dev: Device we arrived on/are leaving by

* @transport_header: Transport layer header

* @network_header: Network layer header

* @mac_header: Link layer header

* @_skb_dst: destination entry

* @sp: the security path, used for xfrm

* @cb: Control buffer. Free for use by every layer. Put private vars here

* @len: Length of actual data

* @data_len: Data length

* @mac_len: Length of link layer header

* @hdr_len: writable header length of cloned skb

* @csum: Checksum (must include start/offset pair)

* @csum_start: Offset from skb->head where checksumming should start

* @csum_offset: Offset from csum_start where checksum should be stored

* @local_df: allow local fragmentation

* @cloned: Head may be cloned (check refcnt to be sure)

* @nohdr: Payload reference only, must not modify header

* @pkt_type: Packet class

* @fclone: skbuff clone status

* @ip_summed: Driver fed us an IP checksum

* @priority: Packet queueing priority

* @users: User count - see {datagram,tcp}.c

* @protocol: Packet protocol from driver

* @truesize: Buffer size

* @head: Head of buffer

* @data: Data head pointer

* @tail: Tail pointer

* @end: End pointer

* @destructor: Destruct function

* @mark: Generic packet mark

* @nfct: Associated connection, if any

* @ipvs_property: skbuff is owned by ipvs

* @peeked: this packet has been seen already, so stats have been

* done for it, don't do them again

* @nf_trace: netfilter packet trace flag

* @nfctinfo: Relationship of this skb to the connection

* @nfct_reasm: netfilter conntrack re-assembly pointer

* @nf_bridge: Saved data about a bridged frame - see br_netfilter.c

* @iif: ifindex of device we arrived on

* @queue_mapping: Queue mapping for multiqueue devices

* @tc_index: Traffic control index

* @tc_verd: traffic control verdict

* @ndisc_nodetype: router type (from link layer)

* @dma_cookie: a cookie to one of several possible DMA operations

* done by skb DMA functions

* @secmark: security marking

* @vlan_tci: vlan tag control information

*/

struct sk_buff {

/* These two members must be first. */

struct sk_buff *next;

struct sk_buff *prev;

struct sock *sk;

ktime_t tstamp;

struct net_device *dev;

unsigned long _skb_dst;

#ifdef CONFIG_XFRM

struct sec_path *sp;

#endif

/*

* This is the control buffer. It is free to use for every

* layer. Please put your private variables there. If you

* want to keep them across layers you have to do a skb_clone()

* first. This is owned by whoever has the skb queued ATM.

*/

char cb[48];

unsigned int len,

data_len;

__u16 mac_len,

hdr_len;

union {

__wsum csum;

struct {

__u16 csum_start;

__u16 csum_offset;

};

};

__u32 priority;

kmemcheck_bitfield_begin(flags1);

__u8 local_df:1,

cloned:1,

ip_summed:2,

nohdr:1,

nfctinfo:3;

__u8 pkt_type:3,

fclone:2,

ipvs_property:1,

peeked:1,

nf_trace:1;

__be16 protocol:16;

kmemcheck_bitfield_end(flags1);

void (*destructor)(struct sk_buff *skb);

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)

struct nf_conntrack *nfct;

struct sk_buff *nfct_reasm;

#endif

#ifdef CONFIG_BRIDGE_NETFILTER

struct nf_bridge_info *nf_bridge;

#endif

int iif;

#ifdef CONFIG_NET_SCHED

__u16 tc_index; /* traffic control index */

#ifdef CONFIG_NET_CLS_ACT

__u16 tc_verd; /* traffic control verdict */

#endif

#endif

kmemcheck_bitfield_begin(flags2);

__u16 queue_mapping:16;

#ifdef CONFIG_IPV6_NDISC_NODETYPE

__u8 ndisc_nodetype:2;

#endif

kmemcheck_bitfield_end(flags2);

/* 0/14 bit hole */

#ifdef CONFIG_NET_DMA

dma_cookie_t dma_cookie;

#endif

#ifdef CONFIG_NETWORK_SECMARK

__u32 secmark;

#endif

__u32 mark;

__u16 vlan_tci;

sk_buff_data_t transport_header;

sk_buff_data_t network_header;

sk_buff_data_t mac_header;

/* These elements must be at the end, see alloc_skb() for details. */

sk_buff_data_t tail;

sk_buff_data_t end;

unsigned char *head,

*data;

unsigned int truesize;

atomic_t users;

};

看到这是结构,让我深深感觉到彻底理清网卡驱动的编写还需要好好下一番功夫,莫要小看了它啊

 

下面会开始具体分析网卡驱动的整个probe过程,很关键的知识点。。。。

相关链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。