GMAC网卡Fixed-Link模式

  • GMAC网卡Fixed-Link模式已关闭评论
  • 95 次浏览
  • A+
所属分类:linux技术
摘要

fixed-link固定链接模式,mac与对端的连接方式是写死的,通常用于mac to mac(不排除mac to phy的情况)。内核要支持fixed-link模式,需要打开CONFIG_FIXED_PHY配置。

GMAC网卡Fixed-Link模式

GMAC

fixed-link固定链接模式,mac与对端的连接方式是写死的,通常用于mac to mac(不排除mac to phy的情况)。内核要支持fixed-link模式,需要打开CONFIG_FIXED_PHY配置。

社区版linux的gmac网卡platform平台驱动中,在设备树默认下支持fixed-link,gmac网卡platform平台驱动默认不支持ACPI模式。

fixed-link模式的实现,概括起来就两步,

  • 通过fixed_phy_register创建phy device
  • 连接phy device

fixed-link的link状态通常是固定的,但也可以通过gpio GPIOF_DIR_IN寄存器获取。

设备树Fixed-Link实现

以4.19.90内核版本为例其实现方式如下(内核版本5.3之后使用phylink替代了phy lib,实现接口有所不同):

设备树配置中定义fixed-link属性

GMAC网卡Fixed-Link模式

设备树fixed-link配置

stmac驱动实现of_phy_register_fixed_link函数读取设备树fixed-link属性并通过fixed_phy_register创建phy device,of_phy_connect连接phy device。

stmmac_platform.c: static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,              struct device_node *np, struct device *dev) { ... ...     /* If phy-handle is not specified, check if we have a fixed-phy */     if (!plat->phy_node && of_phy_is_fixed_link(np)) { 		if ((of_phy_register_fixed_link(np) < 0))             return -ENODEV;          dev_dbg(dev, "Found fixed-link subnoden");         plat->phy_node = of_node_get(np);         mdio = false;     } ... ... }  stmmac_main.c: static int stmmac_init_phy(struct net_device *dev) { ... ... 	if (priv->plat->phy_node) { 		phydev = of_phy_connect(dev, priv->plat->phy_node, 					&stmmac_adjust_link, 0, interface); ... ... }

通过of_phy_register_fixed_link函数可知,fixed-link的配置方式不只一种

/drivers/of/of_mdio.c: int of_phy_register_fixed_link(struct device_node *np) { 	struct fixed_phy_status status = {}; 	struct device_node *fixed_link_node; 	u32 fixed_link_prop[5]; 	const char *managed; 	int link_gpio = -1;  	if (of_property_read_string(np, "managed", &managed) == 0 && 	    strcmp(managed, "in-band-status") == 0) { 		/* status is zeroed, namely its .link member */ 		goto register_phy; 	}  	/* New binding */ 	fixed_link_node = of_get_child_by_name(np, "fixed-link"); 	if (fixed_link_node) { 		status.link = 1; 		status.duplex = of_property_read_bool(fixed_link_node, 						      "full-duplex"); 		if (of_property_read_u32(fixed_link_node, "speed", 					 &status.speed)) { 			of_node_put(fixed_link_node); 			return -EINVAL; 		} 		status.pause = of_property_read_bool(fixed_link_node, "pause"); 		status.asym_pause = of_property_read_bool(fixed_link_node, 							  "asym-pause"); 		link_gpio = of_get_named_gpio_flags(fixed_link_node, 						    "link-gpios", 0, NULL); 		of_node_put(fixed_link_node); 		if (link_gpio == -EPROBE_DEFER) 			return -EPROBE_DEFER;  		goto register_phy; 	}  	/* Old binding */ 	if (of_property_read_u32_array(np, "fixed-link", fixed_link_prop, 				       ARRAY_SIZE(fixed_link_prop)) == 0) { 		status.link = 1; 		status.duplex = fixed_link_prop[1]; 		status.speed  = fixed_link_prop[2]; 		status.pause  = fixed_link_prop[3]; 		status.asym_pause = fixed_link_prop[4]; 		goto register_phy; 	}  	return -ENODEV;  register_phy: 	return PTR_ERR_OR_ZERO(fixed_phy_register(PHY_POLL, &status, link_gpio, 						  np)); } EXPORT_SYMBOL(of_phy_register_fixed_link);

ACPI Fixed-Link实现

本质上ACPI和设备树fixed-link实现是一致的,只是部分接口函数不同,ACPI下可以使用phy_connect_direct进行连接(5.3之后的内核版本使用phylink模式,连接函数是phylink_connect_phy)。

stmmac_platform.c: int fw_phy_register_fixed_link(struct fwnode_handle *np, 			       struct plat_stmmacenet_data *plat) { 	struct fixed_phy_status status = {}; 	u32 fixed_link_prop[5]; 	int size = 5, err; 	int link_gpio = -1; 	struct phy_device *phydev = NULL;  	if (FORCE_FIXED_LINK) { 		status.link = 1; 		status.duplex = DUPLEX_FULL; 		status.speed = SPEED_1000; 		pr_info("force fixed-link busid %dn", plat->bus_id); 	} else { 		err = fwnode_property_read_u32_array(np, "fixed-link", fixed_link_prop, size); 		if (err) { 			pr_err("----there is no fixed-link property in DSD--n"); 			return 0; 		} 		status.link = 1; 		status.duplex = fixed_link_prop[1]; 		status.speed = fixed_link_prop[2]; 		status.pause  = fixed_link_prop[3]; 		status.asym_pause = fixed_link_prop[4]; 	}  	phydev = fixed_phy_register(PHY_POLL, &status, link_gpio, 0); 	if (IS_ERR(phydev)) { 		pr_err("fixed_phy_register failedn"); 		return -1; 	} 	plat->fixedphydev = phydev; 	return 0; }  stmmac_main.c: static int stmmac_init_phy(struct net_device *dev) { ... ... if (priv->plat->fixedphydev) { 		phydev = priv->plat->fixedphydev; 		if (phy_connect_direct(dev, phydev, &stmmac_adjust_link, 				       interface)) { 			netdev_err(priv->dev, "phy_connect_direct failedn"); 			phydev = NULL; } ... ... }