int of_overlay_fdt_apply()

in overlay.c [1017:1074]


int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
			 int *ovcs_id)
{
	void *new_fdt;
	void *new_fdt_align;
	int ret;
	u32 size;
	struct device_node *overlay_root = NULL;

	*ovcs_id = 0;

	if (overlay_fdt_size < sizeof(struct fdt_header) ||
	    fdt_check_header(overlay_fdt)) {
		pr_err("Invalid overlay_fdt header\n");
		return -EINVAL;
	}

	size = fdt_totalsize(overlay_fdt);
	if (overlay_fdt_size < size)
		return -EINVAL;

	/*
	 * Must create permanent copy of FDT because of_fdt_unflatten_tree()
	 * will create pointers to the passed in FDT in the unflattened tree.
	 */
	new_fdt = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL);
	if (!new_fdt)
		return -ENOMEM;

	new_fdt_align = PTR_ALIGN(new_fdt, FDT_ALIGN_SIZE);
	memcpy(new_fdt_align, overlay_fdt, size);

	of_fdt_unflatten_tree(new_fdt_align, NULL, &overlay_root);
	if (!overlay_root) {
		pr_err("unable to unflatten overlay_fdt\n");
		ret = -EINVAL;
		goto out_free_new_fdt;
	}

	ret = of_overlay_apply(new_fdt, overlay_root, ovcs_id);
	if (ret < 0) {
		/*
		 * new_fdt and overlay_root now belong to the overlay
		 * changeset.
		 * overlay changeset code is responsible for freeing them.
		 */
		goto out;
	}

	return 0;


out_free_new_fdt:
	kfree(new_fdt);

out:
	return ret;
}