Commit 0857beff authored by Sourabh Jain's avatar Sourabh Jain Committed by Michael Ellerman
Browse files

powerpc/kexec: make the update_cpus_node() function public



Move the update_cpus_node() from kexec/{file_load_64.c => core_64.c}
to allow other kexec components to use it.

Later in the series, this function is used for in-kernel updates
to the kdump image during CPU/memory hotplug or online/offline events for
both kexec_load and kexec_file_load syscalls.

No functional changes are intended.

Signed-off-by: default avatarSourabh Jain <sourabhjain@linux.ibm.com>
Acked-by: default avatarHari Bathini <hbathini@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240326055413.186534-5-sourabhjain@linux.ibm.com
parent f5f0da5a
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -185,6 +185,10 @@ static inline void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))

#endif /* CONFIG_CRASH_DUMP */

#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP)
int update_cpus_node(void *fdt);
#endif

#ifdef CONFIG_PPC_BOOK3S_64
#include <asm/book3s/64/kexec.h>
#endif
+91 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/cpu.h>
#include <linux/hardirq.h>
#include <linux/of.h>
#include <linux/libfdt.h>

#include <asm/page.h>
#include <asm/current.h>
@@ -30,6 +31,7 @@
#include <asm/hw_breakpoint.h>
#include <asm/svm.h>
#include <asm/ultravisor.h>
#include <asm/crashdump-ppc64.h>

int machine_kexec_prepare(struct kimage *image)
{
@@ -419,3 +421,92 @@ static int __init export_htab_values(void)
}
late_initcall(export_htab_values);
#endif /* CONFIG_PPC_64S_HASH_MMU */

#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP)
/**
 * add_node_props - Reads node properties from device node structure and add
 *                  them to fdt.
 * @fdt:            Flattened device tree of the kernel
 * @node_offset:    offset of the node to add a property at
 * @dn:             device node pointer
 *
 * Returns 0 on success, negative errno on error.
 */
static int add_node_props(void *fdt, int node_offset, const struct device_node *dn)
{
	int ret = 0;
	struct property *pp;

	if (!dn)
		return -EINVAL;

	for_each_property_of_node(dn, pp) {
		ret = fdt_setprop(fdt, node_offset, pp->name, pp->value, pp->length);
		if (ret < 0) {
			pr_err("Unable to add %s property: %s\n", pp->name, fdt_strerror(ret));
			return ret;
		}
	}
	return ret;
}

/**
 * update_cpus_node - Update cpus node of flattened device tree using of_root
 *                    device node.
 * @fdt:              Flattened device tree of the kernel.
 *
 * Returns 0 on success, negative errno on error.
 */
int update_cpus_node(void *fdt)
{
	struct device_node *cpus_node, *dn;
	int cpus_offset, cpus_subnode_offset, ret = 0;

	cpus_offset = fdt_path_offset(fdt, "/cpus");
	if (cpus_offset < 0 && cpus_offset != -FDT_ERR_NOTFOUND) {
		pr_err("Malformed device tree: error reading /cpus node: %s\n",
		       fdt_strerror(cpus_offset));
		return cpus_offset;
	}

	if (cpus_offset > 0) {
		ret = fdt_del_node(fdt, cpus_offset);
		if (ret < 0) {
			pr_err("Error deleting /cpus node: %s\n", fdt_strerror(ret));
			return -EINVAL;
		}
	}

	/* Add cpus node to fdt */
	cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "cpus");
	if (cpus_offset < 0) {
		pr_err("Error creating /cpus node: %s\n", fdt_strerror(cpus_offset));
		return -EINVAL;
	}

	/* Add cpus node properties */
	cpus_node = of_find_node_by_path("/cpus");
	ret = add_node_props(fdt, cpus_offset, cpus_node);
	of_node_put(cpus_node);
	if (ret < 0)
		return ret;

	/* Loop through all subnodes of cpus and add them to fdt */
	for_each_node_by_type(dn, "cpu") {
		cpus_subnode_offset = fdt_add_subnode(fdt, cpus_offset, dn->full_name);
		if (cpus_subnode_offset < 0) {
			pr_err("Unable to add %s subnode: %s\n", dn->full_name,
			       fdt_strerror(cpus_subnode_offset));
			ret = cpus_subnode_offset;
			goto out;
		}

		ret = add_node_props(fdt, cpus_subnode_offset, dn);
		if (ret < 0)
			goto out;
	}
out:
	of_node_put(dn);
	return ret;
}
#endif /* CONFIG_KEXEC_FILE || CONFIG_CRASH_DUMP */
+0 −87
Original line number Diff line number Diff line
@@ -838,93 +838,6 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
	return extra_size + kdump_extra_fdt_size_ppc64(image);
}

/**
 * add_node_props - Reads node properties from device node structure and add
 *                  them to fdt.
 * @fdt:            Flattened device tree of the kernel
 * @node_offset:    offset of the node to add a property at
 * @dn:             device node pointer
 *
 * Returns 0 on success, negative errno on error.
 */
static int add_node_props(void *fdt, int node_offset, const struct device_node *dn)
{
	int ret = 0;
	struct property *pp;

	if (!dn)
		return -EINVAL;

	for_each_property_of_node(dn, pp) {
		ret = fdt_setprop(fdt, node_offset, pp->name, pp->value, pp->length);
		if (ret < 0) {
			pr_err("Unable to add %s property: %s\n", pp->name, fdt_strerror(ret));
			return ret;
		}
	}
	return ret;
}

/**
 * update_cpus_node - Update cpus node of flattened device tree using of_root
 *                    device node.
 * @fdt:              Flattened device tree of the kernel.
 *
 * Returns 0 on success, negative errno on error.
 */
static int update_cpus_node(void *fdt)
{
	struct device_node *cpus_node, *dn;
	int cpus_offset, cpus_subnode_offset, ret = 0;

	cpus_offset = fdt_path_offset(fdt, "/cpus");
	if (cpus_offset < 0 && cpus_offset != -FDT_ERR_NOTFOUND) {
		pr_err("Malformed device tree: error reading /cpus node: %s\n",
		       fdt_strerror(cpus_offset));
		return cpus_offset;
	}

	if (cpus_offset > 0) {
		ret = fdt_del_node(fdt, cpus_offset);
		if (ret < 0) {
			pr_err("Error deleting /cpus node: %s\n", fdt_strerror(ret));
			return -EINVAL;
		}
	}

	/* Add cpus node to fdt */
	cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "cpus");
	if (cpus_offset < 0) {
		pr_err("Error creating /cpus node: %s\n", fdt_strerror(cpus_offset));
		return -EINVAL;
	}

	/* Add cpus node properties */
	cpus_node = of_find_node_by_path("/cpus");
	ret = add_node_props(fdt, cpus_offset, cpus_node);
	of_node_put(cpus_node);
	if (ret < 0)
		return ret;

	/* Loop through all subnodes of cpus and add them to fdt */
	for_each_node_by_type(dn, "cpu") {
		cpus_subnode_offset = fdt_add_subnode(fdt, cpus_offset, dn->full_name);
		if (cpus_subnode_offset < 0) {
			pr_err("Unable to add %s subnode: %s\n", dn->full_name,
			       fdt_strerror(cpus_subnode_offset));
			ret = cpus_subnode_offset;
			goto out;
		}

		ret = add_node_props(fdt, cpus_subnode_offset, dn);
		if (ret < 0)
			goto out;
	}
out:
	of_node_put(dn);
	return ret;
}

static int copy_property(void *fdt, int node_offset, const struct device_node *dn,
			 const char *propname)
{