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

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

三、深入了解

上一回继续解析platform_device_add函数,没有讲完,本回继续往下讲解。为了便于理解和回顾,再次贴出其源码,在drivers/base/platform.c中,如下:

cpp 复制代码
/**
 * platform_device_add - add a platform device to device hierarchy
 * @pdev: platform device we're adding
 *
 * This is part 2 of platform_device_register(), though may be called
 * separately _iff_ pdev was allocated by platform_device_alloc().
 */
int platform_device_add(struct platform_device *pdev)
{
	u32 i;
	int ret;
 
	if (!pdev)
		return -EINVAL;
 
	if (!pdev->dev.parent)
		pdev->dev.parent = &platform_bus;
 
	pdev->dev.bus = &platform_bus_type;
 
	switch (pdev->id) {
	default:
		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
		break;
	case PLATFORM_DEVID_NONE:
		dev_set_name(&pdev->dev, "%s", pdev->name);
		break;
	case PLATFORM_DEVID_AUTO:
		/*
		 * Automatically allocated device ID. We mark it as such so
		 * that we remember it must be freed, and we append a suffix
		 * to avoid namespace collision with explicit IDs.
		 */
		ret = ida_alloc(&platform_devid_ida, GFP_KERNEL);
		if (ret < 0)
			goto err_out;
		pdev->id = ret;
		pdev->id_auto = true;
		dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
		break;
	}
 
	for (i = 0; i < pdev->num_resources; i++) {
		struct resource *p, *r = &pdev->resource[i];
 
		if (r->name == NULL)
			r->name = dev_name(&pdev->dev);
 
		p = r->parent;
		if (!p) {
			if (resource_type(r) == IORESOURCE_MEM)
				p = &iomem_resource;
			else if (resource_type(r) == IORESOURCE_IO)
				p = &ioport_resource;
		}
 
		if (p) {
			ret = insert_resource(p, r);
			if (ret) {
				dev_err(&pdev->dev, "failed to claim resource %d: %pR\n", i, r);
				goto failed;
			}
		}
	}
 
	pr_debug("Registering platform device '%s'. Parent at %s\n",
		 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
 
	ret = device_add(&pdev->dev);
	if (ret == 0)
		return ret;
 
 failed:
	if (pdev->id_auto) {
		ida_free(&platform_devid_ida, pdev->id);
		pdev->id = PLATFORM_DEVID_AUTO;
	}
 
	while (i--) {
		struct resource *r = &pdev->resource[i];
		if (r->parent)
			release_resource(r);
	}
 
 err_out:
	return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);

上一回开始解析__insert_resource函数,它是由platform_device_add函数中的insert_resource函数引出的。该函数总体上分为3段,上一回解析了第1段代码,本回解析后两段代码。为了便于理解和回顾,再次贴出__insert_resource函数源码,在kernel/linux-5.10-origin/kernel/resource.c中,如下:

cpp 复制代码
/*
 * Insert a resource into the resource tree. If successful, return NULL,
 * otherwise return the conflicting resource (compare to __request_resource())
 */
static struct resource * __insert_resource(struct resource *parent, struct resource *new)
{
	struct resource *first, *next;
 
	for (;; parent = first) {
		first = __request_resource(parent, new);
		if (!first)
			return first;
 
		if (first == parent)
			return first;
		if (WARN_ON(first == new))	/* duplicated insertion */
			return first;
 
		if ((first->start > new->start) || (first->end < new->end))
			break;
		if ((first->start == new->start) && (first->end == new->end))
			break;
	}
 
	for (next = first; ; next = next->sibling) {
		/* Partial overlap? Bad, and unfixable */
		if (next->start < new->start || next->end > new->end)
			return next;
		if (!next->sibling)
			break;
		if (next->sibling->start > new->end)
			break;
	}
 
	new->parent = parent;
	new->sibling = next->sibling;
	new->child = first;
 
	next->sibling = NULL;
	for (next = first; next; next = next->sibling)
		next->parent = new;
 
	if (parent->child == first) {
		parent->child = new;
	} else {
		next = parent->child;
		while (next->sibling != first)
			next = next->sibling;
		next->sibling = new;
	}
	return NULL;
}

前文书已讲过,__insert_resource函数的功能和返回值为:将资源插入资源树。若成功,返回空指针(NULL);否则返回冲突资源。

__insert_resource函数代码整体上分为三段,一段一段来看。

1)先尝试简单插入

2)检查冲突是否可嵌套(new完全包含所有冲突子节点)

代码片段如下:

cpp 复制代码
    for (next = first; ; next = next->sibling) {
		/* Partial overlap? Bad, and unfixable */
		if (next->start < new->start || next->end > new->end)
			return next;
		if (!next->sibling)
			break;
		if (next->sibling->start > new->end)
			break;
	}

上一步中的first指向了资源冲突的节点,见上一回中的示意图:

那么这里就由此节点向后遍历各个兄弟节点,作以下进一步判断:

  • 如果某兄弟节点的start < 新资源节点的start,或者该兄弟节点的end大于新资源节点的end,也就是图中的前三种情况,那么就直接返回该兄弟节点;
  • 如果直到遍历结束都没有前三种情况,那么就是第4种情况,跳出循环;
  • 如果下一个兄弟节点的起始还小于新节点的结束,那么说明不止冲突了一个节点,起码有两个节点资源冲突了。那么也跳出循环,往下进行。

3)插入new节点,调整父子关系

代码片段如下:

cpp 复制代码
	new->parent = parent;
	new->sibling = next->sibling;
	new->child = first;
 
	next->sibling = NULL;
	for (next = first; next; next = next->sibling)
		next->parent = new;
 
	if (parent->child == first) {
		parent->child = new;
	} else {
		next = parent->child;
		while (next->sibling != first)
			next = next->sibling;
		next->sibling = new;
	}
	return NULL;
相关推荐
星恒讯工业路由器36 分钟前
AGV集群通信架构:从单点到百台级调度的挑战与对策
网络·物联网·信息与通信·工业物联网·通信架构·agv集群·实时调度
夜月yeyue2 小时前
AUTOSAR CP 从上电到 Runnable
c语言·网络·tcp/ip·车载系统
lsh曙光2 小时前
延时at指令和定时cron指令
linux·服务器·网络
treesforest2 小时前
IP定位技术在网络犯罪侦查中的应用与价值
网络·网络协议·tcp/ip·网络安全·ip归属地查询·反欺诈
圆山猫3 小时前
[Virtualization](四):Linux KVM/RISC-V 的 vCPU 运行路径
java·linux·risc-v
布鲁飞丝3 小时前
vivo Pulsar 万亿级消息处理实践()-Ansible运维部署
运维·ansible
XR1234567883 小时前
企业全光网络架构选型技术白皮书:从物理层到运维层的全链路分析
运维·网络·架构
似的8353 小时前
一步一步学习使用FireMonkey动画() 使用TAnimator类创建动画
linux·学习·nginx
HiDev_3 小时前
【非标自动化】2、认识元器件(直线模组)
运维·自动化
萧瑟余晖4 小时前
Java深入解析篇九之NIO详解
java·网络·nio