File Index
Files and directories
Sign in
FILE

fdt_early.c

File preview with syntax highlighting.

linux-6.19.14/arch/riscv/kernel/pi/fdt_early.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2#include <linux/types.h>
  3#include <linux/init.h>
  4#include <linux/libfdt.h>
  5#include <linux/ctype.h>
  6#include <asm/csr.h>
  7
  8#include "pi.h"
  9
 10u64 get_kaslr_seed(uintptr_t dtb_pa)
 11{
 12	int node, len;
 13	fdt64_t *prop;
 14	u64 ret;
 15
 16	node = fdt_path_offset((void *)dtb_pa, "/chosen");
 17	if (node < 0)
 18		return 0;
 19
 20	prop = fdt_getprop_w((void *)dtb_pa, node, "kaslr-seed", &len);
 21	if (!prop || len != sizeof(u64))
 22		return 0;
 23
 24	ret = fdt64_to_cpu(*prop);
 25	*prop = 0;
 26	return ret;
 27}
 28
 29/**
 30 *  fdt_device_is_available - check if a device is available for use
 31 *
 32 * @fdt: pointer to the device tree blob
 33 * @node: offset of the node whose property to find
 34 *
 35 *  Returns true if the status property is absent or set to "okay" or "ok",
 36 *  false otherwise
 37 */
 38static bool fdt_device_is_available(const void *fdt, int node)
 39{
 40	const char *status;
 41	int statlen;
 42
 43	status = fdt_getprop(fdt, node, "status", &statlen);
 44	if (!status)
 45		return true;
 46
 47	if (statlen > 0) {
 48		if (!strcmp(status, "okay") || !strcmp(status, "ok"))
 49			return true;
 50	}
 51
 52	return false;
 53}
 54
 55/* Copy of fdt_nodename_eq_ */
 56static int fdt_node_name_eq(const void *fdt, int offset,
 57			    const char *s)
 58{
 59	int olen;
 60	int len = strlen(s);
 61	const char *p = fdt_get_name(fdt, offset, &olen);
 62
 63	if (!p || olen < len)
 64		/* short match */
 65		return 0;
 66
 67	if (memcmp(p, s, len) != 0)
 68		return 0;
 69
 70	if (p[len] == '\0')
 71		return 1;
 72	else if (!memchr(s, '@', len) && (p[len] == '@'))
 73		return 1;
 74	else
 75		return 0;
 76}
 77
 78/**
 79 *  isa_string_contains - check if isa string contains an extension
 80 *
 81 * @isa_str: isa string to search
 82 * @ext_name: the extension to search for
 83 *
 84 *  Returns true if the extension is in the given isa string,
 85 *  false otherwise
 86 */
 87static bool isa_string_contains(const char *isa_str, const char *ext_name)
 88{
 89	size_t i, single_end, len = strlen(ext_name);
 90	char ext_end;
 91
 92	/* Error must contain rv32/64 */
 93	if (strlen(isa_str) < 4)
 94		return false;
 95
 96	if (len == 1) {
 97		single_end = strcspn(isa_str, "sSxXzZ");
 98		/* Search for single chars between rv32/64 and multi-letter extensions */
 99		for (i = 4; i < single_end; i++) {
100			if (tolower(isa_str[i]) == ext_name[0])
101				return true;
102		}
103		return false;
104	}
105
106	/* Skip to start of multi-letter extensions */
107	isa_str = strpbrk(isa_str, "sSxXzZ");
108	while (isa_str) {
109		if (strncasecmp(isa_str, ext_name, len) == 0) {
110			ext_end = isa_str[len];
111			/* Check if matches the whole extension. */
112			if (ext_end == '\0' || ext_end == '_')
113				return true;
114		}
115		/* Multi-letter extensions must be split from other multi-letter
116		 * extensions with an "_", the end of a multi-letter extension will
117		 * either be the null character or the "_" at the start of the next
118		 * multi-letter extension.
119		 */
120		isa_str = strchr(isa_str, '_');
121		if (isa_str)
122			isa_str++;
123	}
124
125	return false;
126}
127
128/**
129 *  early_cpu_isa_ext_available - check if cpu node has an extension
130 *
131 * @fdt: pointer to the device tree blob
132 * @node: offset of the cpu node
133 * @ext_name: the extension to search for
134 *
135 *  Returns true if the cpu node has the extension,
136 *  false otherwise
137 */
138static bool early_cpu_isa_ext_available(const void *fdt, int node, const char *ext_name)
139{
140	const void *prop;
141	int len;
142
143	prop = fdt_getprop(fdt, node, "riscv,isa-extensions", &len);
144	if (prop && fdt_stringlist_contains(prop, len, ext_name))
145		return true;
146
147	prop = fdt_getprop(fdt, node, "riscv,isa", &len);
148	if (prop && isa_string_contains(prop, ext_name))
149		return true;
150
151	return false;
152}
153
154/**
155 *  fdt_early_match_extension_isa - check if all cpu nodes have an extension
156 *
157 * @fdt: pointer to the device tree blob
158 * @ext_name: the extension to search for
159 *
160 *  Returns true if the all available the cpu nodes have the extension,
161 *  false otherwise
162 */
163bool fdt_early_match_extension_isa(const void *fdt, const char *ext_name)
164{
165	int node, parent;
166	bool ret = false;
167
168	parent = fdt_path_offset(fdt, "/cpus");
169	if (parent < 0)
170		return false;
171
172	fdt_for_each_subnode(node, fdt, parent) {
173		if (!fdt_node_name_eq(fdt, node, "cpu"))
174			continue;
175
176		if (!fdt_device_is_available(fdt, node))
177			continue;
178
179		if (!early_cpu_isa_ext_available(fdt, node, ext_name))
180			return false;
181
182		ret = true;
183	}
184
185	return ret;
186}
187
188/**
189 *  set_satp_mode_from_fdt - determine SATP mode based on the MMU type in fdt
190 *
191 * @dtb_pa: physical address of the device tree blob
192 *
193 *  Returns the SATP mode corresponding to the MMU type of the first enabled CPU,
194 *  0 otherwise
195 */
196u64 set_satp_mode_from_fdt(uintptr_t dtb_pa)
197{
198	const void *fdt = (const void *)dtb_pa;
199	const char *mmu_type;
200	int node, parent;
201
202	parent = fdt_path_offset(fdt, "/cpus");
203	if (parent < 0)
204		return 0;
205
206	fdt_for_each_subnode(node, fdt, parent) {
207		if (!fdt_node_name_eq(fdt, node, "cpu"))
208			continue;
209
210		if (!fdt_device_is_available(fdt, node))
211			continue;
212
213		mmu_type = fdt_getprop(fdt, node, "mmu-type", NULL);
214		if (!mmu_type)
215			break;
216
217		if (!strcmp(mmu_type, "riscv,sv39"))
218			return SATP_MODE_39;
219		else if (!strcmp(mmu_type, "riscv,sv48"))
220			return SATP_MODE_48;
221		break;
222	}
223
224	return 0;
225}
~/ Read-only file preview.