Mini2440 DM9000 驱动分析(一)

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 <net/iw_handler.h> 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过程,很关键的知识点。。。。

你可能感兴趣的:(ini)