现在的位置: 首页 > 综合 > 正文

ARM-Linux驱动–DM9000网卡驱动分析(一)

2013年10月27日 ⁄ 综合 ⁄ 共 13735字 ⁄ 字号 评论关闭

硬件平台:FL2440s3c2440

内核版本:2.6.35

主机平台:Ubuntu11.04

内核版本:2.6.39

原创作品,转载请标明出处http://blog.csdn.net/yming0221/article/details/6609742

1、下图是DM9000的引脚图

2、这里我们结合具体的开发板FL2440

下面是FL2440DM9000的引脚链接图

本人移植DM9000的时候将设备的资源定义放在了arch/arm/plat-s3c24xx/devs.c中,详情点击上一篇博文linux内核移植-移植2.6.35.4内核到s3c2440

下面是设备的资源定义

/*DM9000*/
/* 定义该设备使用的资源 */
static struct resource s3c_dm9000_resource[] = { 
        [0] = { /* 寄存器定义在mach-s3c2410/include/mach/map.h */
        .start = S3C24XX_PA_DM9000, /* 实际地址  0x20000300 */
        .end   = S3C24XX_PA_DM9000+ 0x3, /* 0x20000303 */
        .flags = IORESOURCE_MEM /* 资源标志为地址资源 */
        }, 
        [1]={ 
        .start = S3C24XX_PA_DM9000 + 0x4, //CMD pin is A2 0x20000304
        .end = S3C24XX_PA_DM9000 + 0x4 + 0x7c, // 0x20000380
        .flags = IORESOURCE_MEM /* 资源标志为地址资源 */
        }, 
        [2] = { 
        .start = IRQ_EINT7, /* 中断为外部7号中断 */
        .end   = IRQ_EINT7, /* 中断为外部7号中断 */
        .flags = IORESOURCE_IRQ /* 资源标志为中断资源 */
        }, 
}; 

这里可以看到,DM9000网卡使用的地址空间资源在nGCS4地址区域,所以上图的DM9000地址使能引脚连接nGCS4引脚。中断使用的是EINT7外部中断。

接着定义平台数据和平台设备,代码如下:

/* 定义平台数据 */
static struct dm9000_plat_data s3c_device_dm9000_platdata = { 
        .flags= DM9000_PLATF_16BITONLY, 
}; 

/* 定义平台设备 */
struct platform_device s3c_device_dm9000 = { 
        .name= "dm9000", //设备名,该名称与平台设备驱动中的名称一致
        .id= 0, 
        .num_resources= ARRAY_SIZE(s3c_dm9000_resource), 
        .resource= s3c_dm9000_resource, //定义设备的资源
        .dev= { 
                .platform_data = &s3c_device_dm9000_platdata, //定义平台数据
         } 
}; 

最后导出函数符号,保存函数地址和名称

EXPORT_SYMBOL(s3c_device_dm9000);

3、设备启动的初始化过程

MACHINE_START(S3C2440, "SMDK2440")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,

        .init_irq       = s3c24xx_init_irq,/* 初始化中断 */
        .map_io         = smdk2440_map_io,
        .init_machine   = smdk2440_machine_init,//定义设备的初始化函数
        .timer          = &s3c24xx_timer,
MACHINE_END

而后会执行下面函数

static void __init smdk2440_machine_init(void)
{
        s3c24xx_fb_set_platdata(&smdk2440_fb_info);
        s3c_i2c0_set_platdata(NULL);
        
        s3c24xx_ts_set_platdata(&smdk2410_ts_cfg);/* Added by yan */
        
        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));/* 向平台中添加设备 */
        smdk_machine_init();
}

下面是具体的设备列表

static struct platform_device *smdk2440_devices[] __initdata = {
        &s3c_device_ohci,
        &s3c_device_lcd,/* ok */
        &s3c_device_wdt,/* ok */
        &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_rtc,/* ok */
        &s3c24xx_uda134x,
        &s3c_device_dm9000,
        &s3c_device_adc,/* ok */
        &s3c_device_ts,/* ok */
        
};

这样系统启动时,会给设备列表中的设备分配资源(地址资源和中断资源等)。

4、信息传输中的信息封装结构

4.1、sk_buff结构,定义在include/linux/skbuff.h

struct sk_buff {
        /* These two members must be first. */
        struct sk_buff          *next;
        struct sk_buff          *prev;

        ktime_t                 tstamp;

        struct sock             *sk;
        struct net_device       *dev;

        /*
         * 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] __aligned(8);

        unsigned long           _skb_refdst;
#ifdef CONFIG_XFRM
        struct  sec_path        *sp;
#endif
        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;
        kmemcheck_bitfield_end(flags1);
        __be16                  protocol;

        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                     skb_iif;
#ifdef CONFIG_NET_SCHED
        __u16                   tc_index;       /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
        __u16                   tc_verd;        /* traffic control verdict */
#endif
#endif

        __u32                   rxhash;

        kmemcheck_bitfield_begin(flags2);
        __u16                   queue_mapping:16;
#ifdef CONFIG_IPV6_NDISC_NODETYPE
        __u8                    ndisc_nodetype:2,
                                deliver_no_wcard:1;
#else
        __u8                    deliver_no_wcard:1;
#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
        union {
                __u32           mark;
                __u32           dropcount;
        };

        __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;
};

元素的含义如下(摘自内核,源码,版本2.6.35.4
 *struct sk_buff - socket buffer
 * @next: Next buffer inlist
 * @prev: Previous buffer in list
 * @sk: Socketwe are owned by
 * @tstamp: Time we arrived
 * @dev:Device we arrived on/are leaving by
 * @transport_header:Transport layer header
 * @network_header: Network layerheader
 * @mac_header: Link layer header
 *@_skb_refdst: destination entry (with norefcount bit)
 * @sp:the security path, used for xfrm
 * @cb: Control buffer. Freefor use by every layer. Put private vars here
 * @len: Lengthof actual data
 * @data_len: Data length
 * @mac_len:Length of link layer header
 * @hdr_len: writable headerlength of cloned skb
 * @csum: Checksum (must includestart/offset pair)
 * @csum_start: Offset from skb->headwhere checksumming should start
 * @csum_offset: Offset fromcsum_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 anIP 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 packetmark
 * @nfct: Associated connection, if any
 *@ipvs_property: skbuff is owned by ipvs
 * @peeked: thispacket has been seen already, so stats have been
 * done forit, don't do them again
 * @nf_trace: netfilter packet traceflag
 * @nfctinfo: Relationship of this skb to theconnection
 * @nfct_reasm: netfilter conntrack re-assemblypointer
 * @nf_bridge: Saved data about a bridged frame - seebr_netfilter.c
 * @skb_iif: ifindex of device we arrivedon
 * @rxhash: the packet hash computed on receive
 *@queue_mapping: Queue mapping for multiqueue devices
 *@tc_index: Traffic control index
 * @tc_verd: traffic controlverdict
 * @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

关于sk_buff的更多分析见另一篇转载的博文http://blog.csdn.net/yming0221/article/details/6609734

4.2、net_device

关于net_device一个非常庞大的结构体,定义在/inlcude/linux/netdevice.h中

如下:

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];

	struct pm_qos_request_list *pm_qos_req;

	/* 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;
	struct list_head	unreg_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*/
#define NETIF_F_NTUPLE		(1 << 27) /* N-tuple filters supported */
#define NETIF_F_RXHASH		(1 << 28) /* Receive hashing offload */

	/* 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 int		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 */

	spinlock_t		addr_list_lock;
	struct netdev_hw_addr_list	uc;	/* Unicast mac addresses */
	struct netdev_hw_addr_list	mc;	/* Multicast mac addresses */
	int			uc_promisc;
	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	*/

#ifdef CONFIG_RPS
	struct kset		*queues_kset;

	struct netdev_rx_queue	*_rx;

	/* Number of RX queues allocated at alloc_netdev_mq() time  */
	unsigned int		num_rx_queues;
#endif

	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 list_head	link_watch_list;

	/* 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:16;

	enum {
		RTNL_LINK_INITIALIZED,
		RTNL_LINK_INITIALIZING,
	} rtnl_link_state:16;

	/* 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 device, statistics, and wireless sysfs groups */
	const struct attribute_group *sysfs_groups[4];

	/* 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 */
	const 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
	/* n-tuple filter list attached to this device */
	struct ethtool_rx_ntuple_list ethtool_ntuple_list;
};

我还没有细细的分析这个结构体,驱动程序在probe函数中使用register_netdev()注册该结构体指明的设备,将内核操作硬件的函数个内核联系起来。

更多见下一节分析ARM-Linux驱动--DM9000网卡驱动分析(二)

抱歉!评论已关闭.