Linux网络驱动之Fixed-Link(7)

接前一篇文章:Linux网络驱动之Fixed-Link(6)

本文内容参考:

linux phy fixed-link-CSDN博客

fixed-link 网口驱动设备树-CSDN博客

GMAC网卡Fixed-Link模式 - StepForwards - 博客园

RTL8367RB的国产P2P替代方案用JL6107-PC的可行性及实现方法-CSDN博客

linux phy处理流程一:探测phy设备_phy link过程-CSDN博客

设备树 fixed-link 使用说明-CSDN博客

Linux 网络驱动-MAC、PHY层驱动框架(三)_ethernet-phy-ieee802.3-c22-CSDN博客

特此致谢!

三、深入了解

4. Linux内核中Fixed-Link的相关内容

(2)PHY驱动(driver)匹配

上一回继续讲解of_phy_get_and_connect函数,讲解了of_phy_is_fixed_link函数返回true的情况,本回讲解of_phy_is_fixed_link函数返回false的情况。为了便于理解和回顾,再次贴出of_phy_get_and_connect函数代码,在drivers/net/mdio/of_mdio.c中,如下:

cpp 复制代码
/**
 * of_phy_get_and_connect
 * - Get phy node and connect to the phy described in the device tree
 * @dev: pointer to net_device claiming the phy
 * @np: Pointer to device tree node for the net_device claiming the phy
 * @hndlr: Link state callback for the network device
 *
 * If successful, returns a pointer to the phy_device with the embedded
 * struct device refcount incremented by one, or NULL on failure. The
 * refcount must be dropped by calling phy_disconnect() or phy_detach().
 */
struct phy_device *of_phy_get_and_connect(struct net_device *dev,
					  struct device_node *np,
					  void (*hndlr)(struct net_device *))
{
	phy_interface_t iface;
	struct device_node *phy_np;
	struct phy_device *phy;
	int ret;
 
	ret = of_get_phy_mode(np, &iface);
	if (ret)
		return NULL;
	if (of_phy_is_fixed_link(np)) {
		ret = of_phy_register_fixed_link(np);
		if (ret < 0) {
			netdev_err(dev, "broken fixed-link specification\n");
			return NULL;
		}
		phy_np = of_node_get(np);
	} else {
		phy_np = of_parse_phandle(np, "phy-handle", 0);
		if (!phy_np)
			return NULL;
	}
 
	phy = of_phy_connect(dev, phy_np, hndlr, 0, iface);
 
	of_node_put(phy_np);
 
	return phy;
}
EXPORT_SYMBOL(of_phy_get_and_connect);

of_phy_is_fixed_link函数返回false,也就是在DTS文件中没有找到Fixed-Link相关结点时,则走else分支。代码片段如下:

cpp 复制代码
    else {
		phy_np = of_parse_phandle(np, "phy-handle", 0);
		if (!phy_np)
			return NULL;
	}

else分支中,主要是调用了of_parse_phandle函数,处理phy结点。of_parse_handle函数在include/linux/of.h中,代码如下:

cpp 复制代码
/**
 * of_parse_phandle - Resolve a phandle property to a device_node pointer
 * @np: Pointer to device node holding phandle property
 * @phandle_name: Name of property holding a phandle value
 * @index: For properties holding a table of phandles, this is the index into
 *         the table
 *
 * Return: The device_node pointer with refcount incremented.  Use
 * of_node_put() on it when done.
 */
static inline struct device_node *of_parse_phandle(const struct device_node *np,
						   const char *phandle_name,
						   int index)
{
	struct of_phandle_args args;

	if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0,
					 index, &args))
		return NULL;

	return args.np;
}

看一下函数注释,of_parse_phandle函数的作用是,将phandle属性解析为device_node指针。该函数和上一回的of_node_get函数类似,也是由struct device *得到struct device_node *。

参数说明:

  • np:指向包含phandle属性的设备节点的指针
  • phandle_name:持有phandle值的属性名称
  • index:对于持有phandles表的属性,这是表中的索引

返回值:

带有refcount已递增的device_node指针。完成后对其使用of_node_put()。

__of_parse_phandle_with_args函数在drivers/of/base.c中,代码如下:

cpp 复制代码
int __of_parse_phandle_with_args(const struct device_node *np,
				 const char *list_name,
				 const char *cells_name,
				 int cell_count, int index,
				 struct of_phandle_args *out_args)
{
	struct of_phandle_iterator it;
	int rc, cur_index = 0;

	if (index < 0)
		return -EINVAL;

	/* Loop over the phandles until all the requested entry is found */
	of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) {
		/*
		 * All of the error cases bail out of the loop, so at
		 * this point, the parsing is successful. If the requested
		 * index matches, then fill the out_args structure and return,
		 * or return -ENOENT for an empty entry.
		 */
		rc = -ENOENT;
		if (cur_index == index) {
			if (!it.phandle)
				goto err;

			if (out_args) {
				int c;

				c = of_phandle_iterator_args(&it,
							     out_args->args,
							     MAX_PHANDLE_ARGS);
				out_args->np = it.node;
				out_args->args_count = c;
			} else {
				of_node_put(it.node);
			}

			/* Found it! return success */
			return 0;
		}

		cur_index++;
	}

	/*
	 * Unlock node before returning result; will be one of:
	 * -ENOENT : index is for empty phandle
	 * -EINVAL : parsing error on data
	 */

 err:
	of_node_put(it.node);
	return rc;
}
EXPORT_SYMBOL(__of_parse_phandle_with_args);

回到of_phy_get_and_connect函数中:

cpp 复制代码
/**
 * of_phy_get_and_connect
 * - Get phy node and connect to the phy described in the device tree
 * @dev: pointer to net_device claiming the phy
 * @np: Pointer to device tree node for the net_device claiming the phy
 * @hndlr: Link state callback for the network device
 *
 * If successful, returns a pointer to the phy_device with the embedded
 * struct device refcount incremented by one, or NULL on failure. The
 * refcount must be dropped by calling phy_disconnect() or phy_detach().
 */
struct phy_device *of_phy_get_and_connect(struct net_device *dev,
					  struct device_node *np,
					  void (*hndlr)(struct net_device *))
{
	phy_interface_t iface;
	struct device_node *phy_np;
	struct phy_device *phy;
	int ret;
 
	ret = of_get_phy_mode(np, &iface);
	if (ret)
		return NULL;
	if (of_phy_is_fixed_link(np)) {
		ret = of_phy_register_fixed_link(np);
		if (ret < 0) {
			netdev_err(dev, "broken fixed-link specification\n");
			return NULL;
		}
		phy_np = of_node_get(np);
	} else {
		phy_np = of_parse_phandle(np, "phy-handle", 0);
		if (!phy_np)
			return NULL;
	}
 
	phy = of_phy_connect(dev, phy_np, hndlr, 0, iface);
 
	of_node_put(phy_np);
 
	return phy;
}
EXPORT_SYMBOL(of_phy_get_and_connect);

接下来调用of_phy_connect函数。其也在drivers/net/mdio/of_mdio.c中,代码如下:

cpp 复制代码
/**
 * of_phy_connect - Connect to the phy described in the device tree
 * @dev: pointer to net_device claiming the phy
 * @phy_np: Pointer to device tree node for the PHY
 * @hndlr: Link state callback for the network device
 * @flags: flags to pass to the PHY
 * @iface: PHY data interface type
 *
 * If successful, returns a pointer to the phy_device with the embedded
 * struct device refcount incremented by one, or NULL on failure. The
 * refcount must be dropped by calling phy_disconnect() or phy_detach().
 */
struct phy_device *of_phy_connect(struct net_device *dev,
				  struct device_node *phy_np,
				  void (*hndlr)(struct net_device *), u32 flags,
				  phy_interface_t iface)
{
	struct phy_device *phy = of_phy_find_device(phy_np);
	int ret;

	if (!phy)
		return NULL;

	phy->dev_flags |= flags;

	ret = phy_connect_direct(dev, phy, hndlr, iface);

	/* refcount is held by phy_connect_direct() on success */
	put_device(&phy->mdio.dev);

	return ret ? NULL : phy;
}
EXPORT_SYMBOL(of_phy_connect);

这就回到了前文书(Linux网络驱动之Fixed-Link(5)-CSDN博客)的起点:

对于of_phy_connect函数的解析,请看下回。

相关推荐
蓝天居士5 小时前
Linux网络驱动之Fixed-Link(8)
网卡·设备驱动
蓝天居士4 天前
RTL8367RB芯片介绍(17)
网卡·设备驱动·芯片资料
蓝天居士11 天前
RTL8367RB芯片介绍(8)
网卡·设备驱动·芯片资料
蓝天居士13 天前
RTL8367RB芯片介绍(6)
网卡·设备驱动·芯片资料
蓝天居士14 天前
RTL8367RB芯片介绍(4)
网卡·设备驱动·芯片资料
秋天之落叶2 个月前
技嘉B760M gaming AC WIFI 主板自带瑞昱2.5G有线网卡的问题
网卡
zzc9216 个月前
根据Wireshark捕获数据包时间和长度绘制路由器发送给电脑数据的信号波形
网络·wireshark·智能路由器·网卡·packets·信号波形·192.168.1.103
qq_63466 个月前
字符设备驱动、块设备驱动和网络设备驱动
设备驱动
9527华安7 个月前
FPGA实现40G网卡NIC,基于PCIE4C+40G/50G Ethernet subsystem架构,提供工程源码和技术支持
fpga开发·架构·网卡·ethernet·nic·40g·pcie4c