GMAC網卡Fixed-Link模式GMACfixed-link固定鏈接模式,mac與對端的連接方式是寫死的,通常用於mac to mac(不排除mac to phy的情況)。內核要支持fixed-link模式,需要打開CONFIG_FIXED_PHY配置。 社區版linux的gmac網卡platf ...
GMAC網卡Fixed-Link模式
GMACfixed-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
屬性
設備樹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 subnode\n");
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 %d\n", 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 failed\n");
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 failed\n");
phydev = NULL;
}
... ...
}
本文來自博客園,作者:StepForwards,轉載請註明原文鏈接:https://www.cnblogs.com/forwards/p/17859265.html