Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@
};
};

/*
* With a #size-cells of 2, the 'size' property should be 2 cells long.
* Unfortunately the old firmware will only write the CMA value correctly
* if the property is 1 cell long. Fortunately the new firmware silently
* makes 'size' 2 cells long, so create what is actually an invalid DTS file
* on the understanding that it will be patched up as needed.
*/
&cma {
size = <0x4000000>; /* 64MB */
};

&soc {
system_timer: timer@7c003000 {
compatible = "brcm,bcm2835-system-timer";
Expand Down
29 changes: 27 additions & 2 deletions drivers/of/fdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,7 @@ int __init early_init_dt_scan_memory(void)

fdt_for_each_subnode(node, fdt, 0) {
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
int actual_size_cells = dt_root_size_cells;
const __be32 *reg, *endp;
int l;
bool hotpluggable;
Expand All @@ -1050,17 +1051,41 @@ int __init early_init_dt_scan_memory(void)
if (reg == NULL)
continue;

if (dt_root_size_cells == 2 &&
l % ((dt_root_addr_cells + 1) * sizeof(__be32)) == 0) {
const int size_cells = 1;
const __be32 *r = reg;
bool ok = true;

/* Scan reg to see if the content makes sense with size-cells == 1 */
endp = reg + (l / sizeof(__be32));
while ((endp - r) >= (dt_root_addr_cells + size_cells)) {
const u64 megabyte = 1024 * 1024ull;
const u64 max_memory = 64 * 1024 * 1024 * 1024ull;
u64 base, size;

base = dt_mem_next_cell(dt_root_addr_cells, &r);
size = dt_mem_next_cell(size_cells, &r);
if (base % megabyte != 0 || base >= max_memory ||
size % megabyte != 0 || size >= max_memory ||
size == 0)
ok = false;
}
if (ok)
actual_size_cells = size_cells;
}

endp = reg + (l / sizeof(__be32));
hotpluggable = of_get_flat_dt_prop(node, "hotpluggable", NULL);

pr_debug("memory scan node %s, reg size %d,\n",
fdt_get_name(fdt, node, NULL), l);

while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
while ((endp - reg) >= (dt_root_addr_cells + actual_size_cells)) {
u64 base, size;

base = dt_mem_next_cell(dt_root_addr_cells, &reg);
size = dt_mem_next_cell(dt_root_size_cells, &reg);
size = dt_mem_next_cell(actual_size_cells, &reg);

if (size == 0)
continue;
Expand Down
45 changes: 40 additions & 5 deletions drivers/of/of_reserved_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,25 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
int len;
const __be32 *prop;
bool nomap, default_cma;
int actual_size_cells = 0;

prop = of_get_flat_dt_prop(node, "reg", &len);
if (!prop)
return -ENOENT;

if (dt_root_addr_cells == 2 &&
dt_root_size_cells == 2 &&
len == (2 + 1) * sizeof(__be32)) {
pr_warn("invalid reg property size in '%s' - firmware out-of-date?\n",
uname);
actual_size_cells = 1;
t_len = (dt_root_addr_cells + actual_size_cells) * sizeof(__be32);
} else {
actual_size_cells = dt_root_size_cells;
}

t_len = (dt_root_addr_cells + actual_size_cells) * sizeof(__be32);

if (len && len % t_len != 0) {
pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
uname);
Expand All @@ -180,7 +194,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,

while (len >= t_len) {
base = dt_mem_next_cell(dt_root_addr_cells, &prop);
size = dt_mem_next_cell(dt_root_size_cells, &prop);
size = dt_mem_next_cell(actual_size_cells, &prop);

if (size && early_init_dt_reserve_memory(base, size, nomap) == 0) {
/* Architecture specific contiguous memory fixup. */
Expand Down Expand Up @@ -267,8 +281,21 @@ void __init fdt_scan_reserved_mem_reg_nodes(void)
if (default_cma && cma_skip_dt_default_reserved_mem())
continue;

if (!of_flat_dt_get_addr_size(child, "reg", &b, &s))
continue;
if (!of_flat_dt_get_addr_size(child, "reg", &b, &s)) {
const __be32 *prop;
int size;

prop = of_get_flat_dt_prop(child, "reg", &size);
if (dt_root_addr_cells == 2 &&
dt_root_size_cells == 2 &&
size == 12) {
/* Handle this specific error case from old firmware */
b = of_read_number(prop, dt_root_addr_cells);
s = of_read_number(prop + 2, 1);
} else {
continue;
}
}

base = b;
size = s;
Expand Down Expand Up @@ -406,16 +433,24 @@ static int __init __reserved_mem_alloc_size(unsigned long node, const char *unam
const __be32 *prop;
bool nomap, default_cma;
int ret;
int actual_size_cells;

prop = of_get_flat_dt_prop(node, "size", &len);
if (!prop)
return -EINVAL;
if (dt_root_size_cells == 2 && len == sizeof(__be32)) {
pr_warn("invalid reg property size in '%s' - firmware out-of-date?\n",
uname);
actual_size_cells = 1;
} else {
actual_size_cells = dt_root_size_cells;
}

if (len != dt_root_size_cells * sizeof(__be32)) {
if (len != actual_size_cells * sizeof(__be32)) {
pr_err("invalid size property in '%s' node.\n", uname);
return -EINVAL;
}
size = dt_mem_next_cell(dt_root_size_cells, &prop);
size = dt_mem_next_cell(actual_size_cells, &prop);

prop = of_get_flat_dt_prop(node, "alignment", &len);
if (prop) {
Expand Down
Loading