powerpc/devtree: Parse new DRC mem/cpu/dev device tree elements
Subsystems (4)
RFC v2 1/1 powerpc/devtree: Parse new DRC mem/cpu/dev device tree elements
Several properties in the DRC device tree format are replaced by more compact representations to allow, for example, for the encoding of vast amounts of memory, and or reduced duplication of information in related data structures.
"ibm,drc-info": This property, when present, replaces the following four properties: “ibm,drc-indexes”, “ibm,drc-names”, “ibm,drc-types” and “ibm,drc-power-domains”. This property is defined for all dynamically reconfigurable platform nodes. The "ibm,drc-info" elements are intended to provide a more compact representation, and reduce some search overhead.
"ibm,dynamic-memory-v2": This property replaces the "ibm,dynamic-memory" node representation within the "ibm,dynamic-reconfiguration-memory" property. This element format is intended to provide a more compact representation of memory, especially, for systems with massive amounts of RAM.
"ibm,architecture.vec": Bit flags are added to this data structure by the front end processor to inform the kernel as to whether to expect the changes to one or both of the device tree structures "ibm,drc-info" and "ibm,dynamic-memory-v2".
The new element structures, "ibm,dynamic-memory-v2" and "ibm,drc-info", should completely replace the previously used structures at execution.
---
arch/powerpc/include/asm/firmware.h +4 -1
@@ -51,6 +51,8 @@#define FW_FEATURE_BEST_ENERGY ASM_CONST(0x0000000080000000)#define FW_FEATURE_TYPE1_AFFINITY ASM_CONST(0x0000000100000000)#define FW_FEATURE_PRRN ASM_CONST(0x0000000200000000) +#define FW_FEATURE_RPS_DM2 ASM_CONST(0x0000000400000000) +#define FW_FEATURE_RPS_DRC_INFO ASM_CONST(0x0000000800000000)#ifndef __ASSEMBLY__
@@ -66,7 +68,8 @@ enum {FW_FEATURE_MULTITCE |FW_FEATURE_SPLPAR |FW_FEATURE_LPAR |FW_FEATURE_CMO |FW_FEATURE_VPHN |FW_FEATURE_XCMO |FW_FEATURE_SET_MODE |FW_FEATURE_BEST_ENERGY | -FW_FEATURE_TYPE1_AFFINITY |FW_FEATURE_PRRN , +FW_FEATURE_TYPE1_AFFINITY |FW_FEATURE_PRRN | +FW_FEATURE_RPS_DM2 |FW_FEATURE_RPS_DRC_INFO ,FW_FEATURE_PSERIES_ALWAYS =0 ,FW_FEATURE_POWERNV_POSSIBLE =FW_FEATURE_OPAL , FW_FEATURE_POWERNV_ALWAYS = 0,
arch/powerpc/include/asm/prom.h +35 -5
@@ -81,8 +81,9 @@ extern void of_instantiate_rtc(void);extern int of_get_ibm_chip_id (struct device_node *np);/* The of_drconf_cell struct defines the layout of the LMB array -* specified in the device tree property -* ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory +* specified in the device tree properties, +* ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory +* ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory-v2 */ struct of_drconf_cell {u64 base_addr;
@@ -92,9 +93,36 @@ struct of_drconf_cell {u32 flags; }; -#define DRCONF_MEM_ASSIGNED 0x00000008 -#define DRCONF_MEM_AI_INVALID 0x00000040 -#define DRCONF_MEM_RESERVED 0x00000080 +struct of_drconf_cell_v2 { +u32 num_seq_lmbs; +u64 base_addr; +u32 drc_index; +u32 aa_index; +u32 flags; +}; + +#define DRCONF_MEM_PRESERVED 0x00000001 +#define DRCONF_MEM_PRESERVABLE 0x00000002 +#define DRCONF_MEM_PRESERVED_STATE 0x00000004 +#define DRCONF_MEM_ASSIGNED 0x00000008 +#define DRCONF_MEM_NO_H_MIGRATE_DATA 0x00000010 +#define DRCONF_MEM_DRC_INVALID 0x00000020 +#define DRCONF_MEM_AI_INVALID 0x00000040 +#define DRCONF_MEM_RESERVED 0x00000080 +#define DRCONF_MEM_RESERVED_SW 0x80000000 + +/* +* Set of dynamic DLPAR memory function operations +*/ +struct dlpar_memory_ops { +struct property * (*clone_drconf_property)(struct device_node *dn); +int (*add_by_count)(u32 lmbs_to_add,struct property **prop); +int (*add_by_index)(u32 lmbs_to_add,struct property **prop); +int (*remove_by_count)(u32 lmbs_to_add,struct property **prop); +int (*remove_by_index)(u32 lmbs_to_add,struct property **prop); +void (*update_drconf_property)(struct device_node *dn, +struct property *prop); +};/* * There are two methods for telling firmware what our capabilities are.
@@ -155,6 +183,8 @@ struct of_drconf_cell {#define OV5_PFO_HW_842 0x0E40/* PFO Compression Accelerator */ #define OV5_PFO_HW_ENCR 0x0E20/* PFO Encryption Accelerator */ #define OV5_SUB_PROCESSORS 0x0F01/* 1,2,or 4 Sub-Processors supported */ +#define OV5_RPS_DM2 0x1601/* Redef Prop Structures: dyn-mem-v2 */ +#define OV5_RPS_DRC_INFO 0x1602/* Redef Prop Structures: drc-info */ /* Option Vector 6: IBM PAPR hints */ #define OV6_LINUX 0x02/* Linux is our OS */
arch/powerpc/kernel/prom.c +141 -24
213 lines not on this page · raw message
arch/powerpc/kernel/prom_init.c +5 -1
@@ -694,7 +694,7 @@ unsigned char ibm_architecture_vec[] = {OV4_MIN_ENT_CAP ,/* minimum VP entitled capacity */ /* option vector 5: PAPR/OF options */ -VECTOR_LENGTH (18 ),/* length */ +VECTOR_LENGTH (22 ),/* length */ 0 ,/* don't ignore, don't halt */ OV5_FEAT (OV5_LPAR ) |OV5_FEAT (OV5_SPLPAR ) |OV5_FEAT (OV5_LARGE_PAGES ) | OV5_FEAT(OV5_DRCONF_MEMORY) | OV5_FEAT(OV5_DONATE_DEDICATE_CPU) |
@@ -727,6 +727,10 @@ unsigned char ibm_architecture_vec[] = {OV5_FEAT (OV5_PFO_HW_RNG ) |OV5_FEAT (OV5_PFO_HW_ENCR ) |OV5_FEAT (OV5_PFO_HW_842 ),OV5_FEAT (OV5_SUB_PROCESSORS ), +0 , +0 , +0 , +OV5_FEAT (OV5_RPS_DM2 ) |OV5_FEAT (OV5_RPS_DRC_INFO ),/* option vector 6: IBM PAPR hints */ VECTOR_LENGTH(3), /* length */
arch/powerpc/mm/numa.c +1 -1
@@ -389,7 +389,7 @@ static unsigned long read_n_cells(int n, const __be32 **buf)/* * Read the next memblock list entry from the ibm,dynamic-memory property -* and return the information in the provided of_drconf_cell structure. +* and return the information in the provided of_drconf_cell/series structure. */ static void read_drconf_cell(struct of_drconf_cell *drmem, const
__be32 **cellp)
{
@@ -407,30 +407,77 @@ static void read_drconf_cell(struct of_drconf_cell *drmem, const __be32 **cellp)
}
/*
- * Retrieve and validate the ibm,dynamic-memory property of the device tree.
+ * Read the next memblock set entry from the ibm,dynamic-memory-v2 property
+ * and return the information in the provided of_drconf_cell_v2 structure.
+ */
+static void read_drconf_cell_v2(struct of_drconf_cell_v2 *drmem,
+ const __be32 **cellp)
+{
+ const __be32 *cp;
+
+ cp = *cellp;
+ drmem->num_seq_lmbs = of_read_number(&cp[0], 1);
+ cp++;
+
+ *cellp = cp;
+ drmem->base_addr = read_n_cells(n_mem_addr_cells, cellp);
+
+ cp = *cellp;
+ drmem->drc_index = of_read_number(&cp[0], 1);
+ drmem->aa_index = of_read_number(&cp[1], 1);
+ drmem->flags = of_read_number(&cp[2], 1);
+
+ *cellp = cp + 3;
+}
+
+/*
+ * Retrieve and validate the ibm,dynamic-memory[-v2] property of the
+ * device tree.
*
* The layout of the ibm,dynamic-memory property is a number N of memblock
* list entries followed by N memblock list entries. Each memblock
list entry
* contains information as laid out in the of_drconf_cell struct above.
+ *
+ * The layout of the ibm,dynamic-memory-v2 property is a number N of memblock
+ * list entries.
*/
static int of_get_drconf_memory(struct device_node *memory, const__be32 **dm)
{
const __be32 *prop;
u32 len, entries;
- prop = of_get_property(memory, "ibm,dynamic-memory", &len);
- if (!prop || len < sizeof(unsigned int))
- return 0;
+ if (firmware_has_feature(FW_FEATURE_RPS_DM2)) {
+ prop = of_get_property(memory, "ibm,dynamic-memory-v2", &len);
+ if (!prop || len < sizeof(unsigned int))
+ return 0;
- entries = of_read_number(prop++, 1);
+ entries = of_read_number(prop++, 1);
- /* Now that we know the number of entries, revalidate the size
- * of the property read in to ensure we have everything
- */
- if (len < (entries * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int))
- return 0;
+ /* Now that we know the number of set entries, revalidate the
+ * size of the property read in to ensure we have everything.
+ */
+ if (len < (entries * (n_mem_addr_cells + 4) + 1) *
+ sizeof(unsigned int))
+ return 0;
+
+ *dm = prop;
+ } else {
+ prop = of_get_property(memory, "ibm,dynamic-memory", &len);
+ if (!prop || len < sizeof(unsigned int))
+ return 0;
+
+ entries = of_read_number(prop++, 1);
+
+ /* Now that we know the number of entries, revalidate the size
+ * of the property read in to ensure we have everything
+ */
+ if (len < (entries * (n_mem_addr_cells + 4) + 1) *
+ sizeof(unsigned int))
+ return 0;
+
+ *dm = prop;
+ }
- *dm = prop;
return entries;
}
@@ -459,7 +506,7 @@ struct assoc_arrays {
/*
* Retrieve and validate the list of associativity arrays for drconf
* memory from the ibm,associativity-lookup-arrays property of the
- * device tree..
+ * device tree.
*
* The layout of the ibm,associativity-lookup-arrays property is a
number N
* indicating the number of associativity arrays, followed by a number M
@@ -493,7 +540,7 @@ static int of_get_assoc_arrays(struct device_node *memory,
* This is like of_node_to_nid_single() for memory represented in the
* ibm,dynamic-reconfiguration-memory node.
*/
-static int of_drconf_to_nid_single(struct of_drconf_cell *drmem, +static int of_drconf_to_nid_single(u32 drmem_flags, u32 drmem_aa_index,
struct assoc_arrays *aa)
{
int default_nid = 0;
@@ -501,16 +548,16 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem,
int index;
if (min_common_depth > 0 && min_common_depth <= aa->array_sz &&
- !(drmem->flags & DRCONF_MEM_AI_INVALID) &&
- drmem->aa_index < aa->n_arrays) {
- index = drmem->aa_index * aa->array_sz + min_common_depth - 1;
+ !(drmem_flags & DRCONF_MEM_AI_INVALID) &&
+ drmem_aa_index < aa->n_arrays) {
+ index = drmem_aa_index * aa->array_sz + min_common_depth - 1;
nid = of_read_number(&aa->arrays[index], 1);
if (nid == 0xffff || nid >= MAX_NUMNODES)
nid = default_nid;
if (nid > 0) {
- index = drmem->aa_index * aa->array_sz;
+ index = drmem_aa_index * aa->array_sz;
initialize_distance_lookup_table(nid,
&aa->arrays[index]);
}
@@ -653,7 +700,93 @@ static inline int __init read_usm_ranges(const __be32 **usm)
* Extract NUMA information from the ibm,dynamic-reconfiguration-memory
* node. This assumes n_mem_{addr,size}_cells have been set.
*/
-static void __init parse_drconf_memory(struct device_node *memory) +static void __init parse_drconf_memory_v2(struct device_node *memory) +{
+ const __be32 *uninitialized_var(dm), *usm;
+ unsigned int n, rc, ranges, is_kexec_kdump = 0;
+ unsigned long lmb_size, base, size, sz;
+ int nid;
+ struct assoc_arrays aa = { .arrays = NULL };
+ const __be32 *prop, *p;
+ u32 len;
+
+ prop = of_get_property(memory, "ibm,dynamic-memory-v2", &len);
+ if (!prop)
+ return;
+ p = prop;
+
+ n = of_get_drconf_memory(memory, &dm); /* Num sets */
+ if (!n)
+ return;
+
+ lmb_size = of_get_lmb_size(memory);
+ if (!lmb_size)
+ return;
+
+ rc = of_get_assoc_arrays(memory, &aa);
+ if (rc)
+ return;
+
+ for (; n != 0; n--) {
+ struct of_drconf_cell_v2 drmem;
+
+ /* Get the current LMB set */
+ read_drconf_cell_v2(&drmem, &dm);
+ base = drmem.base_addr;
+
+ /* Check if this is a kexec/kdump kernel */
+ usm = of_get_usable_memory(memory);
+ if (usm != NULL)
+ is_kexec_kdump = 1;
+
+ /* Skip this block if the reserved bit is set in
+ * flags (0x80) or if the block is not assigned
+ * to this partition (0x8)
+ */
+ if ((drmem.flags & DRCONF_MEM_RESERVED)
+ || !(drmem.flags & DRCONF_MEM_ASSIGNED))
+ continue;
+
+ for (; drmem.num_seq_lmbs != 0; --drmem.num_seq_lmbs) {
+ size = lmb_size;
+ ranges = 1;
+
+ if (is_kexec_kdump) {
+ ranges = read_usm_ranges(&usm);
+ if (!ranges)
+ /* there are no (base, size) duple
+ */
+ continue;
+ }
+ do {
+ if (is_kexec_kdump) {
+ base = read_n_cells(
+ n_mem_addr_cells,
+ &usm);
+ size = read_n_cells(
+ n_mem_size_cells,
+ &usm);
+ }
+ nid = of_drconf_to_nid_single(
+ drmem.flags,
+ drmem.aa_index, &aa);
+ fake_numa_create_new_node(
+ ((base + size) >> PAGE_SHIFT),
+ &nid);
+ node_set_online(nid);
+ sz = numa_enforce_memory_limit(base,
+ size);
+ if (sz)
+ memblock_set_node(base, sz,
+ &memblock.memory, nid);
+ } while (--ranges);
+
+ base += sz;
+ }
+ }
+}
+
+static void __init parse_drconf_memory_v1(struct device_node *memory)
{
const __be32 *uninitialized_var(dm), *usm;
unsigned int n, rc, ranges, is_kexec_kdump = 0;
@@ -673,7 +806,7 @@ static void __init parse_drconf_memory(struct device_node *memory)
if (rc)
return;
- /* check if this is a kexec/kdump kernel */
+ /* Check if this is a kexec/kdump kernel */
usm = of_get_usable_memory(memory);
if (usm != NULL)
is_kexec_kdump = 1;
@@ -683,8 +816,10 @@ static void __init parse_drconf_memory(struct device_node *memory)
read_drconf_cell(&drmem, &dm);
- /* skip this block if the reserved bit is set in flags (0x80)
- or if the block is not assigned to this partition (0x8) */
+ /* skip this block if the reserved bit is set in
+ * flags (0x80) or if the block is not assigned
+ * to this partition (0x8)
+ */
if ((drmem.flags & DRCONF_MEM_RESERVED)
|| !(drmem.flags & DRCONF_MEM_ASSIGNED))
continue;
@@ -695,27 +830,40 @@ static void __init parse_drconf_memory(struct device_node *memory)
if (is_kexec_kdump) {
ranges = read_usm_ranges(&usm);
- if (!ranges) /* there are no (base, size) duple */
+ if (!ranges)
+ /* there are no (base, size) duple */
continue;
}
do {
if (is_kexec_kdump) {
- base = read_n_cells(n_mem_addr_cells, &usm);
- size = read_n_cells(n_mem_size_cells, &usm);
+ base = read_n_cells(n_mem_addr_cells,
+ &usm);
+ size = read_n_cells(n_mem_size_cells,
+ &usm);
}
- nid = of_drconf_to_nid_single(&drmem, &aa);
+ nid = of_drconf_to_nid_single(drmem.flags,
+ drmem.aa_index,
+ &aa);
fake_numa_create_new_node(
((base + size) >> PAGE_SHIFT),
- &nid);
+ &nid);
node_set_online(nid);
sz = numa_enforce_memory_limit(base, size); if (sz)
memblock_set_node(base, sz,
- &memblock.memory, nid);
+ &memblock.memory, nid);
} while (--ranges);
}
}
+static void __init parse_drconf_memory(struct device_node *memory)
+{
+ if (firmware_has_feature(FW_FEATURE_RPS_DM2))
+ parse_drconf_memory_v2(memory);
+ else
+ parse_drconf_memory_v1(memory);
+}
+
static int __init parse_numa_properties(void)
{
struct device_node *memory;
@@ -1035,7 +1183,13 @@ early_param("topology_updates", early_topology_updates);
/*
* Find the node associated with a hot added memory section for
* memory represented in the device tree by the property
- * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory.
+ *
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
+ * or
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory-v2
+ *
+ * The layout of the ibm,dynamic-memory[-v2] property is a number
+ * N of memblock list entries.
*/
static int hot_add_drconf_scn_to_nid(struct device_node *memory,
unsigned long scn_addr)
@@ -1044,6 +1198,7 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
unsigned int drconf_cell_cnt, rc;
unsigned long lmb_size;
struct assoc_arrays aa;
+
int nid = -1;
drconf_cell_cnt = of_get_drconf_memory(memory, &dm);
@@ -1059,21 +1214,37 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
return -1;
for (; drconf_cell_cnt != 0; --drconf_cell_cnt) {
- struct of_drconf_cell drmem;
- read_drconf_cell(&drmem, &dm);
+ if (firmware_has_feature(FW_FEATURE_RPS_DM2)) {
+ struct of_drconf_cell_v2 drmem;
- /* skip this block if it is reserved or not assigned to
- * this partition */
- if ((drmem.flags & DRCONF_MEM_RESERVED)
- || !(drmem.flags & DRCONF_MEM_ASSIGNED))
- continue;
+ read_drconf_cell_v2(&drmem, &dm);
- if ((scn_addr < drmem.base_addr)
- || (scn_addr >= (drmem.base_addr + lmb_size)))
- continue;
+ /* Skip this block/series if it is reserved or not
+ * assigned to this partition
+ */
+ if ((drmem.flags & DRCONF_MEM_RESERVED)
+ || !(drmem.flags & DRCONF_MEM_ASSIGNED))
+ continue;
+
+ if ((scn_addr < drmem.base_addr)
+ || (scn_addr >= (drmem.base_addr +
+ (drmem.num_seq_lmbs * lmb_size))))
+ continue;
+ nid = of_drconf_to_nid_single(drmem.flags,
+ drmem.aa_index, &aa);
+ } else {
+ struct of_drconf_cell drmem;
+
+ read_drconf_cell(&drmem, &dm);
+
+ if ((scn_addr < drmem.base_addr)
+ || (scn_addr >= (drmem.base_addr + lmb_size)))
+ continue;
+ nid = of_drconf_to_nid_single(drmem.flags,
+ drmem.aa_index, &aa);
+ }
- nid = of_drconf_to_nid_single(&drmem, &aa);
break;
}
arch/powerpc/platforms/pseries/firmware.c +2 -0
@@ -111,6 +111,8 @@ static __initdata struct vec5_fw_feature vec5_fw_features_table[] = { {FW_FEATURE_TYPE1_AFFINITY ,OV5_TYPE1_AFFINITY }, {FW_FEATURE_PRRN ,OV5_PRRN }, + {FW_FEATURE_RPS_DM2 ,OV5_RPS_DM2 }, + {FW_FEATURE_RPS_DRC_INFO ,OV5_RPS_DRC_INFO }, };void __init fw_vec5_feature_init (const char *vec5,unsigned long len)
arch/powerpc/platforms/pseries/hotplug-memory.c +798 -37
1,043 lines not on this page · raw message
arch/powerpc/platforms/pseries/pseries_energy.c +157 -24
208 lines not on this page · raw message
drivers/pci/hotplug/rpadlpar_core.c +5 -8
@@ -27,6 +27,7 @@#include <linux/mutex.h> #include <asm/rtas.h> #include <asm/vio.h> +#include <asm/firmware.h> #include "../pci.h" #include "rpaphp.h"
@@ -44,15 +45,14 @@ static struct device_node *find_vio_slot_node(char *drc_name) {struct device_node *parent =of_find_node_by_name (NULL ,"vdevice" );struct device_node *dn =NULL ; -char *name;int rc;if (!parent)return NULL ;while ((dn =of_get_next_child (parent, dn))) { - rc =rpaphp_get_drc_props (dn,NULL , &name,NULL ,NULL ); -if ((rc ==0 ) && (!strcmp (drc_name, name))) + rc =rpaphp_check_drc_props (dn, drc_name,NULL ); +if (rc ==0 )break ; }
@@ -64,15 +64,12 @@ static struct device_node *find_php_slot_pci_node(char *drc_name, char *drc_type) {struct device_node *np =NULL ; -char *name; -char *type;int rc;while ((np =of_find_node_by_name (np,"pci" ))) { - rc =rpaphp_get_drc_props (np,NULL , &name, &type,NULL ); + rc =rpaphp_check_drc_props (np, drc_name, drc_type);if (rc ==0 ) -if (!strcmp (drc_name, name) && !strcmp (drc_type, type)) -break ; +break ; }return np;
drivers/pci/hotplug/rpaphp.h +2 -0
@@ -93,6 +93,8 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state);int rpaphp_add_slot (struct device_node *dn);int rpaphp_get_drc_props (struct device_node *dn,int *drc_index,char **drc_name,char **drc_type,int *drc_power_domain); +int rpaphp_check_drc_props (struct device_node *dn,char *drc_name, +char *drc_type);/* rpaphp_slot.c */ void dealloc_slot_struct (struct slot *slot);
drivers/pci/hotplug/rpaphp_core.c +119 -9
146 lines not on this page · raw message
RFC v3 1/1 powerpc/devtree: Parse new DRC mem/cpu/dev device tree elements
Several properties in the DRC device tree format are replaced by more compact representations to allow, for example, for the encoding of vast amounts of memory, and or reduced duplication of information in related data structures.
"ibm,drc-info": This property, when present, replaces the following four properties: “ibm,drc-indexes”, “ibm,drc-names”, “ibm,drc-types” and “ibm,drc-power-domains”. This property is defined for all dynamically reconfigurable platform nodes. The "ibm,drc-info" elements are intended to provide a more compact representation, and reduce some search overhead.
"ibm,dynamic-memory-v2": This property replaces the "ibm,dynamic-memory" node representation within the "ibm,dynamic-reconfiguration-memory" property. This element format is intended to provide a more compact representation of memory, especially, for systems with massive amounts of RAM.
"ibm,architecture.vec": Bit flags are added to this data structure by the front end processor to inform the kernel as to whether to expect the changes to one or both of the device tree structures "ibm,drc-info" and "ibm,dynamic-memory-v2".
The new element structures, "ibm,dynamic-memory-v2" and "ibm,drc-info", should completely replace the previously used structures at execution.
---
arch/powerpc/include/asm/firmware.h +4 -1
@@ -51,6 +51,8 @@#define FW_FEATURE_BEST_ENERGY ASM_CONST(0x0000000080000000)#define FW_FEATURE_TYPE1_AFFINITY ASM_CONST(0x0000000100000000)#define FW_FEATURE_PRRN ASM_CONST(0x0000000200000000) +#define FW_FEATURE_RPS_DM2 ASM_CONST(0x0000000400000000) +#define FW_FEATURE_RPS_DRC_INFO ASM_CONST(0x0000000800000000)#ifndef __ASSEMBLY__
@@ -66,7 +68,8 @@ enum {FW_FEATURE_MULTITCE |FW_FEATURE_SPLPAR |FW_FEATURE_LPAR |FW_FEATURE_CMO |FW_FEATURE_VPHN |FW_FEATURE_XCMO |FW_FEATURE_SET_MODE |FW_FEATURE_BEST_ENERGY | -FW_FEATURE_TYPE1_AFFINITY |FW_FEATURE_PRRN , +FW_FEATURE_TYPE1_AFFINITY |FW_FEATURE_PRRN | +FW_FEATURE_RPS_DM2 |FW_FEATURE_RPS_DRC_INFO ,FW_FEATURE_PSERIES_ALWAYS =0 ,FW_FEATURE_POWERNV_POSSIBLE =FW_FEATURE_OPAL , FW_FEATURE_POWERNV_ALWAYS = 0,
arch/powerpc/include/asm/prom.h +2 -0
@@ -69,6 +69,8 @@ struct boot_param_header {* OF address retreival & translation */ +extern int n_mem_addr_cells; +/* Parse the ibm,dma-window property of an OF node into the busno,
phys and
* size parameters.
*/
@@ -81,8 +83,9 @@ extern void of_instantiate_rtc(void);
extern int of_get_ibm_chip_id(struct device_node *np);
/* The of_drconf_cell struct defines the layout of the LMB array
- * specified in the device tree property
- * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
+ * specified in the device tree properties,
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory-v2
*/
struct of_drconf_cell {
u64 base_addr;
@@ -92,9 +95,60 @@ struct of_drconf_cell {
u32 flags;
};
-#define DRCONF_MEM_ASSIGNED 0x00000008
-#define DRCONF_MEM_AI_INVALID 0x00000040
-#define DRCONF_MEM_RESERVED 0x00000080
+ /* It is important to note that this structure can not
+ * be safely mapped onto the memory containing the
+ * 'ibm,dynamic-memory-v2' property due to the issues
+ * of compiler alignment. This structure represents
+ * the order of the fields stored, but compiler alignment
+ * may insert extra bytes of padding between the fields
+ * 'num_seq_lmbs' and 'base_addr'.
+ */
+struct of_drconf_cell_v2 {
+ u32 num_seq_lmbs;
+ u64 base_addr;
+ u32 drc_index;
+ u32 aa_index;
+ u32 flags;
+};
+
+#define DRCONF_MEM_PRESERVED 0x00000001
+#define DRCONF_MEM_PRESERVABLE 0x00000002
+#define DRCONF_MEM_PRESERVED_STATE 0x00000004
+#define DRCONF_MEM_ASSIGNED 0x00000008
+#define DRCONF_MEM_NO_H_MIGRATE_DATA 0x00000010
+#define DRCONF_MEM_DRC_INVALID 0x00000020
+#define DRCONF_MEM_AI_INVALID 0x00000040
+#define DRCONF_MEM_RESERVED 0x00000080
+#define DRCONF_MEM_RESERVED_SW 0x80000000
+
+#define DRCONF_V2_CELLS (n_mem_addr_cells + 4)
+#define DRCONF_V2_CELLS_LEN (DRCONF_V2_CELLS * sizeof(unsigned int))
+#define DRCONF_V2_CELL_OFFSET(i) (i * DRCONF_V2_CELLS_LEN)
+#define DRCONF_V2_CELL_POSITION(p,i) (void *)(((char *)p)+(i * DRCONF_V2_CELLS_LEN))
+#define DYN_MEM_V2_LEN(entries) ((entries * DRCONF_V2_CELLS_LEN) + \
+ (1 * sizeof(unsigned int)))
+
+extern void read_drconf_cell_v2(struct of_drconf_cell_v2 *drmem,
+ const __be32 **cellp, int no_cpu_chg);
+extern void write_drconf_cell_v2(struct of_drconf_cell_v2 *drmem,
+ const __be32 **cellp, int no_cpu_chg);
+extern void read_one_drc_info(int **info, char **drc_type, char **drc_name,
+ unsigned long int *fdi_p, unsigned long int *nsl_p,
+ unsigned long int *si_p, unsigned long int *ldi_p);
+
+
+/*
+ * Set of dynamic DLPAR memory function operations
+ */
+struct dlpar_memory_ops {
+ struct property* (*clone_drconf_property)(struct device_node *dn);
+ int (*add_by_count)(u32 lmbs_to_add, struct property **prop);
+ int (*add_by_index)(u32 lmbs_to_add, struct property **prop);
+ int (*remove_by_count)(u32 lmbs_to_add, struct property **prop);
+ int (*remove_by_index)(u32 lmbs_to_add, struct property **prop);
+ void (*update_drconf_property)(struct device_node *dn,
+ struct property *prop);
+};
/*
* There are two methods for telling firmware what our capabilities are.
@@ -155,6 +209,8 @@ struct of_drconf_cell {
#define OV5_PFO_HW_842 0x0E40 /* PFO Compression Accelerator */
#define OV5_PFO_HW_ENCR 0x0E20 /* PFO Encryption Accelerator */
#define OV5_SUB_PROCESSORS 0x0F01 /* 1,2,or 4 Sub-Processors supported */
+#define OV5_RPS_DM2 0x1601 /* Redef Prop Structures: dyn-mem-v2 */
+#define OV5_RPS_DRC_INFO 0x1602 /* Redef Prop Structures: drc-info */
/* Option Vector 6: IBM PAPR hints */
#define OV6_LINUX 0x02 /* Linux is our OS */
arch/powerpc/kernel/prom.c +95 -3
119 lines not on this page · raw message
arch/powerpc/mm/numa.c +4 -2
@@ -57,8 +57,10 @@ EXPORT_SYMBOL(node_to_cpumask_map);EXPORT_SYMBOL (node_data);static int min_common_depth; -static int n_mem_addr_cells, n_mem_size_cells; +int n_mem_addr_cells; +static int n_mem_size_cells;static int form1_affinity; +EXPORT_SYMBOL (n_mem_addr_cells);#define MAX_DISTANCE_REF_POINTS 4static int distance_ref_points_depth;
@@ -389,7 +391,7 @@ static unsigned long read_n_cells(int n, const __be32 **buf)/* * Read the next memblock list entry from the ibm,dynamic-memory property -* and return the information in the provided of_drconf_cell structure. +* and return the information in the provided of_drconf_cell/series structure. */ static void read_drconf_cell(struct of_drconf_cell *drmem, const
__be32 **cellp)
{
@@ -407,30 +409,103 @@ static void read_drconf_cell(struct of_drconf_cell *drmem, const __be32 **cellp)
}
/*
- * Retrieve and validate the ibm,dynamic-memory property of the device tree.
+ * Read the next memblock set entry from the ibm,dynamic-memory-v2 property
+ * and return the information in the provided of_drconf_cell_v2 structure.
+ */
+void read_drconf_cell_v2(struct of_drconf_cell_v2 *drmem, const __be32 **cellp,
+ int no_cpu_chg)
+{
+ const __be32 *cp = (const __be32 *)*cellp;
+
+ if (no_cpu_chg)
+ drmem->num_seq_lmbs = (*cp++);
+ else
+ drmem->num_seq_lmbs = be32_to_cpu(*cp++);
+
+ if (no_cpu_chg)
+ {
+ u64 r = 0;
+ int sz = n_mem_addr_cells;
+ while (sz--)
+ r = (r << 32) | (*cp++);
+ drmem->base_addr = r;
+ printk("numa.c[%d] rdc nmac=%d ba=0x%llx r=0x%llx\n", __LINE__, n_mem_addr_cells, (unsigned long long) drmem->base_addr, r);
+ } else {
+ drmem->base_addr = read_n_cells(n_mem_addr_cells, cp);
+ printk("numa.c[%d] rdc nmac=%d ba=0x%llx\n", __LINE__, n_mem_addr_cells, (unsigned long long) drmem->base_addr);
+ }
+
+ if (no_cpu_chg)
+ drmem->drc_index = (*cp++);
+ else
+ drmem->drc_index = be32_to_cpu(*cp++);
+ if (no_cpu_chg)
+ drmem->aa_index = (*cp++);
+ else
+ drmem->aa_index = be32_to_cpu(*cp++);
+ if (no_cpu_chg)
+ drmem->flags = (*cp++);
+ else
+ drmem->flags = be32_to_cpu(*cp++);
+
+ *cellp = cp;
+}
+EXPORT_SYMBOL(read_drconf_cell_v2);
+
+/*
+ * Retrieve and validate the ibm,dynamic-memory[-v2] property of the
+ * device tree.
*
* The layout of the ibm,dynamic-memory property is a number N of memblock
* list entries followed by N memblock list entries. Each memblock
list entry
* contains information as laid out in the of_drconf_cell struct above.
+ *
+ * The layout of the ibm,dynamic-memory-v2 property is a number N of memblock
+ * list entries.
*/
-static int of_get_drconf_memory(struct device_node *memory, const __be32 **dm) +static int of_get_drconf_memory(struct device_node *memory, const __be32 **dm,
+ int force_v2)
{
const __be32 *prop;
u32 len, entries;
- prop = of_get_property(memory, "ibm,dynamic-memory", &len);
- if (!prop || len < sizeof(unsigned int))
- return 0;
+ if (firmware_has_feature(FW_FEATURE_RPS_DM2) || force_v2)
+ {
+ prop = of_get_property(memory, "ibm,dynamic-memory-v2", &len);
+ if (!prop || len < sizeof(unsigned int))
+ return 0;
- entries = of_read_number(prop++, 1);
+ entries = of_read_number(prop++, 1);
- /* Now that we know the number of entries, revalidate the size
- * of the property read in to ensure we have everything
- */
- if (len < (entries * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int))
- return 0;
+ /* Now that we know the number of set entries, revalidate the
+ * size of the property read in to ensure we have everything.
+ */
+ printk("numa.c[%d] entries=0x%lx len=0x%lx tlen=0x%lx\n",
+ __LINE__,
+ (long unsigned int)entries,
+ (long unsigned int)len,
+ DYN_MEM_V2_LEN(entries));
+ if (len < DYN_MEM_V2_LEN(entries))
+ return 0;
+ printk("numa.c[%d]\n", __LINE__);
+
+ *dm = prop;
+ } else {
+ prop = of_get_property(memory, "ibm,dynamic-memory", &len);
+ if (!prop || len < sizeof(unsigned int))
+ return 0;
+
+ entries = of_read_number(prop++, 1);
+
+ /* Now that we know the number of entries, revalidate the size
+ * of the property read in to ensure we have everything
+ */
+ if (len < (entries * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int))
+ return 0;
+
+ *dm = prop;
+ }
- *dm = prop;
return entries;
}
@@ -459,7 +534,7 @@ struct assoc_arrays {
/*
* Retrieve and validate the list of associativity arrays for drconf
* memory from the ibm,associativity-lookup-arrays property of the
- * device tree..
+ * device tree.
*
* The layout of the ibm,associativity-lookup-arrays property is a
number N
* indicating the number of associativity arrays, followed by a number M
@@ -493,7 +568,7 @@ static int of_get_assoc_arrays(struct device_node *memory,
* This is like of_node_to_nid_single() for memory represented in the
* ibm,dynamic-reconfiguration-memory node.
*/
-static int of_drconf_to_nid_single(struct of_drconf_cell *drmem, +static int of_drconf_to_nid_single(u32 drmem_flags, u32 drmem_aa_index,
struct assoc_arrays *aa)
{
int default_nid = 0;
@@ -501,16 +576,16 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem,
int index;
if (min_common_depth > 0 && min_common_depth <= aa->array_sz &&
- !(drmem->flags & DRCONF_MEM_AI_INVALID) &&
- drmem->aa_index < aa->n_arrays) {
- index = drmem->aa_index * aa->array_sz + min_common_depth - 1;
+ !(drmem_flags & DRCONF_MEM_AI_INVALID) &&
+ drmem_aa_index < aa->n_arrays) {
+ index = drmem_aa_index * aa->array_sz + min_common_depth - 1;
nid = of_read_number(&aa->arrays[index], 1);
if (nid == 0xffff || nid >= MAX_NUMNODES)
nid = default_nid;
if (nid > 0) {
- index = drmem->aa_index * aa->array_sz;
+ index = drmem_aa_index * aa->array_sz;
initialize_distance_lookup_table(nid,
&aa->arrays[index]);
}
@@ -653,7 +728,91 @@ static inline int __init read_usm_ranges(const __be32 **usm)
* Extract NUMA information from the ibm,dynamic-reconfiguration-memory
* node. This assumes n_mem_{addr,size}_cells have been set.
*/
-static void __init parse_drconf_memory(struct device_node *memory) +static void __init parse_drconf_memory_v2(struct device_node *memory) +{
+ const __be32 *uninitialized_var(dm);
+ unsigned int num_sets, rc;
+ unsigned long lmb_size, base;
+ const __be32 *usm;
+ unsigned int ranges, is_kexec_kdump = 0;
+ unsigned long size, sz;
+ int nid;
+ struct assoc_arrays aa = { .arrays = NULL };
+
+ const __be32 *prop, *p;
+ u32 len;
+
+ prop = of_get_property(memory, "ibm,dynamic-memory-v2", &len);
+ if (!prop)
+ return;
+ p = prop;
+
+ num_sets = of_get_drconf_memory(memory, &dm, 1);
+ if (!num_sets)
+ return;
+
+ lmb_size = of_get_lmb_size(memory);
+ if (!lmb_size)
+ return;
+
+ rc = of_get_assoc_arrays(memory, &aa);
+ if (rc)
+ return;
+
+ for (; num_sets != 0; num_sets--) {
+ struct of_drconf_cell_v2 drmem;
+
+ /* Get the current LMB set */
+ read_drconf_cell_v2(&drmem, &dm, 0);
+ base = drmem.base_addr;
+
+ /* Check if this is a kexec/kdump kernel */
+ usm = of_get_usable_memory(memory);
+ if (usm != NULL)
+ is_kexec_kdump = 1;
+
+ /* Skip this block if the reserved bit is set in
+ * flags (0x80) or if the block is not assigned
+ * to this partition (0x8) */
+ if ((drmem.flags & DRCONF_MEM_RESERVED)
+ || !(drmem.flags & DRCONF_MEM_ASSIGNED))
+ continue;
+
+ for (; drmem.num_seq_lmbs != 0; --drmem.num_seq_lmbs) {
+ size = lmb_size;
+ ranges = 1;
+
+ if (is_kexec_kdump) {
+ ranges = read_usm_ranges(&usm);
+ if (!ranges)
+ /* there are no (base, size) duple */
+ continue;
+ }
+ do {
+ if (is_kexec_kdump) {
+ base = read_n_cells(n_mem_addr_cells,
+ &usm);
+ size = read_n_cells(n_mem_size_cells,
+ &usm);
+ }
+ nid = of_drconf_to_nid_single(drmem.flags,
+ drmem.aa_index, &aa);
+ fake_numa_create_new_node(
+ ((base + size) >> PAGE_SHIFT),
+ &nid);
+ node_set_online(nid);
+ sz = numa_enforce_memory_limit(base, size);
+ if (sz)
+ memblock_set_node(base, sz,
+ &memblock.memory, nid);
+ } while (--ranges);
+
+ base += sz;
+ }
+ }
+}
+
+static void __init parse_drconf_memory_v1(struct device_node *memory)
{
const __be32 *uninitialized_var(dm), *usm;
unsigned int n, rc, ranges, is_kexec_kdump = 0;
@@ -661,7 +820,7 @@ static void __init parse_drconf_memory(struct device_node *memory)
int nid;
struct assoc_arrays aa = { .arrays = NULL };
- n = of_get_drconf_memory(memory, &dm);
+ n = of_get_drconf_memory(memory, &dm, 0);
if (!n)
return;
@@ -673,7 +832,7 @@ static void __init parse_drconf_memory(struct device_node *memory)
if (rc)
return;
- /* check if this is a kexec/kdump kernel */
+ /* Check if this is a kexec/kdump kernel */
usm = of_get_usable_memory(memory);
if (usm != NULL)
is_kexec_kdump = 1;
@@ -703,19 +862,28 @@ static void __init parse_drconf_memory(struct device_node *memory)
base = read_n_cells(n_mem_addr_cells, &usm); size = read_n_cells(n_mem_size_cells, &usm);
}
- nid = of_drconf_to_nid_single(&drmem, &aa);
+ nid = of_drconf_to_nid_single(drmem.flags,
+ drmem.aa_index, &aa);
fake_numa_create_new_node(
((base + size) >> PAGE_SHIFT),
- &nid);
+ &nid);
node_set_online(nid);
sz = numa_enforce_memory_limit(base, size);
if (sz)
memblock_set_node(base, sz,
- &memblock.memory, nid);
+ &memblock.memory, nid);
} while (--ranges);
}
}
+static void __init parse_drconf_memory(struct device_node *memory)
+{
+ if (firmware_has_feature(FW_FEATURE_RPS_DM2))
+ parse_drconf_memory_v2(memory);
+ else
+ parse_drconf_memory_v1(memory);
+}
+
static int __init parse_numa_properties(void)
{
struct device_node *memory;
@@ -1035,7 +1203,13 @@ early_param("topology_updates", early_topology_updates);
/*
* Find the node associated with a hot added memory section for
* memory represented in the device tree by the property
- * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory.
+ *
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
+ * or
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory-v2
+ *
+ * The layout of the ibm,dynamic-memory[-v2] property is a number
+ * N of memblock list entries.
*/
static int hot_add_drconf_scn_to_nid(struct device_node *memory,
unsigned long scn_addr)
@@ -1044,9 +1218,10 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
unsigned int drconf_cell_cnt, rc;
unsigned long lmb_size;
struct assoc_arrays aa;
+
int nid = -1;
- drconf_cell_cnt = of_get_drconf_memory(memory, &dm);
+ drconf_cell_cnt = of_get_drconf_memory(memory, &dm, 0);
if (!drconf_cell_cnt)
return -1;
@@ -1059,21 +1234,33 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
return -1;
for (; drconf_cell_cnt != 0; --drconf_cell_cnt) {
- struct of_drconf_cell drmem;
- read_drconf_cell(&drmem, &dm);
+ if (firmware_has_feature(FW_FEATURE_RPS_DM2)) {
+ struct of_drconf_cell_v2 drmem;
- /* skip this block if it is reserved or not assigned to
- * this partition */
- if ((drmem.flags & DRCONF_MEM_RESERVED)
- || !(drmem.flags & DRCONF_MEM_ASSIGNED))
- continue;
+ read_drconf_cell_v2(&drmem, &dm, 0);
- if ((scn_addr < drmem.base_addr)
- || (scn_addr >= (drmem.base_addr + lmb_size)))
- continue;
+ /* Skip this block/series if it is reserved or not
+ * assigned to this partition */
+ if ((drmem.flags & DRCONF_MEM_RESERVED)
+ || !(drmem.flags & DRCONF_MEM_ASSIGNED))
+ continue;
+
+ if ((scn_addr < drmem.base_addr)
+ || (scn_addr >= (drmem.base_addr + (drmem.num_seq_lmbs * lmb_size))))
+ continue;
+ nid = of_drconf_to_nid_single(drmem.flags, drmem.aa_index, &aa);
+ } else {
+ struct of_drconf_cell drmem;
+
+ read_drconf_cell(&drmem, &dm);
+
+ if ((scn_addr < drmem.base_addr)
+ || (scn_addr >= (drmem.base_addr + lmb_size)))
+ continue;
+ nid = of_drconf_to_nid_single(drmem.flags, drmem.aa_index, &aa);
+ }
- nid = of_drconf_to_nid_single(&drmem, &aa);
break;
}
@@ -1170,7 +1357,7 @@ static u64 hot_add_drconf_memory_max(void)
memory =
of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
if (memory) {
- drconf_cell_cnt = of_get_drconf_memory(memory, &dm);
+ drconf_cell_cnt = of_get_drconf_memory(memory, &dm, 0);
lmb_size = of_get_lmb_size(memory);
of_node_put(memory);
}arch/powerpc/platforms/pseries/firmware.c +2 -0
@@ -111,6 +111,8 @@ static __initdata struct vec5_fw_feature vec5_fw_features_table[] = { {FW_FEATURE_TYPE1_AFFINITY ,OV5_TYPE1_AFFINITY }, {FW_FEATURE_PRRN ,OV5_PRRN }, + {FW_FEATURE_RPS_DM2 ,OV5_RPS_DM2 }, + {FW_FEATURE_RPS_DRC_INFO ,OV5_RPS_DRC_INFO }, };void __init fw_vec5_feature_init (const char *vec5,unsigned long len)
arch/powerpc/platforms/pseries/hotplug-memory.c +914 -21
1,089 lines not on this page · raw message
arch/powerpc/platforms/pseries/pseries_energy.c +160 -24
211 lines not on this page · raw message
drivers/pci/hotplug/rpadlpar_core.c +5 -8
@@ -27,6 +27,7 @@#include <linux/mutex.h> #include <asm/rtas.h> #include <asm/vio.h> +#include <asm/firmware.h> #include "../pci.h" #include "rpaphp.h"
@@ -44,15 +45,14 @@ static struct device_node *find_vio_slot_node(char *drc_name) {struct device_node *parent =of_find_node_by_name (NULL ,"vdevice" );struct device_node *dn =NULL ; -char *name;int rc;if (!parent)return NULL ;while ((dn =of_get_next_child (parent, dn))) { - rc =rpaphp_get_drc_props (dn,NULL , &name,NULL ,NULL ); -if ((rc ==0 ) && (!strcmp (drc_name, name))) + rc =rpaphp_check_drc_props (dn, drc_name,NULL ); +if (rc ==0 )break ; }
@@ -64,15 +64,12 @@ static struct device_node *find_php_slot_pci_node(char *drc_name, char *drc_type) {struct device_node *np =NULL ; -char *name; -char *type;int rc;while ((np =of_find_node_by_name (np,"pci" ))) { - rc =rpaphp_get_drc_props (np,NULL , &name, &type,NULL ); + rc =rpaphp_check_drc_props (np, drc_name, drc_type);if (rc ==0 ) -if (!strcmp (drc_name, name) && !strcmp (drc_type, type)) -break ; +break ; }return np;
drivers/pci/hotplug/rpaphp.h +2 -2
@@ -91,8 +91,8 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state);/* rpaphp_core.c */ int rpaphp_add_slot (struct device_node *dn); -int rpaphp_get_drc_props (struct device_node *dn,int *drc_index, -char **drc_name,char **drc_type,int *drc_power_domain); +int rpaphp_check_drc_props (struct device_node *dn,char *drc_name, +char *drc_type);/* rpaphp_slot.c */ void dealloc_slot_struct (struct slot *slot);
drivers/pci/hotplug/rpaphp_core.c +83 -35
153 lines not on this page · raw message