staticbool find_aa_index(struct device_node *dr_node, struct property *ala_prop, const u32 *lmb_assoc, u32 *aa_index)
{
__be32 *assoc_arrays;
u32 new_prop_size; struct property *new_prop; int aa_arrays, aa_array_entries, aa_array_sz; int i, index;
/* * The ibm,associativity-lookup-arrays property is defined to be * a 32-bit value specifying the number of associativity arrays * followed by a 32-bitvalue specifying the number of entries per * array, followed by the associativity arrays.
*/
assoc_arrays = ala_prop->value;
/* increment the number of entries in the lookup array */
assoc_arrays[0] = cpu_to_be32(aa_arrays + 1);
/* copy the new associativity into the lookup array */
index = aa_arrays * aa_array_entries + 2;
memcpy(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz);
of_update_property(dr_node, new_prop);
/* * The associativity lookup array index for this lmb is * number of entries - 1 since we added its associativity * to the end of the lookup array.
*/
*aa_index = be32_to_cpu(assoc_arrays[0]) - 1; returntrue;
}
#ifdef CONFIG_FA_DUMP /* * Don't hot-remove memory that falls in fadump boot memory area * and memory that is reserved for capturing old kernel memory.
*/ if (is_fadump_memory_area(lmb->base_addr, memory_block_size_bytes())) returnfalse; #endif /* device_offline() will determine if we can actually remove this lmb */ returntrue;
}
staticint dlpar_add_lmb(struct drmem_lmb *);
staticint dlpar_remove_lmb(struct drmem_lmb *lmb)
{ struct memory_block *mem_block; int rc;
if (!lmb_is_removable(lmb)) return -EINVAL;
mem_block = lmb_to_memblock(lmb); if (mem_block == NULL) return -EINVAL;
rc = dlpar_offline_lmb(lmb); if (rc) {
put_device(&mem_block->dev); return rc;
}
staticint dlpar_memory_remove_by_count(u32 lmbs_to_remove)
{ struct drmem_lmb *lmb; int lmbs_reserved = 0; int lmbs_available = 0; int rc;
pr_info("Attempting to hot-remove %d LMB(s)\n", lmbs_to_remove);
if (lmbs_to_remove == 0) return -EINVAL;
/* Validate that there are enough LMBs to satisfy the request */
for_each_drmem_lmb(lmb) { if (lmb_is_removable(lmb))
lmbs_available++;
if (lmbs_available == lmbs_to_remove) break;
}
if (lmbs_available < lmbs_to_remove) {
pr_info("Not enough LMBs available (%d of %d) to satisfy request\n",
lmbs_available, lmbs_to_remove); return -EINVAL;
}
for_each_drmem_lmb(lmb) {
rc = dlpar_remove_lmb(lmb); if (rc) continue;
/* Mark this lmb so we can add it later if all of the * requested LMBs cannot be removed.
*/
drmem_mark_lmb_reserved(lmb);
lmbs_reserved++; if (lmbs_reserved == lmbs_to_remove) break;
}
staticint dlpar_memory_remove_by_index(u32 drc_index)
{ struct drmem_lmb *lmb; int lmb_found; int rc;
pr_debug("Attempting to hot-remove LMB, drc index %x\n", drc_index);
lmb_found = 0;
for_each_drmem_lmb(lmb) { if (lmb->drc_index == drc_index) {
lmb_found = 1;
rc = dlpar_remove_lmb(lmb); if (!rc)
dlpar_release_drc(lmb->drc_index);
break;
}
}
if (!lmb_found) {
pr_debug("Failed to look up LMB for drc index %x\n", drc_index);
rc = -EINVAL;
} elseif (rc) {
pr_debug("Failed to hot-remove memory at %llx\n",
lmb->base_addr);
} else {
pr_debug("Memory at %llx was hot-removed\n", lmb->base_addr);
}
pr_info("Attempting to hot-remove %u LMB(s) at %x\n",
lmbs_to_remove, drc_index);
if (lmbs_to_remove == 0) return -EINVAL;
rc = get_lmb_range(drc_index, lmbs_to_remove, &start_lmb, &end_lmb); if (rc) return -EINVAL;
/* * Validate that all LMBs in range are not reserved. Note that it * is ok if they are !ASSIGNED since our goal here is to remove the * LMB range, regardless of whether some LMBs were already removed * by any other reason. * * This is a contrast to what is done in remove_by_count() where we * check for both RESERVED and !ASSIGNED (via lmb_is_removable()), * because we want to remove a fixed amount of LMBs in that function.
*/
for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) { if (lmb->flags & DRCONF_MEM_RESERVED) {
pr_err("Memory at %llx (drc index %x) is reserved\n",
lmb->base_addr, lmb->drc_index); return -EINVAL;
}
}
for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) { /* * dlpar_remove_lmb() will error out if the LMB is already * !ASSIGNED, but this case is a no-op for us.
*/ if (!(lmb->flags & DRCONF_MEM_ASSIGNED)) continue;
rc = dlpar_remove_lmb(lmb); if (rc) break;
drmem_mark_lmb_reserved(lmb);
}
if (rc) {
pr_err("Memory indexed-count-remove failed, adding any removed LMBs\n");
for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) { if (!drmem_lmb_reserved(lmb)) continue;
/* * Setting the isolation state of an UNISOLATED/CONFIGURED * device to UNISOLATE is a no-op, but the hypervisor can * use it as a hint that the LMB removal failed.
*/
dlpar_unisolate_drc(lmb->drc_index);
rc = dlpar_add_lmb(lmb); if (rc)
pr_err("Failed to add LMB, drc index %x\n",
lmb->drc_index);
staticint dlpar_add_lmb(struct drmem_lmb *lmb)
{ unsignedlong block_sz; int nid, rc;
if (lmb->flags & DRCONF_MEM_ASSIGNED) return -EINVAL;
rc = update_lmb_associativity_index(lmb); if (rc) {
dlpar_release_drc(lmb->drc_index);
pr_err("Failed to configure LMB 0x%x\n", lmb->drc_index); return rc;
}
block_sz = memory_block_size_bytes();
/* Find the node id for this LMB. Fake one if necessary. */
nid = of_drconf_to_nid_single(lmb); if (nid < 0 || !node_possible(nid))
nid = first_online_node;
/* Add the memory */
rc = __add_memory(nid, lmb->base_addr, block_sz, MHP_MEMMAP_ON_MEMORY); if (rc) {
pr_err("Failed to add LMB 0x%x to node %u", lmb->drc_index, nid);
invalidate_lmb_associativity_index(lmb); return rc;
}
rc = dlpar_online_lmb(lmb); if (rc) {
pr_err("Failed to online LMB 0x%x on node %u\n", lmb->drc_index, nid);
__remove_memory(lmb->base_addr, block_sz);
invalidate_lmb_associativity_index(lmb);
} else {
lmb->flags |= DRCONF_MEM_ASSIGNED;
}
return rc;
}
staticint dlpar_memory_add_by_count(u32 lmbs_to_add)
{ struct drmem_lmb *lmb; int lmbs_available = 0; int lmbs_reserved = 0; int rc;
pr_info("Attempting to hot-add %d LMB(s)\n", lmbs_to_add);
if (lmbs_to_add == 0) return -EINVAL;
/* Validate that there are enough LMBs to satisfy the request */
for_each_drmem_lmb(lmb) { if (lmb->flags & DRCONF_MEM_RESERVED) continue;
if (!(lmb->flags & DRCONF_MEM_ASSIGNED))
lmbs_available++;
if (lmbs_available == lmbs_to_add) break;
}
if (lmbs_available < lmbs_to_add) return -EINVAL;
for_each_drmem_lmb(lmb) { if (lmb->flags & DRCONF_MEM_ASSIGNED) continue;
rc = dlpar_acquire_drc(lmb->drc_index); if (rc) continue;
rc = dlpar_add_lmb(lmb); if (rc) {
dlpar_release_drc(lmb->drc_index); continue;
}
/* Mark this lmb so we can remove it later if all of the * requested LMBs cannot be added.
*/
drmem_mark_lmb_reserved(lmb);
lmbs_reserved++; if (lmbs_reserved == lmbs_to_add) break;
}
if (lmbs_reserved != lmbs_to_add) {
pr_err("Memory hot-add failed, removing any added LMBs\n");
for_each_drmem_lmb(lmb) { if (!drmem_lmb_reserved(lmb)) continue;
rc = dlpar_remove_lmb(lmb); if (rc)
pr_err("Failed to remove LMB, drc index %x\n",
lmb->drc_index); else
dlpar_release_drc(lmb->drc_index);
if (lmbs_reserved == 0) break;
}
rc = -EINVAL;
} else {
for_each_drmem_lmb(lmb) { if (!drmem_lmb_reserved(lmb)) continue;
pr_debug("Memory at %llx (drc index %x) was hot-added\n",
lmb->base_addr, lmb->drc_index);
drmem_remove_lmb_reservation(lmb);
lmbs_reserved--;
if (lmbs_reserved == 0) break;
}
rc = 0;
}
return rc;
}
staticint dlpar_memory_add_by_index(u32 drc_index)
{ struct drmem_lmb *lmb; int rc, lmb_found;
pr_info("Attempting to hot-add LMB, drc index %x\n", drc_index);
lmb_found = 0;
for_each_drmem_lmb(lmb) { if (lmb->drc_index == drc_index) {
lmb_found = 1;
rc = dlpar_acquire_drc(lmb->drc_index); if (!rc) {
rc = dlpar_add_lmb(lmb); if (rc)
dlpar_release_drc(lmb->drc_index);
}
break;
}
}
if (!lmb_found)
rc = -EINVAL;
if (rc)
pr_info("Failed to hot-add memory, drc index %x\n", drc_index); else
pr_info("Memory at %llx (drc index %x) was hot-added\n",
lmb->base_addr, drc_index);
pr_info("Attempting to hot-add %u LMB(s) at index %x\n",
lmbs_to_add, drc_index);
if (lmbs_to_add == 0) return -EINVAL;
rc = get_lmb_range(drc_index, lmbs_to_add, &start_lmb, &end_lmb); if (rc) return -EINVAL;
/* Validate that the LMBs in this range are not reserved */
for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) { /* Fail immediately if the whole range can't be hot-added */ if (lmb->flags & DRCONF_MEM_RESERVED) {
pr_err("Memory at %llx (drc index %x) is reserved\n",
lmb->base_addr, lmb->drc_index); return -EINVAL;
}
}
for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) { if (lmb->flags & DRCONF_MEM_ASSIGNED) continue;
rc = dlpar_acquire_drc(lmb->drc_index); if (rc) break;
rc = dlpar_add_lmb(lmb); if (rc) {
dlpar_release_drc(lmb->drc_index); break;
}
drmem_mark_lmb_reserved(lmb);
}
if (rc) {
pr_err("Memory indexed-count-add failed, removing any added LMBs\n");
for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) { if (!drmem_lmb_reserved(lmb)) continue;
rc = dlpar_remove_lmb(lmb); if (rc)
pr_err("Failed to remove LMB, drc index %x\n",
lmb->drc_index); else
dlpar_release_drc(lmb->drc_index);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.