[PATCH 1/2] libfdt: add fdt_setprop_reg()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



This function will add a memory region property based on parent node's
"#address-cells" and "#size-cells" properties.

It will be used in implementing kdump with kexec_file_load system call
at linux kernel for arm64 once it is merged into kernel tree.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@xxxxxxxxxx>
---
 libfdt/fdt_addresses.c | 49 ++++++++++++++++++++++++++++++++++++++++++
 libfdt/libfdt.h        | 30 ++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/libfdt/fdt_addresses.c b/libfdt/fdt_addresses.c
index f13a87dfa068..08615c9f669a 100644
--- a/libfdt/fdt_addresses.c
+++ b/libfdt/fdt_addresses.c
@@ -95,3 +95,52 @@ int fdt_size_cells(const void *fdt, int nodeoffset)
 		return 1;
 	return val;
 }
+
+static void cpu64_to_fdt_cells(void *prop, uint64_t val, int cells)
+{
+	fdt32_t val32;
+
+	while (cells) {
+		val32 = cpu_to_fdt32(val >> (32 * (--cells)));
+		memcpy(prop, &val32, sizeof(val32));
+		prop = (uint8_t *)prop + sizeof(val32);
+	}
+}
+
+/* This function assumes that [address|size]_cells is 1 or 2 */
+int fdt_setprop_reg(void *fdt, int nodeoffset, const char *name,
+		    uint64_t addr, uint64_t size)
+{
+	int parent, addr_cells, size_cells, buf_size;
+	char buf[sizeof(fdt32_t) * 2 * 2];
+	void *prop;
+
+	parent = fdt_parent_offset(fdt, nodeoffset);
+	if (parent < 0)
+		return parent;
+
+	addr_cells = fdt_address_cells(fdt, parent);
+	if (addr_cells < 0)
+		return addr_cells;
+	size_cells = fdt_size_cells(fdt, parent);
+	if (size_cells < 0)
+		return size_cells;
+
+	if ((addr_cells == 1) && ((addr > UINT32_MAX) ||
+				  ((addr + size) > UINT32_MAX)))
+		return -FDT_ERR_BADVALUE;
+
+	if ((size_cells == 1) && (size > UINT32_MAX))
+		return -FDT_ERR_BADVALUE;
+
+	buf_size = (addr_cells + size_cells) * sizeof(fdt32_t);
+	prop = buf;
+	cpu64_to_fdt_cells(prop, addr, addr_cells);
+	prop = (uint8_t *)prop + addr_cells * sizeof(fdt32_t);
+	cpu64_to_fdt_cells(prop, size, size_cells);
+
+	if (!name)
+		name = "reg";
+
+	return fdt_setprop(fdt, nodeoffset, name, (const void *)buf, buf_size);
+}
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index fdaa3e6f39fe..6375d7cb7367 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -1690,6 +1690,36 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
 #define fdt_setprop_empty(fdt, nodeoffset, name) \
 	fdt_setprop((fdt), (nodeoffset), (name), NULL, 0)
 
+/**
+ * fdt_setprop_reg - add/set a memory region property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to add a property at
+ * @name: name of property
+ * @addr: physical start address
+ * @size: size of region
+ *
+ * If name is not specified, a default "reg" is used.
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *		#address-cells property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain a new property
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_reg(void *fdt, int nodeoffset, const char *name,
+		    uint64_t addr, uint64_t size);
+
 /**
  * fdt_appendprop - append to or create a property
  * @fdt: pointer to the device tree blob
-- 
2.19.1




[Index of Archives]     [Device Tree]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux