1 /* 2 * Dynamic reconfiguration memory support 3 * 4 * Copyright 2017 IBM Corporation 5 * 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. 10 */ 11 12 #define pr_fmt(fmt) "drmem: " fmt 13 14 #include <linux/kernel.h> 15 #include <linux/of.h> 16 #include <linux/of_fdt.h> 17 #include <linux/memblock.h> 18 #include <asm/prom.h> 19 #include <asm/drmem.h> 20 21 static struct drmem_lmb_info __drmem_info; 22 struct drmem_lmb_info *drmem_info = &__drmem_info; 23 24 u64 drmem_lmb_memory_max(void) 25 { 26 struct drmem_lmb *last_lmb; 27 28 last_lmb = &drmem_info->lmbs[drmem_info->n_lmbs - 1]; 29 return last_lmb->base_addr + drmem_lmb_size(); 30 } 31 32 static u32 drmem_lmb_flags(struct drmem_lmb *lmb) 33 { 34 /* 35 * Return the value of the lmb flags field minus the reserved 36 * bit used internally for hotplug processing. 37 */ 38 return lmb->flags & ~DRMEM_LMB_RESERVED; 39 } 40 41 static struct property *clone_property(struct property *prop, u32 prop_sz) 42 { 43 struct property *new_prop; 44 45 new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); 46 if (!new_prop) 47 return NULL; 48 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); 54 kfree(new_prop); 55 return NULL; 56 } 57 58 new_prop->length = prop_sz; 59 #if defined(CONFIG_OF_DYNAMIC) 60 of_property_set_flag(new_prop, OF_DYNAMIC); 61 #endif 62 return new_prop; 63 } 64 65 static int drmem_update_dt_v1(struct device_node *memory, 66 struct property *prop) 67 { 68 struct property *new_prop; 69 struct of_drconf_cell_v1 *dr_cell; 70 struct drmem_lmb *lmb; 71 u32 *p; 72 73 new_prop = clone_property(prop, prop->length); 74 if (!new_prop) 75 return -1; 76 77 p = new_prop->value; 78 *p++ = cpu_to_be32(drmem_info->n_lmbs); 79 80 dr_cell = (struct of_drconf_cell_v1 *)p; 81 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)); 87 88 dr_cell++; 89 } 90 91 of_update_property(memory, new_prop); 92 return 0; 93 } 94 95 static void init_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell, 96 struct drmem_lmb *lmb) 97 { 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); 102 } 103 104 static int drmem_update_dt_v2(struct device_node *memory, 105 struct property *prop) 106 { 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; 111 u32 *p; 112 113 /* First pass, determine how many LMB sets are needed. */ 114 lmb_sets = 0; 115 prev_lmb = NULL; 116 for_each_drmem_lmb(lmb) { 117 if (!prev_lmb) { 118 prev_lmb = lmb; 119 lmb_sets++; 120 continue; 121 } 122 123 if (prev_lmb->aa_index != lmb->aa_index || 124 prev_lmb->flags != lmb->flags) 125 lmb_sets++; 126 127 prev_lmb = lmb; 128 } 129 130 prop_sz = lmb_sets * sizeof(*dr_cell) + sizeof(__be32); 131 new_prop = clone_property(prop, prop_sz); 132 if (!new_prop) 133 return -1; 134 135 p = new_prop->value; 136 *p++ = cpu_to_be32(lmb_sets); 137 138 dr_cell = (struct of_drconf_cell_v2 *)p; 139 140 /* Second pass, populate the LMB set data */ 141 prev_lmb = NULL; 142 seq_lmbs = 0; 143 for_each_drmem_lmb(lmb) { 144 if (prev_lmb == NULL) { 145 /* Start of first LMB set */ 146 prev_lmb = lmb; 147 init_drconf_v2_cell(dr_cell, lmb); 148 seq_lmbs++; 149 continue; 150 } 151 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); 156 dr_cell++; 157 158 init_drconf_v2_cell(dr_cell, lmb); 159 seq_lmbs = 1; 160 } else { 161 seq_lmbs++; 162 } 163 164 prev_lmb = lmb; 165 } 166 167 /* close out last LMB set */ 168 dr_cell->seq_lmbs = cpu_to_be32(seq_lmbs); 169 of_update_property(memory, new_prop); 170 return 0; 171 } 172 173 int drmem_update_dt(void) 174 { 175 struct device_node *memory; 176 struct property *prop; 177 int rc = -1; 178 179 memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); 180 if (!memory) 181 return -1; 182 183 prop = of_find_property(memory, "ibm,dynamic-memory", NULL); 184 if (prop) { 185 rc = drmem_update_dt_v1(memory, prop); 186 } else { 187 prop = of_find_property(memory, "ibm,dynamic-memory-v2", NULL); 188 if (prop) 189 rc = drmem_update_dt_v2(memory, prop); 190 } 191 192 of_node_put(memory); 193 return rc; 194 } 195 196 static void __init read_drconf_v1_cell(struct drmem_lmb *lmb, 197 const __be32 **prop) 198 { 199 const __be32 *p = *prop; 200 201 lmb->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p); 202 lmb->drc_index = of_read_number(p++, 1); 203 204 p++; /* skip reserved field */ 205 206 lmb->aa_index = of_read_number(p++, 1); 207 lmb->flags = of_read_number(p++, 1); 208 209 *prop = p; 210 } 211 212 static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm, 213 void (*func)(struct drmem_lmb *, const __be32 **)) 214 { 215 struct drmem_lmb lmb; 216 u32 i, n_lmbs; 217 218 n_lmbs = of_read_number(prop++, 1); 219 220 for (i = 0; i < n_lmbs; i++) { 221 read_drconf_v1_cell(&lmb, &prop); 222 func(&lmb, &usm); 223 } 224 } 225 226 static void __init read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell, 227 const __be32 **prop) 228 { 229 const __be32 *p = *prop; 230 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); 236 237 *prop = p; 238 } 239 240 static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm, 241 void (*func)(struct drmem_lmb *, const __be32 **)) 242 { 243 struct of_drconf_cell_v2 dr_cell; 244 struct drmem_lmb lmb; 245 u32 i, j, lmb_sets; 246 247 lmb_sets = of_read_number(prop++, 1); 248 249 for (i = 0; i < lmb_sets; i++) { 250 read_drconf_v2_cell(&dr_cell, &prop); 251 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(); 255 256 lmb.drc_index = dr_cell.drc_index; 257 dr_cell.drc_index++; 258 259 lmb.aa_index = dr_cell.aa_index; 260 lmb.flags = dr_cell.flags; 261 262 func(&lmb, &usm); 263 } 264 } 265 } 266 267 #ifdef CONFIG_PPC_PSERIES 268 void __init walk_drmem_lmbs_early(unsigned long node, 269 void (*func)(struct drmem_lmb *, const __be32 **)) 270 { 271 const __be32 *prop, *usm; 272 int len; 273 274 prop = of_get_flat_dt_prop(node, "ibm,lmb-size", &len); 275 if (!prop || len < dt_root_size_cells * sizeof(__be32)) 276 return; 277 278 drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop); 279 280 usm = of_get_flat_dt_prop(node, "linux,drconf-usable-memory", &len); 281 282 prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory", &len); 283 if (prop) { 284 __walk_drmem_v1_lmbs(prop, usm, func); 285 } else { 286 prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory-v2", 287 &len); 288 if (prop) 289 __walk_drmem_v2_lmbs(prop, usm, func); 290 } 291 292 memblock_dump_all(); 293 } 294 295 #endif 296 297 static int __init init_drmem_lmb_size(struct device_node *dn) 298 { 299 const __be32 *prop; 300 int len; 301 302 if (drmem_info->lmb_size) 303 return 0; 304 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"); 308 return -1; 309 } 310 311 drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop); 312 return 0; 313 } 314 315 /* 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) 319 */ 320 static const __be32 *of_get_usable_memory(struct device_node *dn) 321 { 322 const __be32 *prop; 323 u32 len; 324 325 prop = of_get_property(dn, "linux,drconf-usable-memory", &len); 326 if (!prop || len < sizeof(unsigned int)) 327 return NULL; 328 329 return prop; 330 } 331 332 void __init walk_drmem_lmbs(struct device_node *dn, 333 void (*func)(struct drmem_lmb *, const __be32 **)) 334 { 335 const __be32 *prop, *usm; 336 337 if (init_drmem_lmb_size(dn)) 338 return; 339 340 usm = of_get_usable_memory(dn); 341 342 prop = of_get_property(dn, "ibm,dynamic-memory", NULL); 343 if (prop) { 344 __walk_drmem_v1_lmbs(prop, usm, func); 345 } else { 346 prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL); 347 if (prop) 348 __walk_drmem_v2_lmbs(prop, usm, func); 349 } 350 } 351 352 static void __init init_drmem_v1_lmbs(const __be32 *prop) 353 { 354 struct drmem_lmb *lmb; 355 356 drmem_info->n_lmbs = of_read_number(prop++, 1); 357 358 drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb), 359 GFP_KERNEL); 360 if (!drmem_info->lmbs) 361 return; 362 363 for_each_drmem_lmb(lmb) 364 read_drconf_v1_cell(lmb, &prop); 365 } 366 367 static void __init init_drmem_v2_lmbs(const __be32 *prop) 368 { 369 struct drmem_lmb *lmb; 370 struct of_drconf_cell_v2 dr_cell; 371 const __be32 *p; 372 u32 i, j, lmb_sets; 373 int lmb_index; 374 375 lmb_sets = of_read_number(prop++, 1); 376 377 /* first pass, calculate the number of LMBs */ 378 p = prop; 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; 382 } 383 384 drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb), 385 GFP_KERNEL); 386 if (!drmem_info->lmbs) 387 return; 388 389 /* second pass, read in the LMB information */ 390 lmb_index = 0; 391 p = prop; 392 393 for (i = 0; i < lmb_sets; i++) { 394 read_drconf_v2_cell(&dr_cell, &p); 395 396 for (j = 0; j < dr_cell.seq_lmbs; j++) { 397 lmb = &drmem_info->lmbs[lmb_index++]; 398 399 lmb->base_addr = dr_cell.base_addr; 400 dr_cell.base_addr += drmem_info->lmb_size; 401 402 lmb->drc_index = dr_cell.drc_index; 403 dr_cell.drc_index++; 404 405 lmb->aa_index = dr_cell.aa_index; 406 lmb->flags = dr_cell.flags; 407 } 408 } 409 } 410 411 static int __init drmem_init(void) 412 { 413 struct device_node *dn; 414 const __be32 *prop; 415 416 dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); 417 if (!dn) { 418 pr_info("No dynamic reconfiguration memory found\n"); 419 return 0; 420 } 421 422 if (init_drmem_lmb_size(dn)) { 423 of_node_put(dn); 424 return 0; 425 } 426 427 prop = of_get_property(dn, "ibm,dynamic-memory", NULL); 428 if (prop) { 429 init_drmem_v1_lmbs(prop); 430 } else { 431 prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL); 432 if (prop) 433 init_drmem_v2_lmbs(prop); 434 } 435 436 of_node_put(dn); 437 return 0; 438 } 439 late_initcall(drmem_init); 440