嵌入式Linux系统开发

嵌入式Linux系统开发

本文探讨有线网络。

嵌入式网络硬件分为两部分:MAC 和 PHY,大家都是通过看数据手册来判断一款 SoC 是否支持网络,如果一款芯片数据手册说自己支持网络,一般都是说的这款 SoC 内置 MAC,MAC 类似 I2C 控制器、SPI 控制器一样的外设。但是光有 MAC 还不能直接驱动网络,还需要另外一个芯片:PHY,因此对于内置 MAC 的 SoC,其外部必须搭配一个 PHY 芯片。但是有些 SoC 内部没有 MAC,那也就没法搭配 PHY 芯片了,这些内部没有网络 MAC 的芯片如何上网呢?这里就要牵扯出常见的两个嵌入式网络硬件方案了。

1、SOC 内部没有网络 MAC 外设

2、SOC 内部集成网络 MAC 外设

一般情况下是 SOC 内部 MAC+外置 PHY 芯片这种方案。

Linux 内核网络驱动框架

Linux 内核使用 net_device 结构体表示一个具体的网络设备,net_device 是整个网络驱动的灵魂。网络驱动的核心就是初始化 net_device 结构体中的各个成员变量,然后将初始化完成以后的 net_device 注册到 Linux 内核中。

2005  struct net_device {
2006  	char			name[IFNAMSIZ];
2007  	struct netdev_name_node	*name_node;
2008  	struct dev_ifalias	__rcu *ifalias;
2009  	/*
2010  	 *	I/O specific fields
2011  	 *	FIXME: Merge these and struct ifmap into one
2012  	 */
2013  	unsigned long		mem_end;
2014  	unsigned long		mem_start;
2015  	unsigned long		base_addr;
2016  

2022  
2023  	unsigned long		state;
2024  
2025  	struct list_head	dev_list;
2026  	struct list_head	napi_list;
2027  	struct list_head	unreg_list;
2028  	struct list_head	close_list;
2029  	struct list_head	ptype_all;
2030  	struct list_head	ptype_specific;
2031  
2032  	struct {
2033  		struct list_head upper;
2034  		struct list_head lower;
2035  	} adj_list;
2036  
2037  	/* Read-mostly cache-line for fast-path access */
2038  	unsigned int		flags;
2039  	unsigned int		priv_flags;
2040  	const struct net_device_ops *netdev_ops;
2041  	int			ifindex;
2042  	unsigned short		gflags;
2043  	unsigned short		hard_header_len;
2044  
2045  	/* Note : dev->mtu is often read without holding a lock.
2046  	 * Writers usually hold RTNL.
2047  	 * It is recommended to use READ_ONCE() to annotate the reads,
2048  	 * and to use WRITE_ONCE() to annotate the writes.
2049  	 */
2050  	unsigned int		mtu;
2051  	unsigned short		needed_headroom;
2052  	unsigned short		needed_tailroom;
2053  
2054  	netdev_features_t	features;
2055  	netdev_features_t	hw_features;
2056  	netdev_features_t	wanted_features;
2057  	netdev_features_t	vlan_features;
2058  	netdev_features_t	hw_enc_features;
2059  	netdev_features_t	mpls_features;
2060  	netdev_features_t	gso_partial_features;
2061  
2062  	unsigned int		min_mtu;
2063  	unsigned int		max_mtu;
2064  	unsigned short		type;
2065  	unsigned char		min_header_len;
2066  	unsigned char		name_assign_type;
2067  
2068  	int			group;
2069  
2070  	struct net_device_stats	stats; /* not used by modern drivers */
2071  
2072  	atomic_long_t		rx_dropped;
2073  	atomic_long_t		tx_dropped;
2074  	atomic_long_t		rx_nohandler;
2075  
2076  	/* Stats to monitor link on/off, flapping */
2077  	atomic_t		carrier_up_count;
2078  	atomic_t		carrier_down_count;
2079  
2080  #ifdef CONFIG_WIRELESS_EXT
2081  	const struct iw_handler_def *wireless_handlers;
2082  	struct iw_public_data	*wireless_data;
2083  #endif
2084  	const struct ethtool_ops *ethtool_ops;
2085  #ifdef CONFIG_NET_L3_MASTER_DEV
2086  	const struct l3mdev_ops	*l3mdev_ops;
2087  #endif
2088  #if IS_ENABLED(CONFIG_IPV6)
2089  	const struct ndisc_ops *ndisc_ops;
2090  #endif
2091  
2092  #ifdef CONFIG_XFRM_OFFLOAD
2093  	const struct xfrmdev_ops *xfrmdev_ops;
2094  #endif
2095  
2096  #if IS_ENABLED(CONFIG_TLS_DEVICE)
2097  	const struct tlsdev_ops *tlsdev_ops;
2098  #endif
2099  
2100  	const struct header_ops *header_ops;
2101  
2102  	unsigned char		operstate;
2103  	unsigned char		link_mode;
2104  
2105  	unsigned char		if_port;
2106  	unsigned char		dma;
2107  
2108  	/* Interface address info. */
2109  	unsigned char		perm_addr[MAX_ADDR_LEN];
2110  	unsigned char		addr_assign_type;
2111  	unsigned char		addr_len;
2112  	unsigned char		upper_level;
2113  	unsigned char		lower_level;
2114  

2175  	/* Interface address info used in eth_type_trans() */
2176  	unsigned char		*dev_addr;
2177  
2178  	struct netdev_rx_queue	*_rx;
2179  	unsigned int		num_rx_queues;
2180  	unsigned int		real_num_rx_queues;
2181  

2205  	struct netdev_queue	*_tx ____cacheline_aligned_in_smp;
2206  	unsigned int		num_tx_queues;
2207  	unsigned int		real_num_tx_queues;
2208  	struct Qdisc __rcu	*qdisc;
2209  	unsigned int		tx_queue_len;
2210  	spinlock_t		tx_global_lock;
2211  

2287  	/* for setting kernel sock attribute on TCP connection setup */
2288  #define GSO_MAX_SIZE		65536
2289  	unsigned int		gso_max_size;
2290  #define GSO_MAX_SEGS		65535
2291  	u16			gso_max_segs;
2292  
2293  #ifdef CONFIG_DCB
2294  	const struct dcbnl_rtnl_ops *dcbnl_ops;
2295  #endif
2296  	s16			num_tc;
2297  	struct netdev_tc_txq	tc_to_txq[TC_MAX_QUEUE];
2298  	u8			prio_tc_map[TC_BITMASK + 1];
2299  
2300  #if IS_ENABLED(CONFIG_FCOE)
2301  	unsigned int		fcoe_ddp_xid;
2302  #endif
2303  #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
2304  	struct netprio_map __rcu *priomap;
2305  #endif
2306  	struct phy_device	*phydev;
2307  	struct sfp_bus		*sfp_bus;

2334  };
2335  #define to_net_dev(d) container_of(d, struct net_device, dev)

name 是网络设备的名字。mem_end 是共享内存结束地址。mem_start 是共享内存起始地址。base_addr 是网络设备 I/O 地址。irq 是网络设备的中断号。dev_list 是全局网络设备列表。napi_list 是 napi 网络设备的列表入口。unreg_list 是注销(unregister)的网络设备列表入口。close_list 是关闭的网络设备列表入口。netdev_ops 是网络设备的操作集函数,包含了一系列的网络设备操作回调函数,类似字符设备中的 file_operations。ethtool_ops 是网络管理工具相关函数集,用户空间网络管理工具会调用此结构体中的相关函数获取网卡状态或者配置网卡。header_ops 是头部的相关操作函数集,比如创建、解析、缓冲等。flags 是网络接口标志。if_port 指定接口的端口类型。dma 是网络设备所使用的 DMA 通道,不是所有的设备都会用到 DMA。mtu 是网络最大传输单元,为 1500。type 用于指定 ARP 模块的类型。perm_addr 是永久的硬件地址,如果某个网卡设备有永久的硬件地址,那么就会填充 perm_addr。addr_len 是硬件地址长度。dev_addr 也是硬件地址,是当前分配的 MAC 地址,可以通过软件修改。_rx 是接收队列。num_rx_queues 是接收队列数量,在调用 register_netdev 注册网络设备的时候会分配指定数量的接收队列。real_num_rx_queues 是当前活动的队列数量。_tx 是发送队列。num_tx_queues 是发送队列数量,通过 alloc_netdev_mq 函数分配指定数量的发送队列。real_num_tx_queues 是当前有效的发送队列数量。phydev 是对应的 PHY 设备。

申请 net_device:alloc_netdev

删除 net_device:free_netdev

注册 net_device:register_netdev

注销 net_device:unregister_netdev

net_device 有个非常重要的成员变量:netdev_ops,为 net_device_ops 结构体指针类型,这就是网络设备的操作集,net_device_ops 结构体里面都是一些以“ndo_”开头的函数,这些函数就需要网络驱动人员去实现,不需要全部都实现,根据实际驱动情况实现其中一小部分即可。

1395  struct net_device_ops {
1396  	int			(*ndo_init)(struct net_device *dev);
1397  	void			(*ndo_uninit)(struct net_device *dev);
1398  	int			(*ndo_open)(struct net_device *dev);
1399  	int			(*ndo_stop)(struct net_device *dev);
1400  	netdev_tx_t		(*ndo_start_xmit)(struct sk_buff *skb,
1401  						  struct net_device *dev);
1402  	netdev_features_t	(*ndo_features_check)(struct sk_buff *skb,
1403  						      struct net_device *dev,
1404  						      netdev_features_t features);
1405  	u16			(*ndo_select_queue)(struct net_device *dev,
1406  						    struct sk_buff *skb,
1407  						    struct net_device *sb_dev);
1408  	void			(*ndo_change_rx_flags)(struct net_device *dev,
1409  						       int flags);
1410  	void			(*ndo_set_rx_mode)(struct net_device *dev);
1411  	int			(*ndo_set_mac_address)(struct net_device *dev,
1412  						       void *addr);
1413  	int			(*ndo_validate_addr)(struct net_device *dev);
1414  	int			(*ndo_do_ioctl)(struct net_device *dev,
1415  					        struct ifreq *ifr, int cmd);
1416  	int			(*ndo_eth_ioctl)(struct net_device *dev,
1417  						 struct ifreq *ifr, int cmd);
1418  	int			(*ndo_siocbond)(struct net_device *dev,
1419  						struct ifreq *ifr, int cmd);
1420  	int			(*ndo_siocwandev)(struct net_device *dev,
1421  						  struct if_settings *ifs);
1422  	int			(*ndo_siocdevprivate)(struct net_device *dev,
1423  						      struct ifreq *ifr,
1424  						      void __user *data, int cmd);
1425  	int			(*ndo_set_config)(struct net_device *dev,
1426  					          struct ifmap *map);
1427  	int			(*ndo_change_mtu)(struct net_device *dev,
1428  						  int new_mtu);
1429  	int			(*ndo_neigh_setup)(struct net_device *dev,
1430  						   struct neigh_parms *);
1431  	void			(*ndo_tx_timeout) (struct net_device *dev,
1432  						   unsigned int txqueue);
1433  

1446  #ifdef CONFIG_NET_POLL_CONTROLLER
1447  	void                    (*ndo_poll_controller)(struct net_device *dev);
1448  	int			(*ndo_netpoll_setup)(struct net_device *dev,
1449  						     struct netpoll_info *info);
1450  	void			(*ndo_netpoll_cleanup)(struct net_device *dev);
1451  #endif

1521  	int			(*ndo_add_slave)(struct net_device *dev,
1522  						 struct net_device *slave_dev,
1523  						 struct netlink_ext_ack *extack);
1524  	int			(*ndo_del_slave)(struct net_device *dev,
1525  						 struct net_device *slave_dev);
1526  	struct net_device*	(*ndo_get_xmit_slave)(struct net_device *dev,
1527  						      struct sk_buff *skb,
1528  						      bool all_slaves);
1529  	struct net_device*	(*ndo_sk_get_lower_dev)(struct net_device *dev,
1530  							struct sock *sk);
1531  	netdev_features_t	(*ndo_fix_features)(struct net_device *dev,
1532  						    netdev_features_t features);
1533  	int			(*ndo_set_features)(struct net_device *dev,
1534  						    netdev_features_t features);

1622  };

ndo_init 函数,当第一次注册网络设备的时候此函数会执行,设备可以在此函数中
做一些需要推后初始化的内容,不过一般驱动中不使用此函数,虚拟网络设备可能会使用。

ndo_uninit 函数,卸载网络设备的时候此函数会执行。

do_open 函数,打开网络设备的时候此函数会执行,网络驱动程序需要实现此函数,非常重要!

ndo_stop 函数,关闭网络设备的时候此函数会执行,网络驱动程序也需要实现此函数。

ndo_start_xmit 函数,当需要发送数据的时候此函数就会执行,此函数有一个参数
为 sk_buff 结构体指针,sk_buff 结构体在 Linux 的网络驱动中非常重要,sk_buff 保存了上层传递给网络驱动层的数据。也就是说,要发送出去的数据都存在了 sk_buff 中,关于 sk_buff 稍后会做详细的讲解。如果发送成功的话此函数返回 NETDEV_TX_OK,如果发送失败了就返回 NETDEV_TX_BUSY,如果发送失败了我们就需要停止队列。

do_select_queue 函数,当设备支持多传输队列的时候选择使用哪个队列。

ndo_set_rx_mode 函数,此函数用于改变地址过滤列表,根据 net_device 的 flags
成员变量来设置 SoC 的网络外设寄存器。比如 flags 可能为 IFF_PROMISC、IFF_ALLMULTI 或 IFF_MULTICAST,分别表示混杂模式、单播模式或多播模式。

ndo_set_mac_address 函数,此函数用于修改网卡的 MAC 地址,设置 net_device
的 dev_addr 成员变量,并且将 MAC 地址写入到网络外设的硬件寄存器中。

ndo_validate_addr 函数,验证 MAC 地址是否合法,也即是验证 net_device 的
dev_addr 中的 MAC 地址是否合法,直接调用 is_valid_ether_addr 函数。

ndo_do_ioctl 函数,用户程序调用 ioctl 的时候此函数就会执行,比如 PHY 芯片
相关的命令操作,一般会直接调用 phy_mii_ioctl 函数。

ndo_change_mtu 函数,更改 MTU 大小。

ndo_tx_timeout 函数,当发送超时的时候产生会执行,一般都是网络出问题了导
致发送超时。一般可能会重启 MAC 和 PHY,重新开始数据发送等。

ndo_poll_controller 函数,使用查询方式来处理网卡数据的收发。

ndo_set_features 函数,修改 net_device 的 features 属性,设置相应的硬件属性。

03-21 17:33