···12741274 void *fdt = initial_boot_params;1275127512761276 /* Save the statically-placed regions in the reserved_mem array */12771277- fdt_scan_reserved_mem_reg_nodes();12771277+ fdt_scan_reserved_mem_late();1278127812791279 /* Populate an empty root node when bootloader doesn't provide one */12801280 if (!fdt) {
···2424#include <linux/slab.h>2525#include <linux/memblock.h>2626#include <linux/kmemleak.h>2727-#include <linux/cma.h>2828-#include <linux/dma-map-ops.h>29273028#include "of_private.h"3129···102104 reserved_mem = new_array;103105}104106105105-static void __init fdt_init_reserved_mem_node(struct reserved_mem *rmem);106106-/*107107- * fdt_reserved_mem_save_node() - save fdt node for second pass initialization108108- */109109-static void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,110110- phys_addr_t base, phys_addr_t size)111111-{112112- struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];113113-114114- if (reserved_mem_count == total_reserved_mem_cnt) {115115- pr_err("not enough space for all defined regions.\n");116116- return;117117- }118118-119119- rmem->fdt_node = node;120120- rmem->name = uname;121121- rmem->base = base;122122- rmem->size = size;123123-124124- /* Call the region specific initialization function */125125- fdt_init_reserved_mem_node(rmem);126126-127127- reserved_mem_count++;128128-}107107+static void fdt_init_reserved_mem_node(unsigned long node, const char *uname,108108+ phys_addr_t base, phys_addr_t size);109109+static int fdt_validate_reserved_mem_node(unsigned long node,110110+ phys_addr_t *align);111111+static int fdt_fixup_reserved_mem_node(unsigned long node,112112+ phys_addr_t base, phys_addr_t size);129113130114static int __init early_init_dt_reserve_memory(phys_addr_t base,131115 phys_addr_t size, bool nomap)···134154 const char *uname)135155{136156 phys_addr_t base, size;137137- int i, len;157157+ int i, len, err;138158 const __be32 *prop;139139- bool nomap, default_cma;159159+ bool nomap;140160141161 prop = of_flat_dt_get_addr_size_prop(node, "reg", &len);142162 if (!prop)143163 return -ENOENT;144164145165 nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;146146- default_cma = of_get_flat_dt_prop(node, "linux,cma-default", NULL);147166148148- if (default_cma && cma_skip_dt_default_reserved_mem()) {149149- pr_err("Skipping dt linux,cma-default for \"cma=\" kernel param.\n");150150- return -EINVAL;151151- }167167+ err = fdt_validate_reserved_mem_node(node, NULL);168168+ if (err && err != -ENODEV)169169+ return err;152170153171 for (i = 0; i < len; i++) {154172 u64 b, s;···157179 size = s;158180159181 if (size && early_init_dt_reserve_memory(base, size, nomap) == 0) {160160- /* Architecture specific contiguous memory fixup. */161161- if (of_flat_dt_is_compatible(node, "shared-dma-pool") &&162162- of_get_flat_dt_prop(node, "reusable", NULL))163163- dma_contiguous_early_fixup(base, size);182182+ fdt_fixup_reserved_mem_node(node, base, size);164183 pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",165184 uname, &base, (unsigned long)(size / SZ_1M));166185 } else {···191216 return 0;192217}193218194194-static void __init __rmem_check_for_overlap(void);219219+static int __init __rmem_cmp(const void *a, const void *b)220220+{221221+ const struct reserved_mem *ra = a, *rb = b;222222+223223+ if (ra->base < rb->base)224224+ return -1;225225+226226+ if (ra->base > rb->base)227227+ return 1;228228+229229+ /*230230+ * Put the dynamic allocations (address == 0, size == 0) before static231231+ * allocations at address 0x0 so that overlap detection works232232+ * correctly.233233+ */234234+ if (ra->size < rb->size)235235+ return -1;236236+ if (ra->size > rb->size)237237+ return 1;238238+239239+ return 0;240240+}241241+242242+static void __init __rmem_check_for_overlap(void)243243+{244244+ int i;245245+246246+ if (reserved_mem_count < 2)247247+ return;248248+249249+ sort(reserved_mem, reserved_mem_count, sizeof(reserved_mem[0]),250250+ __rmem_cmp, NULL);251251+ for (i = 0; i < reserved_mem_count - 1; i++) {252252+ struct reserved_mem *this, *next;253253+254254+ this = &reserved_mem[i];255255+ next = &reserved_mem[i + 1];256256+257257+ if (this->base + this->size > next->base) {258258+ phys_addr_t this_end, next_end;259259+260260+ this_end = this->base + this->size;261261+ next_end = next->base + next->size;262262+ pr_err("OVERLAP DETECTED!\n%s (%pa--%pa) overlaps with %s (%pa--%pa)\n",263263+ this->name, &this->base, &this_end,264264+ next->name, &next->base, &next_end);265265+ }266266+ }267267+}195268196269/**197197- * fdt_scan_reserved_mem_reg_nodes() - Store info for the "reg" defined198198- * reserved memory regions.270270+ * fdt_scan_reserved_mem_late() - Scan FDT and initialize remaining reserved271271+ * memory regions.199272 *200200- * This function is used to scan through the DT and store the201201- * information for the reserved memory regions that are defined using202202- * the "reg" property. The region node number, name, base address, and203203- * size are all stored in the reserved_mem array by calling the204204- * fdt_reserved_mem_save_node() function.273273+ * This function is used to scan again through the DT and initialize the274274+ * "static" reserved memory regions, that are defined using the "reg"275275+ * property. Each such region is then initialized with its specific init276276+ * function and stored in the global reserved_mem array.205277 */206206-void __init fdt_scan_reserved_mem_reg_nodes(void)278278+void __init fdt_scan_reserved_mem_late(void)207279{208280 const void *fdt = initial_boot_params;209281 phys_addr_t base, size;···275253276254 fdt_for_each_subnode(child, fdt, node) {277255 const char *uname;278278- bool default_cma = of_get_flat_dt_prop(child, "linux,cma-default", NULL);279256 u64 b, s;257257+ int ret;280258281259 if (!of_fdt_device_is_available(fdt, child))282260 continue;283283- if (default_cma && cma_skip_dt_default_reserved_mem())284284- continue;285261286262 if (!of_flat_dt_get_addr_size(child, "reg", &b, &s))263263+ continue;264264+265265+ ret = fdt_validate_reserved_mem_node(child, NULL);266266+ if (ret && ret != -ENODEV)287267 continue;288268289269 base = b;···293269294270 if (size) {295271 uname = fdt_get_name(fdt, child, NULL);296296- fdt_reserved_mem_save_node(child, uname, base, size);272272+ fdt_init_reserved_mem_node(child, uname, base, size);297273 }298274 }299275···304280static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname);305281306282/*307307- * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory283283+ * fdt_scan_reserved_mem() - reserve and allocate memory occupied by284284+ * reserved memory regions.285285+ *286286+ * This function is used to scan through the FDT and mark memory occupied287287+ * by all static (defined by the "reg" property) reserved memory regions.288288+ * Then memory for all dynamic regions (defined by size & alignment) is289289+ * allocated, a region specific init function is called and region information290290+ * is stored in the reserved_mem array.308291 */309292int __init fdt_scan_reserved_mem(void)310293{···428397 phys_addr_t base = 0, align = 0, size;429398 int i, len;430399 const __be32 *prop;431431- bool nomap, default_cma;400400+ bool nomap;432401 int ret;433402434403 prop = of_get_flat_dt_prop(node, "size", &len);···452421 }453422454423 nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;455455- default_cma = of_get_flat_dt_prop(node, "linux,cma-default", NULL);456424457457- if (default_cma && cma_skip_dt_default_reserved_mem()) {458458- pr_err("Skipping dt linux,cma-default for \"cma=\" kernel param.\n");459459- return -EINVAL;460460- }461461-462462- /* Need adjust the alignment to satisfy the CMA requirement */463463- if (IS_ENABLED(CONFIG_CMA)464464- && of_flat_dt_is_compatible(node, "shared-dma-pool")465465- && of_get_flat_dt_prop(node, "reusable", NULL)466466- && !nomap)467467- align = max_t(phys_addr_t, align, CMA_MIN_ALIGNMENT_BYTES);425425+ ret = fdt_validate_reserved_mem_node(node, &align);426426+ if (ret && ret != -ENODEV)427427+ return ret;468428469429 prop = of_flat_dt_get_addr_size_prop(node, "alloc-ranges", &len);470430 if (prop) {···490468 uname, (unsigned long)(size / SZ_1M));491469 return -ENOMEM;492470 }493493- /* Architecture specific contiguous memory fixup. */494494- if (of_flat_dt_is_compatible(node, "shared-dma-pool") &&495495- of_get_flat_dt_prop(node, "reusable", NULL))496496- dma_contiguous_early_fixup(base, size);497497- /* Save region in the reserved_mem array */498498- fdt_reserved_mem_save_node(node, uname, base, size);471471+472472+ fdt_fixup_reserved_mem_node(node, base, size);473473+ fdt_init_reserved_mem_node(node, uname, base, size);474474+499475 return 0;500476}501477478478+extern const struct of_device_id __reservedmem_of_table[];502479static const struct of_device_id __rmem_of_table_sentinel503480 __used __section("__reservedmem_of_table_end");504481505505-/*506506- * __reserved_mem_init_node() - call region specific reserved memory init code482482+/**483483+ * fdt_fixup_reserved_mem_node() - call fixup function for a reserved memory node484484+ * @node: FDT node to fixup485485+ * @base: base address of the reserved memory region486486+ * @size: size of the reserved memory region487487+ *488488+ * This function iterates through the reserved memory drivers and calls489489+ * the node_fixup callback for the compatible entry matching the node.490490+ *491491+ * Return: 0 on success, -ENODEV if no compatible match found507492 */508508-static int __init __reserved_mem_init_node(struct reserved_mem *rmem)493493+static int __init fdt_fixup_reserved_mem_node(unsigned long node,494494+ phys_addr_t base, phys_addr_t size)509495{510510- extern const struct of_device_id __reservedmem_of_table[];511496 const struct of_device_id *i;512512- int ret = -ENOENT;497497+ int ret = -ENODEV;513498514514- for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {515515- reservedmem_of_init_fn initfn = i->data;516516- const char *compat = i->compatible;499499+ for (i = __reservedmem_of_table; ret == -ENODEV &&500500+ i < &__rmem_of_table_sentinel; i++) {501501+ const struct reserved_mem_ops *ops = i->data;517502518518- if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))503503+ if (!of_flat_dt_is_compatible(node, i->compatible))519504 continue;520505521521- ret = initfn(rmem);506506+ if (ops->node_fixup)507507+ ret = ops->node_fixup(node, base, size);508508+ }509509+ return ret;510510+}511511+512512+/**513513+ * fdt_validate_reserved_mem_node() - validate a reserved memory node514514+ * @node: FDT node to validate515515+ * @align: pointer to store the validated alignment (may be modified by callback)516516+ *517517+ * This function iterates through the reserved memory drivers and calls518518+ * the node_validate callback for the compatible entry matching the node.519519+ *520520+ * Return: 0 on success, -ENODEV if no compatible match found521521+ */522522+static int __init fdt_validate_reserved_mem_node(unsigned long node, phys_addr_t *align)523523+{524524+ const struct of_device_id *i;525525+ int ret = -ENODEV;526526+527527+ for (i = __reservedmem_of_table; ret == -ENODEV &&528528+ i < &__rmem_of_table_sentinel; i++) {529529+ const struct reserved_mem_ops *ops = i->data;530530+531531+ if (!of_flat_dt_is_compatible(node, i->compatible))532532+ continue;533533+534534+ if (ops->node_validate)535535+ ret = ops->node_validate(node, align);536536+ }537537+ return ret;538538+}539539+540540+/**541541+ * __reserved_mem_init_node() - initialize a reserved memory region542542+ * @rmem: reserved_mem structure to initialize543543+ * @node: FDT node describing the reserved memory region544544+ *545545+ * This function iterates through the reserved memory drivers and calls the546546+ * node_init callback for the compatible entry matching the node. On success,547547+ * the operations pointer is stored in the reserved_mem structure.548548+ *549549+ * Return: 0 on success, -ENODEV if no compatible match found550550+ */551551+static int __init __reserved_mem_init_node(struct reserved_mem *rmem,552552+ unsigned long node)553553+{554554+ const struct of_device_id *i;555555+ int ret = -ENODEV;556556+557557+ for (i = __reservedmem_of_table; ret == -ENODEV &&558558+ i < &__rmem_of_table_sentinel; i++) {559559+ const struct reserved_mem_ops *ops = i->data;560560+ const char *compat = i->compatible;561561+562562+ if (!of_flat_dt_is_compatible(node, compat))563563+ continue;564564+565565+ ret = ops->node_init(node, rmem);522566 if (ret == 0) {567567+ rmem->ops = ops;523568 pr_info("initialized node %s, compatible id %s\n",524569 rmem->name, compat);525525- break;570570+ return ret;526571 }527572 }528573 return ret;529574}530575531531-static int __init __rmem_cmp(const void *a, const void *b)532532-{533533- const struct reserved_mem *ra = a, *rb = b;534534-535535- if (ra->base < rb->base)536536- return -1;537537-538538- if (ra->base > rb->base)539539- return 1;540540-541541- /*542542- * Put the dynamic allocations (address == 0, size == 0) before static543543- * allocations at address 0x0 so that overlap detection works544544- * correctly.545545- */546546- if (ra->size < rb->size)547547- return -1;548548- if (ra->size > rb->size)549549- return 1;550550-551551- if (ra->fdt_node < rb->fdt_node)552552- return -1;553553- if (ra->fdt_node > rb->fdt_node)554554- return 1;555555-556556- return 0;557557-}558558-559559-static void __init __rmem_check_for_overlap(void)560560-{561561- int i;562562-563563- if (reserved_mem_count < 2)564564- return;565565-566566- sort(reserved_mem, reserved_mem_count, sizeof(reserved_mem[0]),567567- __rmem_cmp, NULL);568568- for (i = 0; i < reserved_mem_count - 1; i++) {569569- struct reserved_mem *this, *next;570570-571571- this = &reserved_mem[i];572572- next = &reserved_mem[i + 1];573573-574574- if (this->base + this->size > next->base) {575575- phys_addr_t this_end, next_end;576576-577577- this_end = this->base + this->size;578578- next_end = next->base + next->size;579579- pr_err("OVERLAP DETECTED!\n%s (%pa--%pa) overlaps with %s (%pa--%pa)\n",580580- this->name, &this->base, &this_end,581581- next->name, &next->base, &next_end);582582- }583583- }584584-}585585-586576/**587577 * fdt_init_reserved_mem_node() - Initialize a reserved memory region588588- * @rmem: reserved_mem struct of the memory region to be initialized.578578+ * @node: fdt node of the initialized region579579+ * @uname: name of the reserved memory node580580+ * @base: base address of the reserved memory region581581+ * @size: size of the reserved memory region589582 *590590- * This function is used to call the region specific initialization591591- * function for a reserved memory region.583583+ * This function calls the region-specific initialization function for a584584+ * reserved memory region and saves all region-specific data to the585585+ * reserved_mem array to allow of_reserved_mem_lookup() to find it.592586 */593593-static void __init fdt_init_reserved_mem_node(struct reserved_mem *rmem)587587+static void __init fdt_init_reserved_mem_node(unsigned long node, const char *uname,588588+ phys_addr_t base, phys_addr_t size)594589{595595- unsigned long node = rmem->fdt_node;596590 int err = 0;597591 bool nomap;598592593593+ struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];594594+595595+ if (reserved_mem_count == total_reserved_mem_cnt) {596596+ pr_err("not enough space for all defined regions.\n");597597+ return;598598+ }599599+600600+ rmem->name = uname;601601+ rmem->base = base;602602+ rmem->size = size;603603+599604 nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;600605601601- err = __reserved_mem_init_node(rmem);602602- if (err != 0 && err != -ENOENT) {606606+ err = __reserved_mem_init_node(rmem, node);607607+ if (err != 0 && err != -ENODEV) {603608 pr_info("node %s compatible matching fail\n", rmem->name);609609+ rmem->name = NULL;610610+604611 if (nomap)605612 memblock_clear_nomap(rmem->base, rmem->size);606613 else607614 memblock_phys_free(rmem->base, rmem->size);615615+ return;608616 } else {609617 phys_addr_t end = rmem->base + rmem->size - 1;610618 bool reusable =···646594 reusable ? "reusable" : "non-reusable",647595 rmem->name ? rmem->name : "unknown");648596 }597597+598598+ reserved_mem_count++;649599}650600651601struct rmem_assigned_device {