[{"id":1758696,"web_url":"http://patchwork.ozlabs.org/comment/1758696/","msgid":"<d5b7a976-b0a6-a4d6-c062-75d65d8a6eac@linux.vnet.ibm.com>","date":"2017-08-28T16:25:05","subject":"Re: [PATCH V10 1/2] powerpc/numa: Update CPU topology when VPHN\n\tenabled","submitter":{"id":17146,"url":"http://patchwork.ozlabs.org/api/people/17146/","name":"Nathan Fontenot","email":"nfont@linux.vnet.ibm.com"},"content":"On 08/24/2017 05:07 PM, Michael Bringmann wrote:\n> \n> powerpc/numa: Correct the currently broken capability to set the\n> topology for shared CPUs in LPARs.  At boot time for shared CPU\n> lpars, the topology for each shared CPU is set to node zero, however,\n> this is now updated correctly using the Virtual Processor Home Node\n> (VPHN) capabilities information provided by the pHyp.\n> \n> Also, update initialization checks for device-tree attributes to\n> independently recognize PRRN or VPHN usage.\n> \n> Finally, try to distinguish the VPHN code from the NUMA code better,\n> and move relevant functions to another file.\n\nYou need to split the move of the vphn code to a different file into\na separate patch. With thia all in one patch it is really difficult\nto distinguish what pieces are code changes and what is just moving\ncode around.\n\n-Nathan\n\n> \n> Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>\n> ---\n> Changes in V10:\n>   -- Reorganize VPHN code to distinguish it from NUMA processing\n> ---\n>  arch/powerpc/include/asm/topology.h          |    8 \n>  arch/powerpc/mm/numa.c                       |  503 ----------------------\n>  arch/powerpc/mm/vphn.c                       |  586 ++++++++++++++++++++++++++\n>  arch/powerpc/mm/vphn.h                       |    4 \n>  arch/powerpc/platforms/pseries/hotplug-cpu.c |    2 \n>  5 files changed, 609 insertions(+), 494 deletions(-)\n> \n> diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h\n> index dc4e159..600e1c6 100644\n> --- a/arch/powerpc/include/asm/topology.h\n> +++ b/arch/powerpc/include/asm/topology.h\n> @@ -98,6 +98,14 @@ static inline int prrn_is_enabled(void)\n>  }\n>  #endif /* CONFIG_NUMA && CONFIG_PPC_SPLPAR */\n> \n> +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_NEED_MULTIPLE_NODES)\n> +#if defined(CONFIG_PPC_SPLPAR)\n> +extern int timed_topology_update(int nsecs);\n> +#else\n> +#define\ttimed_topology_update(nsecs)\t0\n> +#endif /* CONFIG_PPC_SPLPAR */\n> +#endif /* CONFIG_HOTPLUG_CPU || CONFIG_NEED_MULTIPLE_NODES */\n> +\n>  #include <asm-generic/topology.h>\n> \n>  #ifdef CONFIG_SMP\n> diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c\n> index b95c584..73427e290 100644\n> --- a/arch/powerpc/mm/numa.c\n> +++ b/arch/powerpc/mm/numa.c\n> @@ -29,6 +29,7 @@\n>  #include <linux/seq_file.h>\n>  #include <linux/uaccess.h>\n>  #include <linux/slab.h>\n> +#include <linux/sched.h>\n>  #include <asm/cputhreads.h>\n>  #include <asm/sparsemem.h>\n>  #include <asm/prom.h>\n> @@ -41,8 +42,12 @@\n>  #include <asm/setup.h>\n>  #include <asm/vdso.h>\n> \n> +#include \"vphn.h\"\n> +\n>  static int numa_enabled = 1;\n> \n> +bool topology_updates_enabled = true;\n> +\n>  static char *cmdline __initdata;\n> \n>  static int numa_debug;\n> @@ -60,8 +65,7 @@\n>  static int n_mem_addr_cells, n_mem_size_cells;\n>  static int form1_affinity;\n> \n> -#define MAX_DISTANCE_REF_POINTS 4\n> -static int distance_ref_points_depth;\n> +int distance_ref_points_depth;\n>  static const __be32 *distance_ref_points;\n>  static int distance_lookup_table[MAX_NUMNODES][MAX_DISTANCE_REF_POINTS];\n> \n> @@ -142,12 +146,12 @@ static void reset_numa_cpu_lookup_table(void)\n>  \t\tnuma_cpu_lookup_table[cpu] = -1;\n>  }\n> \n> -static void update_numa_cpu_lookup_table(unsigned int cpu, int node)\n> +void update_numa_cpu_lookup_table(unsigned int cpu, int node)\n>  {\n>  \tnuma_cpu_lookup_table[cpu] = node;\n>  }\n> \n> -static void map_cpu_to_node(int cpu, int node)\n> +void map_cpu_to_node(int cpu, int node)\n>  {\n>  \tupdate_numa_cpu_lookup_table(cpu, node);\n> \n> @@ -158,7 +162,7 @@ static void map_cpu_to_node(int cpu, int node)\n>  }\n> \n>  #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PPC_SPLPAR)\n> -static void unmap_cpu_from_node(unsigned long cpu)\n> +void unmap_cpu_from_node(unsigned long cpu)\n>  {\n>  \tint node = numa_cpu_lookup_table[cpu];\n> \n> @@ -233,7 +237,7 @@ static void initialize_distance_lookup_table(int nid,\n>  /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa\n>   * info is found.\n>   */\n> -static int associativity_to_nid(const __be32 *associativity)\n> +int associativity_to_nid(const __be32 *associativity)\n>  {\n>  \tint nid = -1;\n> \n> @@ -957,8 +961,6 @@ static int __init early_numa(char *p)\n>  }\n>  early_param(\"numa\", early_numa);\n> \n> -static bool topology_updates_enabled = true;\n> -\n>  static int __init early_topology_updates(char *p)\n>  {\n>  \tif (!p)\n> @@ -1135,488 +1137,3 @@ u64 memory_hotplug_max(void)\n>          return max(hot_add_drconf_memory_max(), memblock_end_of_DRAM());\n>  }\n>  #endif /* CONFIG_MEMORY_HOTPLUG */\n> -\n> -/* Virtual Processor Home Node (VPHN) support */\n> -#ifdef CONFIG_PPC_SPLPAR\n> -\n> -#include \"vphn.h\"\n> -\n> -struct topology_update_data {\n> -\tstruct topology_update_data *next;\n> -\tunsigned int cpu;\n> -\tint old_nid;\n> -\tint new_nid;\n> -};\n> -\n> -static u8 vphn_cpu_change_counts[NR_CPUS][MAX_DISTANCE_REF_POINTS];\n> -static cpumask_t cpu_associativity_changes_mask;\n> -static int vphn_enabled;\n> -static int prrn_enabled;\n> -static void reset_topology_timer(void);\n> -\n> -/*\n> - * Store the current values of the associativity change counters in the\n> - * hypervisor.\n> - */\n> -static void setup_cpu_associativity_change_counters(void)\n> -{\n> -\tint cpu;\n> -\n> -\t/* The VPHN feature supports a maximum of 8 reference points */\n> -\tBUILD_BUG_ON(MAX_DISTANCE_REF_POINTS > 8);\n> -\n> -\tfor_each_possible_cpu(cpu) {\n> -\t\tint i;\n> -\t\tu8 *counts = vphn_cpu_change_counts[cpu];\n> -\t\tvolatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;\n> -\n> -\t\tfor (i = 0; i < distance_ref_points_depth; i++)\n> -\t\t\tcounts[i] = hypervisor_counts[i];\n> -\t}\n> -}\n> -\n> -/*\n> - * The hypervisor maintains a set of 8 associativity change counters in\n> - * the VPA of each cpu that correspond to the associativity levels in the\n> - * ibm,associativity-reference-points property. When an associativity\n> - * level changes, the corresponding counter is incremented.\n> - *\n> - * Set a bit in cpu_associativity_changes_mask for each cpu whose home\n> - * node associativity levels have changed.\n> - *\n> - * Returns the number of cpus with unhandled associativity changes.\n> - */\n> -static int update_cpu_associativity_changes_mask(void)\n> -{\n> -\tint cpu;\n> -\tcpumask_t *changes = &cpu_associativity_changes_mask;\n> -\n> -\tfor_each_possible_cpu(cpu) {\n> -\t\tint i, changed = 0;\n> -\t\tu8 *counts = vphn_cpu_change_counts[cpu];\n> -\t\tvolatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;\n> -\n> -\t\tfor (i = 0; i < distance_ref_points_depth; i++) {\n> -\t\t\tif (hypervisor_counts[i] != counts[i]) {\n> -\t\t\t\tcounts[i] = hypervisor_counts[i];\n> -\t\t\t\tchanged = 1;\n> -\t\t\t}\n> -\t\t}\n> -\t\tif (changed) {\n> -\t\t\tcpumask_or(changes, changes, cpu_sibling_mask(cpu));\n> -\t\t\tcpu = cpu_last_thread_sibling(cpu);\n> -\t\t}\n> -\t}\n> -\n> -\treturn cpumask_weight(changes);\n> -}\n> -\n> -/*\n> - * Retrieve the new associativity information for a virtual processor's\n> - * home node.\n> - */\n> -static long hcall_vphn(unsigned long cpu, __be32 *associativity)\n> -{\n> -\tlong rc;\n> -\tlong retbuf[PLPAR_HCALL9_BUFSIZE] = {0};\n> -\tu64 flags = 1;\n> -\tint hwcpu = get_hard_smp_processor_id(cpu);\n> -\n> -\trc = plpar_hcall9(H_HOME_NODE_ASSOCIATIVITY, retbuf, flags, hwcpu);\n> -\tvphn_unpack_associativity(retbuf, associativity);\n> -\n> -\treturn rc;\n> -}\n> -\n> -static long vphn_get_associativity(unsigned long cpu,\n> -\t\t\t\t\t__be32 *associativity)\n> -{\n> -\tlong rc;\n> -\n> -\trc = hcall_vphn(cpu, associativity);\n> -\n> -\tswitch (rc) {\n> -\tcase H_FUNCTION:\n> -\t\tprintk(KERN_INFO\n> -\t\t\t\"VPHN is not supported. Disabling polling...\\n\");\n> -\t\tstop_topology_update();\n> -\t\tbreak;\n> -\tcase H_HARDWARE:\n> -\t\tprintk(KERN_ERR\n> -\t\t\t\"hcall_vphn() experienced a hardware fault \"\n> -\t\t\t\"preventing VPHN. Disabling polling...\\n\");\n> -\t\tstop_topology_update();\n> -\t}\n> -\n> -\treturn rc;\n> -}\n> -\n> -/*\n> - * Update the CPU maps and sysfs entries for a single CPU when its NUMA\n> - * characteristics change. This function doesn't perform any locking and is\n> - * only safe to call from stop_machine().\n> - */\n> -static int update_cpu_topology(void *data)\n> -{\n> -\tstruct topology_update_data *update;\n> -\tunsigned long cpu;\n> -\n> -\tif (!data)\n> -\t\treturn -EINVAL;\n> -\n> -\tcpu = smp_processor_id();\n> -\n> -\tfor (update = data; update; update = update->next) {\n> -\t\tint new_nid = update->new_nid;\n> -\t\tif (cpu != update->cpu)\n> -\t\t\tcontinue;\n> -\n> -\t\tunmap_cpu_from_node(cpu);\n> -\t\tmap_cpu_to_node(cpu, new_nid);\n> -\t\tset_cpu_numa_node(cpu, new_nid);\n> -\t\tset_cpu_numa_mem(cpu, local_memory_node(new_nid));\n> -\t\tvdso_getcpu_init();\n> -\t}\n> -\n> -\treturn 0;\n> -}\n> -\n> -static int update_lookup_table(void *data)\n> -{\n> -\tstruct topology_update_data *update;\n> -\n> -\tif (!data)\n> -\t\treturn -EINVAL;\n> -\n> -\t/*\n> -\t * Upon topology update, the numa-cpu lookup table needs to be updated\n> -\t * for all threads in the core, including offline CPUs, to ensure that\n> -\t * future hotplug operations respect the cpu-to-node associativity\n> -\t * properly.\n> -\t */\n> -\tfor (update = data; update; update = update->next) {\n> -\t\tint nid, base, j;\n> -\n> -\t\tnid = update->new_nid;\n> -\t\tbase = cpu_first_thread_sibling(update->cpu);\n> -\n> -\t\tfor (j = 0; j < threads_per_core; j++) {\n> -\t\t\tupdate_numa_cpu_lookup_table(base + j, nid);\n> -\t\t}\n> -\t}\n> -\n> -\treturn 0;\n> -}\n> -\n> -/*\n> - * Update the node maps and sysfs entries for each cpu whose home node\n> - * has changed. Returns 1 when the topology has changed, and 0 otherwise.\n> - *\n> - * cpus_locked says whether we already hold cpu_hotplug_lock.\n> - */\n> -int numa_update_cpu_topology(bool cpus_locked)\n> -{\n> -\tunsigned int cpu, sibling, changed = 0;\n> -\tstruct topology_update_data *updates, *ud;\n> -\t__be32 associativity[VPHN_ASSOC_BUFSIZE] = {0};\n> -\tcpumask_t updated_cpus;\n> -\tstruct device *dev;\n> -\tint weight, new_nid, i = 0;\n> -\n> -\tif (!prrn_enabled && !vphn_enabled)\n> -\t\treturn 0;\n> -\n> -\tweight = cpumask_weight(&cpu_associativity_changes_mask);\n> -\tif (!weight)\n> -\t\treturn 0;\n> -\n> -\tupdates = kzalloc(weight * (sizeof(*updates)), GFP_KERNEL);\n> -\tif (!updates)\n> -\t\treturn 0;\n> -\n> -\tcpumask_clear(&updated_cpus);\n> -\n> -\tfor_each_cpu(cpu, &cpu_associativity_changes_mask) {\n> -\t\t/*\n> -\t\t * If siblings aren't flagged for changes, updates list\n> -\t\t * will be too short. Skip on this update and set for next\n> -\t\t * update.\n> -\t\t */\n> -\t\tif (!cpumask_subset(cpu_sibling_mask(cpu),\n> -\t\t\t\t\t&cpu_associativity_changes_mask)) {\n> -\t\t\tpr_info(\"Sibling bits not set for associativity \"\n> -\t\t\t\t\t\"change, cpu%d\\n\", cpu);\n> -\t\t\tcpumask_or(&cpu_associativity_changes_mask,\n> -\t\t\t\t\t&cpu_associativity_changes_mask,\n> -\t\t\t\t\tcpu_sibling_mask(cpu));\n> -\t\t\tcpu = cpu_last_thread_sibling(cpu);\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\t/* Use associativity from first thread for all siblings */\n> -\t\tvphn_get_associativity(cpu, associativity);\n> -\t\tnew_nid = associativity_to_nid(associativity);\n> -\t\tif (new_nid < 0 || !node_online(new_nid))\n> -\t\t\tnew_nid = first_online_node;\n> -\n> -\t\tif (new_nid == numa_cpu_lookup_table[cpu]) {\n> -\t\t\tcpumask_andnot(&cpu_associativity_changes_mask,\n> -\t\t\t\t\t&cpu_associativity_changes_mask,\n> -\t\t\t\t\tcpu_sibling_mask(cpu));\n> -\t\t\tcpu = cpu_last_thread_sibling(cpu);\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\tfor_each_cpu(sibling, cpu_sibling_mask(cpu)) {\n> -\t\t\tud = &updates[i++];\n> -\t\t\tud->cpu = sibling;\n> -\t\t\tud->new_nid = new_nid;\n> -\t\t\tud->old_nid = numa_cpu_lookup_table[sibling];\n> -\t\t\tcpumask_set_cpu(sibling, &updated_cpus);\n> -\t\t\tif (i < weight)\n> -\t\t\t\tud->next = &updates[i];\n> -\t\t}\n> -\t\tcpu = cpu_last_thread_sibling(cpu);\n> -\t}\n> -\n> -\tpr_debug(\"Topology update for the following CPUs:\\n\");\n> -\tif (cpumask_weight(&updated_cpus)) {\n> -\t\tfor (ud = &updates[0]; ud; ud = ud->next) {\n> -\t\t\tpr_debug(\"cpu %d moving from node %d \"\n> -\t\t\t\t\t  \"to %d\\n\", ud->cpu,\n> -\t\t\t\t\t  ud->old_nid, ud->new_nid);\n> -\t\t}\n> -\t}\n> -\n> -\t/*\n> -\t * In cases where we have nothing to update (because the updates list\n> -\t * is too short or because the new topology is same as the old one),\n> -\t * skip invoking update_cpu_topology() via stop-machine(). This is\n> -\t * necessary (and not just a fast-path optimization) since stop-machine\n> -\t * can end up electing a random CPU to run update_cpu_topology(), and\n> -\t * thus trick us into setting up incorrect cpu-node mappings (since\n> -\t * 'updates' is kzalloc()'ed).\n> -\t *\n> -\t * And for the similar reason, we will skip all the following updating.\n> -\t */\n> -\tif (!cpumask_weight(&updated_cpus))\n> -\t\tgoto out;\n> -\n> -\tif (cpus_locked)\n> -\t\tstop_machine_cpuslocked(update_cpu_topology, &updates[0],\n> -\t\t\t\t\t&updated_cpus);\n> -\telse\n> -\t\tstop_machine(update_cpu_topology, &updates[0], &updated_cpus);\n> -\n> -\t/*\n> -\t * Update the numa-cpu lookup table with the new mappings, even for\n> -\t * offline CPUs. It is best to perform this update from the stop-\n> -\t * machine context.\n> -\t */\n> -\tif (cpus_locked)\n> -\t\tstop_machine_cpuslocked(update_lookup_table, &updates[0],\n> -\t\t\t\t\tcpumask_of(raw_smp_processor_id()));\n> -\telse\n> -\t\tstop_machine(update_lookup_table, &updates[0],\n> -\t\t\t     cpumask_of(raw_smp_processor_id()));\n> -\n> -\tfor (ud = &updates[0]; ud; ud = ud->next) {\n> -\t\tunregister_cpu_under_node(ud->cpu, ud->old_nid);\n> -\t\tregister_cpu_under_node(ud->cpu, ud->new_nid);\n> -\n> -\t\tdev = get_cpu_device(ud->cpu);\n> -\t\tif (dev)\n> -\t\t\tkobject_uevent(&dev->kobj, KOBJ_CHANGE);\n> -\t\tcpumask_clear_cpu(ud->cpu, &cpu_associativity_changes_mask);\n> -\t\tchanged = 1;\n> -\t}\n> -\n> -out:\n> -\tkfree(updates);\n> -\treturn changed;\n> -}\n> -\n> -int arch_update_cpu_topology(void)\n> -{\n> -\tlockdep_assert_cpus_held();\n> -\treturn numa_update_cpu_topology(true);\n> -}\n> -\n> -static void topology_work_fn(struct work_struct *work)\n> -{\n> -\trebuild_sched_domains();\n> -}\n> -static DECLARE_WORK(topology_work, topology_work_fn);\n> -\n> -static void topology_schedule_update(void)\n> -{\n> -\tschedule_work(&topology_work);\n> -}\n> -\n> -static void topology_timer_fn(unsigned long ignored)\n> -{\n> -\tif (prrn_enabled && cpumask_weight(&cpu_associativity_changes_mask))\n> -\t\ttopology_schedule_update();\n> -\telse if (vphn_enabled) {\n> -\t\tif (update_cpu_associativity_changes_mask() > 0)\n> -\t\t\ttopology_schedule_update();\n> -\t\treset_topology_timer();\n> -\t}\n> -}\n> -static struct timer_list topology_timer =\n> -\tTIMER_INITIALIZER(topology_timer_fn, 0, 0);\n> -\n> -static void reset_topology_timer(void)\n> -{\n> -\ttopology_timer.data = 0;\n> -\ttopology_timer.expires = jiffies + 60 * HZ;\n> -\tmod_timer(&topology_timer, topology_timer.expires);\n> -}\n> -\n> -#ifdef CONFIG_SMP\n> -\n> -static void stage_topology_update(int core_id)\n> -{\n> -\tcpumask_or(&cpu_associativity_changes_mask,\n> -\t\t&cpu_associativity_changes_mask, cpu_sibling_mask(core_id));\n> -\treset_topology_timer();\n> -}\n> -\n> -static int dt_update_callback(struct notifier_block *nb,\n> -\t\t\t\tunsigned long action, void *data)\n> -{\n> -\tstruct of_reconfig_data *update = data;\n> -\tint rc = NOTIFY_DONE;\n> -\n> -\tswitch (action) {\n> -\tcase OF_RECONFIG_UPDATE_PROPERTY:\n> -\t\tif (!of_prop_cmp(update->dn->type, \"cpu\") &&\n> -\t\t    !of_prop_cmp(update->prop->name, \"ibm,associativity\")) {\n> -\t\t\tu32 core_id;\n> -\t\t\tof_property_read_u32(update->dn, \"reg\", &core_id);\n> -\t\t\tstage_topology_update(core_id);\n> -\t\t\trc = NOTIFY_OK;\n> -\t\t}\n> -\t\tbreak;\n> -\t}\n> -\n> -\treturn rc;\n> -}\n> -\n> -static struct notifier_block dt_update_nb = {\n> -\t.notifier_call = dt_update_callback,\n> -};\n> -\n> -#endif\n> -\n> -/*\n> - * Start polling for associativity changes.\n> - */\n> -int start_topology_update(void)\n> -{\n> -\tint rc = 0;\n> -\n> -\tif (firmware_has_feature(FW_FEATURE_PRRN)) {\n> -\t\tif (!prrn_enabled) {\n> -\t\t\tprrn_enabled = 1;\n> -\t\t\tvphn_enabled = 0;\n> -#ifdef CONFIG_SMP\n> -\t\t\trc = of_reconfig_notifier_register(&dt_update_nb);\n> -#endif\n> -\t\t}\n> -\t} else if (firmware_has_feature(FW_FEATURE_VPHN) &&\n> -\t\t   lppaca_shared_proc(get_lppaca())) {\n> -\t\tif (!vphn_enabled) {\n> -\t\t\tprrn_enabled = 0;\n> -\t\t\tvphn_enabled = 1;\n> -\t\t\tsetup_cpu_associativity_change_counters();\n> -\t\t\tinit_timer_deferrable(&topology_timer);\n> -\t\t\treset_topology_timer();\n> -\t\t}\n> -\t}\n> -\n> -\treturn rc;\n> -}\n> -\n> -/*\n> - * Disable polling for VPHN associativity changes.\n> - */\n> -int stop_topology_update(void)\n> -{\n> -\tint rc = 0;\n> -\n> -\tif (prrn_enabled) {\n> -\t\tprrn_enabled = 0;\n> -#ifdef CONFIG_SMP\n> -\t\trc = of_reconfig_notifier_unregister(&dt_update_nb);\n> -#endif\n> -\t} else if (vphn_enabled) {\n> -\t\tvphn_enabled = 0;\n> -\t\trc = del_timer_sync(&topology_timer);\n> -\t}\n> -\n> -\treturn rc;\n> -}\n> -\n> -int prrn_is_enabled(void)\n> -{\n> -\treturn prrn_enabled;\n> -}\n> -\n> -static int topology_read(struct seq_file *file, void *v)\n> -{\n> -\tif (vphn_enabled || prrn_enabled)\n> -\t\tseq_puts(file, \"on\\n\");\n> -\telse\n> -\t\tseq_puts(file, \"off\\n\");\n> -\n> -\treturn 0;\n> -}\n> -\n> -static int topology_open(struct inode *inode, struct file *file)\n> -{\n> -\treturn single_open(file, topology_read, NULL);\n> -}\n> -\n> -static ssize_t topology_write(struct file *file, const char __user *buf,\n> -\t\t\t      size_t count, loff_t *off)\n> -{\n> -\tchar kbuf[4]; /* \"on\" or \"off\" plus null. */\n> -\tint read_len;\n> -\n> -\tread_len = count < 3 ? count : 3;\n> -\tif (copy_from_user(kbuf, buf, read_len))\n> -\t\treturn -EINVAL;\n> -\n> -\tkbuf[read_len] = '\\0';\n> -\n> -\tif (!strncmp(kbuf, \"on\", 2))\n> -\t\tstart_topology_update();\n> -\telse if (!strncmp(kbuf, \"off\", 3))\n> -\t\tstop_topology_update();\n> -\telse\n> -\t\treturn -EINVAL;\n> -\n> -\treturn count;\n> -}\n> -\n> -static const struct file_operations topology_ops = {\n> -\t.read = seq_read,\n> -\t.write = topology_write,\n> -\t.open = topology_open,\n> -\t.release = single_release\n> -};\n> -\n> -static int topology_update_init(void)\n> -{\n> -\t/* Do not poll for changes if disabled at boot */\n> -\tif (topology_updates_enabled)\n> -\t\tstart_topology_update();\n> -\n> -\tif (!proc_create(\"powerpc/topology_updates\", 0644, NULL, &topology_ops))\n> -\t\treturn -ENOMEM;\n> -\n> -\treturn 0;\n> -}\n> -device_initcall(topology_update_init);\n> -#endif /* CONFIG_PPC_SPLPAR */\n> diff --git a/arch/powerpc/mm/vphn.c b/arch/powerpc/mm/vphn.c\n> index 5f8ef50..006bcc2 100644\n> --- a/arch/powerpc/mm/vphn.c\n> +++ b/arch/powerpc/mm/vphn.c\n> @@ -1,4 +1,46 @@\n> -#include <asm/byteorder.h>\n> +/*\n> + * pSeries VPHN support\n> + *\n> + * Copyright (C) 2016 Greg Kurz <gkurz@linux.vnet.ibm.com>, IBM\n> + *\n> + * This program is free software; you can redistribute it and/or\n> + * modify it under the terms of the GNU General Public License\n> + * as published by the Free Software Foundation; either version\n> + * 2 of the License, or (at your option) any later version.\n> + */\n> +\n> +#include <linux/threads.h>\n> +#include <linux/bootmem.h>\n> +#include <linux/init.h>\n> +#include <linux/mm.h>\n> +#include <linux/mmzone.h>\n> +#include <linux/export.h>\n> +#include <linux/nodemask.h>\n> +#include <linux/cpu.h>\n> +#include <linux/notifier.h>\n> +#include <linux/memblock.h>\n> +#include <linux/of.h>\n> +#include <linux/pfn.h>\n> +#include <linux/cpuset.h>\n> +#include <linux/node.h>\n> +#include <linux/stop_machine.h>\n> +#include <linux/proc_fs.h>\n> +#include <linux/seq_file.h>\n> +#include <linux/uaccess.h>\n> +#include <linux/slab.h>\n> +#include <linux/sched.h>\n> +#include <asm/cputhreads.h>\n> +#include <asm/sparsemem.h>\n> +#include <asm/prom.h>\n> +#include <asm/smp.h>\n> +#include <asm/cputhreads.h>\n> +#include <asm/topology.h>\n> +#include <asm/firmware.h>\n> +#include <asm/paca.h>\n> +#include <asm/hvcall.h>\n> +#include <asm/setup.h>\n> +#include <asm/vdso.h>\n> +\n>  #include \"vphn.h\"\n> \n>  /*\n> @@ -68,3 +110,545 @@ int vphn_unpack_associativity(const long *packed, __be32 *unpacked)\n> \n>  \treturn nr_assoc_doms;\n>  }\n> +\n> +\n> +/* Virtual Processor Home Node (VPHN) support */\n> +#ifdef CONFIG_PPC_SPLPAR\n> +\n> +extern bool topology_updates_enabled;\n> +extern int distance_ref_points_depth;\n> +\n> +extern int associativity_to_nid(const __be32 *associativity);\n> +extern void unmap_cpu_from_node(unsigned long cpu);\n> +extern void map_cpu_to_node(int cpu, int node);\n> +extern void update_numa_cpu_lookup_table(unsigned int cpu, int node);\n> +\n> +\n> +struct topology_update_data {\n> +\tstruct topology_update_data *next;\n> +\tunsigned int cpu;\n> +\tint old_nid;\n> +\tint new_nid;\n> +};\n> +\n> +#define\tTOPOLOGY_DEF_TIMER_SECS\t\t60\n> +\n> +static u8 vphn_cpu_change_counts[NR_CPUS][MAX_DISTANCE_REF_POINTS];\n> +static cpumask_t cpu_associativity_changes_mask;\n> +static int topology_timer_secs = TOPOLOGY_DEF_TIMER_SECS;\n> +static int vphn_enabled;\n> +static int prrn_enabled;\n> +static int topology_inited;\n> +static int topology_update_needed;\n> +\n> +static void reset_topology_timer(void);\n> +\n> +/*\n> + * Change polling interval for associativity changes.\n> + */\n> +int timed_topology_update(int nsecs)\n> +{\n> +\tif (nsecs > 0)\n> +\t\ttopology_timer_secs = nsecs;\n> +\telse\n> +\t\ttopology_timer_secs = TOPOLOGY_DEF_TIMER_SECS;\n> +\n> +\tif (vphn_enabled)\n> +\t\treset_topology_timer();\n> +\n> +\treturn 0;\n> +}\n> +\n> +/*\n> + * Store the current values of the associativity change counters in the\n> + * hypervisor.\n> + */\n> +static void setup_cpu_associativity_change_counters(void)\n> +{\n> +\tint cpu;\n> +\n> +\t/* The VPHN feature supports a maximum of 8 reference points */\n> +\tBUILD_BUG_ON(MAX_DISTANCE_REF_POINTS > 8);\n> +\n> +\tfor_each_possible_cpu(cpu) {\n> +\t\tint i;\n> +\t\tu8 *counts = vphn_cpu_change_counts[cpu];\n> +\t\tvolatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;\n> +\n> +\t\tfor (i = 0; i < distance_ref_points_depth; i++)\n> +\t\t\tcounts[i] = hypervisor_counts[i];\n> +\t}\n> +}\n> +\n> +/*\n> + * The hypervisor maintains a set of 8 associativity change counters in\n> + * the VPA of each cpu that correspond to the associativity levels in the\n> + * ibm,associativity-reference-points property. When an associativity\n> + * level changes, the corresponding counter is incremented.\n> + *\n> + * Set a bit in cpu_associativity_changes_mask for each cpu whose home\n> + * node associativity levels have changed.\n> + *\n> + * Returns the number of cpus with unhandled associativity changes.\n> + */\n> +static int update_cpu_associativity_changes_mask(void)\n> +{\n> +\tint cpu;\n> +\tcpumask_t *changes = &cpu_associativity_changes_mask;\n> +\n> +\tfor_each_possible_cpu(cpu) {\n> +\t\tint i, changed = 0;\n> +\t\tu8 *counts = vphn_cpu_change_counts[cpu];\n> +\t\tvolatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;\n> +\n> +\t\tfor (i = 0; i < distance_ref_points_depth; i++) {\n> +\t\t\tif (hypervisor_counts[i] != counts[i]) {\n> +\t\t\t\tcounts[i] = hypervisor_counts[i];\n> +\t\t\t\tchanged = 1;\n> +\t\t\t}\n> +\t\t}\n> +\t\tif (changed) {\n> +\t\t\tcpumask_or(changes, changes, cpu_sibling_mask(cpu));\n> +\t\t\tcpu = cpu_last_thread_sibling(cpu);\n> +\t\t}\n> +\t}\n> +\n> +\treturn cpumask_weight(changes);\n> +}\n> +\n> +/*\n> + * Retrieve the new associativity information for a virtual processor's\n> + * home node.\n> + */\n> +static long hcall_vphn(unsigned long cpu, __be32 *associativity)\n> +{\n> +\tlong rc;\n> +\tlong retbuf[PLPAR_HCALL9_BUFSIZE] = {0};\n> +\tu64 flags = 1;\n> +\tint hwcpu = get_hard_smp_processor_id(cpu);\n> +\n> +\trc = plpar_hcall9(H_HOME_NODE_ASSOCIATIVITY, retbuf, flags, hwcpu);\n> +\tvphn_unpack_associativity(retbuf, associativity);\n> +\n> +\treturn rc;\n> +}\n> +\n> +static long vphn_get_associativity(unsigned long cpu,\n> +\t\t\t\t\t\t\t\t__be32 *associativity)\n> +{\n> +\tlong rc;\n> +\n> +\trc = hcall_vphn(cpu, associativity);\n> +\n> +\tswitch (rc) {\n> +\tcase H_FUNCTION:\n> +\t\tpr_debug(\"VPHN is not supported. Disabling polling...\\n\");\n> +\t\tstop_topology_update();\n> +\t\tbreak;\n> +\tcase H_HARDWARE:\n> +\t\tprintk(KERN_ERR\n> +\t\t\t\"hcall_vphn() experienced a hardware fault \"\n> +\t\t\t\"preventing VPHN. Disabling polling...\\n\");\n> +\t\tstop_topology_update();\n> +\t\tbreak;\n> +\tcase H_SUCCESS:\n> +\t\tprintk(KERN_INFO\n> +\t\t\t\"VPHN hcall succeeded. Reset polling...\\n\");\n> +\t\ttimed_topology_update(0);\n> +\t\tbreak;\n> +\t}\n> +\n> +\treturn rc;\n> +}\n> +\n> +/*\n> + * Update the CPU maps and sysfs entries for a single CPU when its NUMA\n> + * characteristics change. This function doesn't perform any locking and is\n> + * only safe to call from stop_machine().\n> + */\n> +static int update_cpu_topology(void *data)\n> +{\n> +\tstruct topology_update_data *update;\n> +\tunsigned long cpu;\n> +\n> +\tif (!data)\n> +\t\treturn -EINVAL;\n> +\n> +\tcpu = smp_processor_id();\n> +\n> +\tfor (update = data; update; update = update->next) {\n> +\t\tint new_nid = update->new_nid;\n> +\t\tif (cpu != update->cpu)\n> +\t\t\tcontinue;\n> +\n> +\t\tunmap_cpu_from_node(cpu);\n> +\t\tmap_cpu_to_node(cpu, new_nid);\n> +\t\tset_cpu_numa_node(cpu, new_nid);\n> +\t\tset_cpu_numa_mem(cpu, local_memory_node(new_nid));\n> +\t\tvdso_getcpu_init();\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int update_lookup_table(void *data)\n> +{\n> +\tstruct topology_update_data *update;\n> +\n> +\tif (!data)\n> +\t\treturn -EINVAL;\n> +\n> +\t/*\n> +\t * Upon topology update, the numa-cpu lookup table needs to be updated\n> +\t * for all threads in the core, including offline CPUs, to ensure that\n> +\t * future hotplug operations respect the cpu-to-node associativity\n> +\t * properly.\n> +\t */\n> +\tfor (update = data; update; update = update->next) {\n> +\t\tint nid, base, j;\n> +\n> +\t\tnid = update->new_nid;\n> +\t\tbase = cpu_first_thread_sibling(update->cpu);\n> +\n> +\t\tfor (j = 0; j < threads_per_core; j++) {\n> +\t\t\tupdate_numa_cpu_lookup_table(base + j, nid);\n> +\t\t}\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +/*\n> + * Update the node maps and sysfs entries for each cpu whose home node\n> + * has changed. Returns 1 when the topology has changed, and 0 otherwise.\n> + *\n> + * cpus_locked says whether we already hold cpu_hotplug_lock.\n> + */\n> +int numa_update_cpu_topology(bool cpus_locked)\n> +{\n> +\tunsigned int cpu, sibling, changed = 0;\n> +\tstruct topology_update_data *updates, *ud;\n> +\t__be32 associativity[VPHN_ASSOC_BUFSIZE] = {0};\n> +\tcpumask_t updated_cpus;\n> +\tstruct device *dev;\n> +\tint weight, new_nid, i = 0;\n> +\n> +\tif (!prrn_enabled && !vphn_enabled) {\n> +\t\tif (!topology_inited)\n> +\t\t\ttopology_update_needed = 1;\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tweight = cpumask_weight(&cpu_associativity_changes_mask);\n> +\tif (!weight)\n> +\t\treturn 0;\n> +\n> +\tupdates = kzalloc(weight * (sizeof(*updates)), GFP_KERNEL);\n> +\tif (!updates)\n> +\t\treturn 0;\n> +\n> +\tcpumask_clear(&updated_cpus);\n> +\n> +\tfor_each_cpu(cpu, &cpu_associativity_changes_mask) {\n> +\t\t/*\n> +\t\t * If siblings aren't flagged for changes, updates list\n> +\t\t * will be too short. Skip on this update and set for next\n> +\t\t * update.\n> +\t\t */\n> +\t\tif (!cpumask_subset(cpu_sibling_mask(cpu),\n> +\t\t\t\t\t&cpu_associativity_changes_mask)) {\n> +\t\t\tpr_info(\"Sibling bits not set for associativity \"\n> +\t\t\t\t\t\"change, cpu%d\\n\", cpu);\n> +\t\t\tcpumask_or(&cpu_associativity_changes_mask,\n> +\t\t\t\t\t&cpu_associativity_changes_mask,\n> +\t\t\t\t\tcpu_sibling_mask(cpu));\n> +\t\t\tcpu = cpu_last_thread_sibling(cpu);\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\t/* Use associativity from first thread for all siblings */\n> +\t\tvphn_get_associativity(cpu, associativity);\n> +\t\tnew_nid = associativity_to_nid(associativity);\n> +\t\tif (new_nid < 0 || !node_online(new_nid))\n> +\t\t\tnew_nid = first_online_node;\n> +\n> +\t\tif (new_nid == numa_cpu_lookup_table[cpu]) {\n> +\t\t\tcpumask_andnot(&cpu_associativity_changes_mask,\n> +\t\t\t\t\t&cpu_associativity_changes_mask,\n> +\t\t\t\t\tcpu_sibling_mask(cpu));\n> +\t\t\tcpu = cpu_last_thread_sibling(cpu);\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\tfor_each_cpu(sibling, cpu_sibling_mask(cpu)) {\n> +\t\t\tud = &updates[i++];\n> +\t\t\tud->cpu = sibling;\n> +\t\t\tud->new_nid = new_nid;\n> +\t\t\tud->old_nid = numa_cpu_lookup_table[sibling];\n> +\t\t\tcpumask_set_cpu(sibling, &updated_cpus);\n> +\t\t\tif (i < weight)\n> +\t\t\t\tud->next = &updates[i];\n> +\t\t\telse\n> +\t\t\t\tud->next = NULL;\t/* Don't overrun and use data\n> +\t\t\t\t\t\t\t\t\t * from previous hotplug ops */\n> +\t\t}\n> +\t\tcpu = cpu_last_thread_sibling(cpu);\n> +\t}\n> +\n> +\tpr_debug(\"Topology update for the following CPUs:\\n\");\n> +\tif (cpumask_weight(&updated_cpus)) {\n> +\t\tfor (ud = &updates[0]; ud; ud = ud->next) {\n> +\t\t\tpr_debug(\"cpu %d moving from node %d \"\n> +\t\t\t\t\t  \"to %d\\n\", ud->cpu,\n> +\t\t\t\t\t  ud->old_nid, ud->new_nid);\n> +\t\t}\n> +\t}\n> +\n> +\t/*\n> +\t * In cases where we have nothing to update (because the updates list\n> +\t * is too short or because the new topology is same as the old one),\n> +\t * skip invoking update_cpu_topology() via stop-machine(). This is\n> +\t * necessary (and not just a fast-path optimization) since stop-machine\n> +\t * can end up electing a random CPU to run update_cpu_topology(), and\n> +\t * thus trick us into setting up incorrect cpu-node mappings (since\n> +\t * 'updates' is kzalloc()'ed).\n> +\t *\n> +\t * And for the similar reason, we will skip all the following updating.\n> +\t */\n> +\tif (!cpumask_weight(&updated_cpus))\n> +\t\tgoto out;\n> +\n> +\tif (cpus_locked)\n> +\t\tstop_machine_cpuslocked(update_cpu_topology, &updates[0],\n> +\t\t\t\t\t&updated_cpus);\n> +\telse\n> +\t\tstop_machine(update_cpu_topology, &updates[0], &updated_cpus);\n> +\n> +\t/*\n> +\t * Update the numa-cpu lookup table with the new mappings, even for\n> +\t * offline CPUs. It is best to perform this update from the stop-\n> +\t * machine context.\n> +\t */\n> +\tif (cpus_locked)\n> +\t\tstop_machine_cpuslocked(update_lookup_table, &updates[0],\n> +\t\t\t\t\tcpumask_of(raw_smp_processor_id()));\n> +\telse\n> +\t\tstop_machine(update_lookup_table, &updates[0],\n> +\t\t\t     cpumask_of(raw_smp_processor_id()));\n> +\n> +\tfor (ud = &updates[0]; ud; ud = ud->next) {\n> +\t\tunregister_cpu_under_node(ud->cpu, ud->old_nid);\n> +\t\tregister_cpu_under_node(ud->cpu, ud->new_nid);\n> +\n> +\t\tdev = get_cpu_device(ud->cpu);\n> +\t\tif (dev)\n> +\t\t\tkobject_uevent(&dev->kobj, KOBJ_CHANGE);\n> +\t\tcpumask_clear_cpu(ud->cpu, &cpu_associativity_changes_mask);\n> +\t\tchanged = 1;\n> +\t}\n> +\n> +out:\n> +\tkfree(updates);\n> +\ttopology_update_needed = 0;\n> +\treturn changed;\n> +}\n> +\n> +int arch_update_cpu_topology(void)\n> +{\n> +\tlockdep_assert_cpus_held();\n> +\treturn numa_update_cpu_topology(true);\n> +}\n> +\n> +static void topology_work_fn(struct work_struct *work)\n> +{\n> +\trebuild_sched_domains();\n> +}\n> +static DECLARE_WORK(topology_work, topology_work_fn);\n> +\n> +static void topology_schedule_update(void)\n> +{\n> +\tschedule_work(&topology_work);\n> +}\n> +\n> +static int shared_topology_update(void)\n> +{\n> +\tif (firmware_has_feature(FW_FEATURE_VPHN) &&\n> +\t\t   lppaca_shared_proc(get_lppaca()))\n> +\t\ttopology_schedule_update();\n> +\n> +\treturn 0;\n> +}\n> +device_initcall(shared_topology_update);\n> +\n> +static void topology_timer_fn(unsigned long ignored)\n> +{\n> +\tif (prrn_enabled && cpumask_weight(&cpu_associativity_changes_mask))\n> +\t\ttopology_schedule_update();\n> +\telse if (vphn_enabled) {\n> +\t\tif (update_cpu_associativity_changes_mask() > 0)\n> +\t\t\ttopology_schedule_update();\n> +\t\treset_topology_timer();\n> +\t}\n> +}\n> +static struct timer_list topology_timer =\n> +\tTIMER_INITIALIZER(topology_timer_fn, 0, 0);\n> +\n> +static void reset_topology_timer(void)\n> +{\n> +\ttopology_timer.data = 0;\n> +\ttopology_timer.expires = jiffies + topology_timer_secs * HZ;\n> +\tmod_timer(&topology_timer, topology_timer.expires);\n> +}\n> +\n> +#ifdef CONFIG_SMP\n> +\n> +static void stage_topology_update(int core_id)\n> +{\n> +\tcpumask_or(&cpu_associativity_changes_mask,\n> +\t\t&cpu_associativity_changes_mask, cpu_sibling_mask(core_id));\n> +\treset_topology_timer();\n> +}\n> +\n> +static int dt_update_callback(struct notifier_block *nb,\n> +\t\t\t\tunsigned long action, void *data)\n> +{\n> +\tstruct of_reconfig_data *update = data;\n> +\tint rc = NOTIFY_DONE;\n> +\n> +\tswitch (action) {\n> +\tcase OF_RECONFIG_UPDATE_PROPERTY:\n> +\t\tif (!of_prop_cmp(update->dn->type, \"cpu\") &&\n> +\t\t    !of_prop_cmp(update->prop->name, \"ibm,associativity\")) {\n> +\t\t\tu32 core_id;\n> +\t\t\tof_property_read_u32(update->dn, \"reg\", &core_id);\n> +\t\t\tstage_topology_update(core_id);\n> +\t\t\trc = NOTIFY_OK;\n> +\t\t}\n> +\t\tbreak;\n> +\t}\n> +\n> +\treturn rc;\n> +}\n> +\n> +static struct notifier_block dt_update_nb = {\n> +\t.notifier_call = dt_update_callback,\n> +};\n> +\n> +#endif\n> +\n> +/*\n> + * Start polling for associativity changes.\n> + */\n> +int start_topology_update(void)\n> +{\n> +\tint rc = 0;\n> +\n> +\tif (firmware_has_feature(FW_FEATURE_PRRN)) {\n> +\t\tif (!prrn_enabled) {\n> +\t\t\tprrn_enabled = 1;\n> +#ifdef CONFIG_SMP\n> +\t\t\trc = of_reconfig_notifier_register(&dt_update_nb);\n> +#endif\n> +\t\t}\n> +\t}\n> +\tif (firmware_has_feature(FW_FEATURE_VPHN) &&\n> +\t\t   lppaca_shared_proc(get_lppaca())) {\n> +\t\tif (!vphn_enabled) {\n> +\t\t\tvphn_enabled = 1;\n> +\t\t\tsetup_cpu_associativity_change_counters();\n> +\t\t\tinit_timer_deferrable(&topology_timer);\n> +\t\t\treset_topology_timer();\n> +\t\t}\n> +\t}\n> +\n> +\treturn rc;\n> +}\n> +\n> +/*\n> + * Disable polling for VPHN associativity changes.\n> + */\n> +int stop_topology_update(void)\n> +{\n> +\tint rc = 0;\n> +\n> +\tif (prrn_enabled) {\n> +\t\tprrn_enabled = 0;\n> +#ifdef CONFIG_SMP\n> +\t\trc = of_reconfig_notifier_unregister(&dt_update_nb);\n> +#endif\n> +\t}\n> +\tif (vphn_enabled) {\n> +\t\tvphn_enabled = 0;\n> +\t\trc = del_timer_sync(&topology_timer);\n> +\t}\n> +\n> +\treturn rc;\n> +}\n> +\n> +int prrn_is_enabled(void)\n> +{\n> +\treturn prrn_enabled;\n> +}\n> +\n> +static int topology_read(struct seq_file *file, void *v)\n> +{\n> +\tif (vphn_enabled || prrn_enabled)\n> +\t\tseq_puts(file, \"on\\n\");\n> +\telse\n> +\t\tseq_puts(file, \"off\\n\");\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int topology_open(struct inode *inode, struct file *file)\n> +{\n> +\treturn single_open(file, topology_read, NULL);\n> +}\n> +\n> +static ssize_t topology_write(struct file *file, const char __user *buf,\n> +\t\t\t      size_t count, loff_t *off)\n> +{\n> +\tchar kbuf[4]; /* \"on\" or \"off\" plus null. */\n> +\tint read_len;\n> +\n> +\tread_len = count < 3 ? count : 3;\n> +\tif (copy_from_user(kbuf, buf, read_len))\n> +\t\treturn -EINVAL;\n> +\n> +\tkbuf[read_len] = '\\0';\n> +\n> +\tif (!strncmp(kbuf, \"on\", 2))\n> +\t\tstart_topology_update();\n> +\telse if (!strncmp(kbuf, \"off\", 3))\n> +\t\tstop_topology_update();\n> +\telse\n> +\t\treturn -EINVAL;\n> +\n> +\treturn count;\n> +}\n> +\n> +static const struct file_operations topology_ops = {\n> +\t.read = seq_read,\n> +\t.write = topology_write,\n> +\t.open = topology_open,\n> +\t.release = single_release\n> +};\n> +\n> +static int topology_update_init(void)\n> +{\n> +\t/* Do not poll for changes if disabled at boot */\n> +\tif (topology_updates_enabled)\n> +\t\tstart_topology_update();\n> +\n> +\tif (!proc_create(\"powerpc/topology_updates\", 0644, NULL, &topology_ops))\n> +\t\treturn -ENOMEM;\n> +\n> +\ttopology_inited = 1;\n> +\tif (topology_update_needed)\n> +\t\tbitmap_fill(cpumask_bits(&cpu_associativity_changes_mask),\n> +\t\t\t\t\tnr_cpumask_bits);\n> +\n> +\treturn 0;\n> +}\n> +device_initcall(topology_update_init);\n> +#endif /* CONFIG_PPC_SPLPAR */\n> diff --git a/arch/powerpc/mm/vphn.h b/arch/powerpc/mm/vphn.h\n> index fe8b780..a8ec93b 100644\n> --- a/arch/powerpc/mm/vphn.h\n> +++ b/arch/powerpc/mm/vphn.h\n> @@ -5,6 +5,10 @@\n>   */\n>  #define VPHN_REGISTER_COUNT 6\n> \n> +/* Maximum number of affinity reference points supported by NUMA/VPHN.\n> + */\n> +#define MAX_DISTANCE_REF_POINTS 4\n> +\n>  /*\n>   * 6 64-bit registers unpacked into up to 24 be32 associativity values. To\n>   * form the complete property we have to add the length in the first cell.\n> diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c\n> index 6afd1ef..5a7fb1e 100644\n> --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c\n> +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c\n> @@ -356,6 +356,7 @@ static int dlpar_online_cpu(struct device_node *dn)\n>  \t\t\tBUG_ON(get_cpu_current_state(cpu)\n>  \t\t\t\t\t!= CPU_STATE_OFFLINE);\n>  \t\t\tcpu_maps_update_done();\n> +\t\t\ttimed_topology_update(1);\n>  \t\t\trc = device_online(get_cpu_device(cpu));\n>  \t\t\tif (rc)\n>  \t\t\t\tgoto out;\n> @@ -522,6 +523,7 @@ static int dlpar_offline_cpu(struct device_node *dn)\n>  \t\t\t\tset_preferred_offline_state(cpu,\n>  \t\t\t\t\t\t\t    CPU_STATE_OFFLINE);\n>  \t\t\t\tcpu_maps_update_done();\n> +\t\t\t\ttimed_topology_update(1);\n>  \t\t\t\trc = device_offline(get_cpu_device(cpu));\n>  \t\t\t\tif (rc)\n>  \t\t\t\t\tgoto out;\n>","headers":{"Return-Path":"<linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org>","X-Original-To":["patchwork-incoming@ozlabs.org","linuxppc-dev@lists.ozlabs.org"],"Delivered-To":["patchwork-incoming@ozlabs.org","linuxppc-dev@lists.ozlabs.org"],"Received":["from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68])\n\t(using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xgxwx4Xrqz9sNr\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 29 Aug 2017 02:26:41 +1000 (AEST)","from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3xgxwx3RyczDqJs\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 29 Aug 2017 02:26:41 +1000 (AEST)","from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com\n\t[148.163.158.5])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby lists.ozlabs.org (Postfix) with ESMTPS id 3xgxvF6hvQzDq5m\n\tfor <linuxppc-dev@lists.ozlabs.org>;\n\tTue, 29 Aug 2017 02:25:13 +1000 (AEST)","from pps.filterd (m0098421.ppops.net [127.0.0.1])\n\tby mx0a-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv7SGNkn8136797\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 28 Aug 2017 12:25:10 -0400","from e15.ny.us.ibm.com (e15.ny.us.ibm.com [129.33.205.205])\n\tby mx0a-001b2d01.pphosted.com with ESMTP id 2cmnjpc3jk-1\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT)\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 28 Aug 2017 12:25:09 -0400","from localhost\n\tby e15.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use\n\tOnly! Violators will be prosecuted\n\tfor <linuxppc-dev@lists.ozlabs.org> from <nfont@linux.vnet.ibm.com>; \n\tMon, 28 Aug 2017 12:25:09 -0400","from b01cxnp22036.gho.pok.ibm.com (9.57.198.26)\n\tby e15.ny.us.ibm.com (146.89.104.202) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tMon, 28 Aug 2017 12:25:06 -0400","from b01ledav003.gho.pok.ibm.com (b01ledav003.gho.pok.ibm.com\n\t[9.57.199.108])\n\tby b01cxnp22036.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP\n\tid v7SGP6eb31457300; Mon, 28 Aug 2017 16:25:06 GMT","from b01ledav003.gho.pok.ibm.com (unknown [127.0.0.1])\n\tby IMSVA (Postfix) with ESMTP id 57DAFB2054;\n\tMon, 28 Aug 2017 12:22:30 -0400 (EDT)","from [9.41.92.186] (unknown [9.41.92.186])\n\tby b01ledav003.gho.pok.ibm.com (Postfix) with ESMTP id C6B7AB204E;\n\tMon, 28 Aug 2017 12:22:29 -0400 (EDT)"],"Subject":"Re: [PATCH V10 1/2] powerpc/numa: Update CPU topology when VPHN\n\tenabled","To":"Michael Bringmann <mwb@linux.vnet.ibm.com>, linuxppc-dev@lists.ozlabs.org,\n\tlinux-kernel@vger.kernel.org","References":"<6a89709d-ee0f-80bf-27fb-c76dde5cde2f@linux.vnet.ibm.com>","From":"Nathan Fontenot <nfont@linux.vnet.ibm.com>","Date":"Mon, 28 Aug 2017 11:25:05 -0500","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101\n\tThunderbird/52.2.1","MIME-Version":"1.0","In-Reply-To":"<6a89709d-ee0f-80bf-27fb-c76dde5cde2f@linux.vnet.ibm.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-US","Content-Transfer-Encoding":"7bit","X-TM-AS-GCONF":"00","x-cbid":"17082816-0036-0000-0000-000002601203","X-IBM-SpamModules-Scores":"","X-IBM-SpamModules-Versions":"BY=3.00007628; HX=3.00000241; KW=3.00000007;\n\tPH=3.00000004; SC=3.00000226; SDB=6.00908870; UDB=6.00455755;\n\tIPR=6.00689122; \n\tBA=6.00005557; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009;\n\tZB=6.00000000; \n\tZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00016902;\n\tXFM=3.00000015; UTC=2017-08-28 16:25:08","X-IBM-AV-DETECTION":"SAVI=unused REMOTE=unused XFE=unused","x-cbparentid":"17082816-0037-0000-0000-000041956794","Message-Id":"<d5b7a976-b0a6-a4d6-c062-75d65d8a6eac@linux.vnet.ibm.com>","X-Proofpoint-Virus-Version":"vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-08-28_09:, , signatures=0","X-Proofpoint-Spam-Details":"rule=outbound_notspam policy=outbound score=0\n\tspamscore=0 suspectscore=0\n\tmalwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam\n\tadjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000\n\tdefinitions=main-1708280262","X-BeenThere":"linuxppc-dev@lists.ozlabs.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"Linux on PowerPC Developers Mail List\n\t<linuxppc-dev.lists.ozlabs.org>","List-Unsubscribe":"<https://lists.ozlabs.org/options/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@lists.ozlabs.org?subject=unsubscribe>","List-Archive":"<http://lists.ozlabs.org/pipermail/linuxppc-dev/>","List-Post":"<mailto:linuxppc-dev@lists.ozlabs.org>","List-Help":"<mailto:linuxppc-dev-request@lists.ozlabs.org?subject=help>","List-Subscribe":"<https://lists.ozlabs.org/listinfo/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@lists.ozlabs.org?subject=subscribe>","Cc":"John Allen <jallen@linux.vnet.ibm.com>","Errors-To":"linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org","Sender":"\"Linuxppc-dev\"\n\t<linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org>"}}]