2 * Dynamic reconfiguration memory support
4 * Copyright 2017 IBM Corporation
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #define pr_fmt(fmt) "drmem: " fmt
14 #include <linux/kernel.h>
16 #include <linux/of_fdt.h>
17 #include <linux/memblock.h>
19 #include <asm/drmem.h>
21 static struct drmem_lmb_info __drmem_info;
22 struct drmem_lmb_info *drmem_info = &__drmem_info;
24 u64 drmem_lmb_memory_max(void)
26 struct drmem_lmb *last_lmb;
28 last_lmb = &drmem_info->lmbs[drmem_info->n_lmbs - 1];
29 return last_lmb->base_addr + drmem_lmb_size();
32 static u32 drmem_lmb_flags(struct drmem_lmb *lmb)
35 * Return the value of the lmb flags field minus the reserved
36 * bit used internally for hotplug processing.
38 return lmb->flags & ~DRMEM_LMB_RESERVED;
41 static struct property *clone_property(struct property *prop, u32 prop_sz)
43 struct property *new_prop;
45 new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
49 new_prop->name = kstrdup(prop->name, GFP_KERNEL);
50 new_prop->value = kzalloc(prop_sz, GFP_KERNEL);
51 if (!new_prop->name || !new_prop->value) {
52 kfree(new_prop->name);
53 kfree(new_prop->value);
58 new_prop->length = prop_sz;
59 #if defined(CONFIG_OF_DYNAMIC)
60 of_property_set_flag(new_prop, OF_DYNAMIC);
65 static int drmem_update_dt_v1(struct device_node *memory,
66 struct property *prop)
68 struct property *new_prop;
69 struct of_drconf_cell_v1 *dr_cell;
70 struct drmem_lmb *lmb;
73 new_prop = clone_property(prop, prop->length);
78 *p++ = cpu_to_be32(drmem_info->n_lmbs);
80 dr_cell = (struct of_drconf_cell_v1 *)p;
82 for_each_drmem_lmb(lmb) {
83 dr_cell->base_addr = cpu_to_be64(lmb->base_addr);
84 dr_cell->drc_index = cpu_to_be32(lmb->drc_index);
85 dr_cell->aa_index = cpu_to_be32(lmb->aa_index);
86 dr_cell->flags = cpu_to_be32(drmem_lmb_flags(lmb));
91 of_update_property(memory, new_prop);
95 static void init_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell,
96 struct drmem_lmb *lmb)
98 dr_cell->base_addr = cpu_to_be64(lmb->base_addr);
99 dr_cell->drc_index = cpu_to_be32(lmb->drc_index);
100 dr_cell->aa_index = cpu_to_be32(lmb->aa_index);
101 dr_cell->flags = cpu_to_be32(lmb->flags);
104 static int drmem_update_dt_v2(struct device_node *memory,
105 struct property *prop)
107 struct property *new_prop;
108 struct of_drconf_cell_v2 *dr_cell;
109 struct drmem_lmb *lmb, *prev_lmb;
110 u32 lmb_sets, prop_sz, seq_lmbs;
113 /* First pass, determine how many LMB sets are needed. */
116 for_each_drmem_lmb(lmb) {
123 if (prev_lmb->aa_index != lmb->aa_index ||
124 prev_lmb->flags != lmb->flags)
130 prop_sz = lmb_sets * sizeof(*dr_cell) + sizeof(__be32);
131 new_prop = clone_property(prop, prop_sz);
136 *p++ = cpu_to_be32(lmb_sets);
138 dr_cell = (struct of_drconf_cell_v2 *)p;
140 /* Second pass, populate the LMB set data */
143 for_each_drmem_lmb(lmb) {
144 if (prev_lmb == NULL) {
145 /* Start of first LMB set */
147 init_drconf_v2_cell(dr_cell, lmb);
152 if (prev_lmb->aa_index != lmb->aa_index ||
153 prev_lmb->flags != lmb->flags) {
154 /* end of one set, start of another */
155 dr_cell->seq_lmbs = cpu_to_be32(seq_lmbs);
158 init_drconf_v2_cell(dr_cell, lmb);
167 /* close out last LMB set */
168 dr_cell->seq_lmbs = cpu_to_be32(seq_lmbs);
169 of_update_property(memory, new_prop);
173 int drmem_update_dt(void)
175 struct device_node *memory;
176 struct property *prop;
179 memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
183 prop = of_find_property(memory, "ibm,dynamic-memory", NULL);
185 rc = drmem_update_dt_v1(memory, prop);
187 prop = of_find_property(memory, "ibm,dynamic-memory-v2", NULL);
189 rc = drmem_update_dt_v2(memory, prop);
196 static void __init read_drconf_v1_cell(struct drmem_lmb *lmb,
199 const __be32 *p = *prop;
201 lmb->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p);
202 lmb->drc_index = of_read_number(p++, 1);
204 p++; /* skip reserved field */
206 lmb->aa_index = of_read_number(p++, 1);
207 lmb->flags = of_read_number(p++, 1);
212 static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm,
213 void (*func)(struct drmem_lmb *, const __be32 **))
215 struct drmem_lmb lmb;
218 n_lmbs = of_read_number(prop++, 1);
220 for (i = 0; i < n_lmbs; i++) {
221 read_drconf_v1_cell(&lmb, &prop);
226 static void __init read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell,
229 const __be32 *p = *prop;
231 dr_cell->seq_lmbs = of_read_number(p++, 1);
232 dr_cell->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p);
233 dr_cell->drc_index = of_read_number(p++, 1);
234 dr_cell->aa_index = of_read_number(p++, 1);
235 dr_cell->flags = of_read_number(p++, 1);
240 static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm,
241 void (*func)(struct drmem_lmb *, const __be32 **))
243 struct of_drconf_cell_v2 dr_cell;
244 struct drmem_lmb lmb;
247 lmb_sets = of_read_number(prop++, 1);
249 for (i = 0; i < lmb_sets; i++) {
250 read_drconf_v2_cell(&dr_cell, &prop);
252 for (j = 0; j < dr_cell.seq_lmbs; j++) {
253 lmb.base_addr = dr_cell.base_addr;
254 dr_cell.base_addr += drmem_lmb_size();
256 lmb.drc_index = dr_cell.drc_index;
259 lmb.aa_index = dr_cell.aa_index;
260 lmb.flags = dr_cell.flags;
267 #ifdef CONFIG_PPC_PSERIES
268 void __init walk_drmem_lmbs_early(unsigned long node,
269 void (*func)(struct drmem_lmb *, const __be32 **))
271 const __be32 *prop, *usm;
274 prop = of_get_flat_dt_prop(node, "ibm,lmb-size", &len);
275 if (!prop || len < dt_root_size_cells * sizeof(__be32))
278 drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop);
280 usm = of_get_flat_dt_prop(node, "linux,drconf-usable-memory", &len);
282 prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory", &len);
284 __walk_drmem_v1_lmbs(prop, usm, func);
286 prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory-v2",
289 __walk_drmem_v2_lmbs(prop, usm, func);
297 static int __init init_drmem_lmb_size(struct device_node *dn)
302 if (drmem_info->lmb_size)
305 prop = of_get_property(dn, "ibm,lmb-size", &len);
306 if (!prop || len < dt_root_size_cells * sizeof(__be32)) {
307 pr_info("Could not determine LMB size\n");
311 drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop);
316 * Returns the property linux,drconf-usable-memory if
317 * it exists (the property exists only in kexec/kdump kernels,
318 * added by kexec-tools)
320 static const __be32 *of_get_usable_memory(struct device_node *dn)
325 prop = of_get_property(dn, "linux,drconf-usable-memory", &len);
326 if (!prop || len < sizeof(unsigned int))
332 void __init walk_drmem_lmbs(struct device_node *dn,
333 void (*func)(struct drmem_lmb *, const __be32 **))
335 const __be32 *prop, *usm;
337 if (init_drmem_lmb_size(dn))
340 usm = of_get_usable_memory(dn);
342 prop = of_get_property(dn, "ibm,dynamic-memory", NULL);
344 __walk_drmem_v1_lmbs(prop, usm, func);
346 prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL);
348 __walk_drmem_v2_lmbs(prop, usm, func);
352 static void __init init_drmem_v1_lmbs(const __be32 *prop)
354 struct drmem_lmb *lmb;
356 drmem_info->n_lmbs = of_read_number(prop++, 1);
358 drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb),
360 if (!drmem_info->lmbs)
363 for_each_drmem_lmb(lmb)
364 read_drconf_v1_cell(lmb, &prop);
367 static void __init init_drmem_v2_lmbs(const __be32 *prop)
369 struct drmem_lmb *lmb;
370 struct of_drconf_cell_v2 dr_cell;
375 lmb_sets = of_read_number(prop++, 1);
377 /* first pass, calculate the number of LMBs */
379 for (i = 0; i < lmb_sets; i++) {
380 read_drconf_v2_cell(&dr_cell, &p);
381 drmem_info->n_lmbs += dr_cell.seq_lmbs;
384 drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb),
386 if (!drmem_info->lmbs)
389 /* second pass, read in the LMB information */
393 for (i = 0; i < lmb_sets; i++) {
394 read_drconf_v2_cell(&dr_cell, &p);
396 for (j = 0; j < dr_cell.seq_lmbs; j++) {
397 lmb = &drmem_info->lmbs[lmb_index++];
399 lmb->base_addr = dr_cell.base_addr;
400 dr_cell.base_addr += drmem_info->lmb_size;
402 lmb->drc_index = dr_cell.drc_index;
405 lmb->aa_index = dr_cell.aa_index;
406 lmb->flags = dr_cell.flags;
411 static int __init drmem_init(void)
413 struct device_node *dn;
416 dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
418 pr_info("No dynamic reconfiguration memory found\n");
422 if (init_drmem_lmb_size(dn)) {
427 prop = of_get_property(dn, "ibm,dynamic-memory", NULL);
429 init_drmem_v1_lmbs(prop);
431 prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL);
433 init_drmem_v2_lmbs(prop);
439 late_initcall(drmem_init);