Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/806840/?format=api
{ "id": 806840, "url": "http://patchwork.ozlabs.org/api/patches/806840/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/b631b666-91c9-863e-9b74-26cc0c39986e@linux.vnet.ibm.com/", "project": { "id": 2, "url": "http://patchwork.ozlabs.org/api/projects/2/?format=api", "name": "Linux PPC development", "link_name": "linuxppc-dev", "list_id": "linuxppc-dev.lists.ozlabs.org", "list_email": "linuxppc-dev@lists.ozlabs.org", "web_url": "https://github.com/linuxppc/wiki/wiki", "scm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git", "webscm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/", "list_archive_url": "https://lore.kernel.org/linuxppc-dev/", "list_archive_url_format": "https://lore.kernel.org/linuxppc-dev/{}/", "commit_url_format": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/commit/?id={}" }, "msgid": "<b631b666-91c9-863e-9b74-26cc0c39986e@linux.vnet.ibm.com>", "list_archive_url": "https://lore.kernel.org/linuxppc-dev/b631b666-91c9-863e-9b74-26cc0c39986e@linux.vnet.ibm.com/", "date": "2017-08-29T00:33:03", "name": "[V11,3/3] powerpc/vphn: Better integrate vphn source code", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": true, "hash": "c750fd3b2972b259c39d764f7498abdce1b04e0e", "submitter": { "id": 65104, "url": "http://patchwork.ozlabs.org/api/people/65104/?format=api", "name": "Michael Bringmann", "email": "mwb@linux.vnet.ibm.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/b631b666-91c9-863e-9b74-26cc0c39986e@linux.vnet.ibm.com/mbox/", "series": [ { "id": 282, "url": "http://patchwork.ozlabs.org/api/series/282/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/list/?series=282", "date": "2017-08-29T00:32:02", "name": "powerpc/dlpar: Correct display of hot-add/hot-remove CPUs and memory", "version": 11, "mbox": "http://patchwork.ozlabs.org/series/282/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/806840/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/806840/checks/", "tags": {}, "related": [], "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 [IPv6:2401:3900:2:1::3])\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 3xh8qX2kBRz9s4s\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 29 Aug 2017 10:37:44 +1000 (AEST)", "from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3xh8qX1S6XzDqkQ\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 29 Aug 2017 10:37:44 +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 3xh8kJ0mRvzDqJ9\n\tfor <linuxppc-dev@lists.ozlabs.org>;\n\tTue, 29 Aug 2017 10:33:11 +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\tv7T0TC31112326\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 28 Aug 2017 20:33:10 -0400", "from e32.co.us.ibm.com (e32.co.us.ibm.com [32.97.110.150])\n\tby mx0a-001b2d01.pphosted.com with ESMTP id 2cmurndf2g-1\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT)\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 28 Aug 2017 20:33:09 -0400", "from localhost\n\tby e32.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use\n\tOnly! Violators will be prosecuted\n\tfor <linuxppc-dev@lists.ozlabs.org> from <mwb@linux.vnet.ibm.com>;\n\tMon, 28 Aug 2017 18:33:08 -0600", "from b03cxnp07029.gho.boulder.ibm.com (9.17.130.16)\n\tby e32.co.us.ibm.com (192.168.1.132) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tMon, 28 Aug 2017 18:33:05 -0600", "from b03ledav001.gho.boulder.ibm.com\n\t(b03ledav001.gho.boulder.ibm.com [9.17.130.232])\n\tby b03cxnp07029.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with\n\tESMTP id v7T0X5Yk8192500; Mon, 28 Aug 2017 17:33:05 -0700", "from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1])\n\tby IMSVA (Postfix) with ESMTP id 314BC6E03A;\n\tMon, 28 Aug 2017 18:33:05 -0600 (MDT)", "from oc1554177480.ibm.com (unknown [9.80.214.231])\n\tby b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP id E1F7B6E03D;\n\tMon, 28 Aug 2017 18:33:03 -0600 (MDT)" ], "To": "linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org", "In-Reply-To": "<27ed5a3a-e2d5-fc6d-9a3b-735430faa9da@linux.vnet.ibm.com>", "From": "Michael Bringmann <mwb@linux.vnet.ibm.com>", "Subject": "[PATCH V11 3/3] powerpc/vphn: Better integrate vphn source code", "Organization": "IBM Linux Technology Center", "Date": "Mon, 28 Aug 2017 19:33:03 -0500", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101\n\tThunderbird/52.2.0", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=utf-8", "Content-Language": "en-US", "Content-Transfer-Encoding": "7bit", "X-TM-AS-GCONF": "00", "x-cbid": "17082900-0004-0000-0000-000012D6D7A0", "X-IBM-SpamModules-Scores": "", "X-IBM-SpamModules-Versions": "BY=3.00007630; HX=3.00000241; KW=3.00000007;\n\tPH=3.00000004; SC=3.00000226; SDB=6.00909033; UDB=6.00455852;\n\tIPR=6.00689284; \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.00016909;\n\tXFM=3.00000015; UTC=2017-08-29 00:33:07", "X-IBM-AV-DETECTION": "SAVI=unused REMOTE=unused XFE=unused", "x-cbparentid": "17082900-0005-0000-0000-000080E5A74E", "Message-Id": "<b631b666-91c9-863e-9b74-26cc0c39986e@linux.vnet.ibm.com>", "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-08-28_13:, , 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-1708290005", "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": "Nathan Fontenot <nfont@linux.vnet.ibm.com>,\n\tMichael Bringmann <mwb@linux.vnet.ibm.com>,\n\tJohn 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>" }, "content": "powerpc/vphn: Reorganize source code in order to better distinguish the\nVPHN code from the NUMA code better, by moving relevant functions to\nappropriate files.\n\nSigned-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>\n---\n arch/powerpc/include/asm/topology.h | 6 \n arch/powerpc/mm/numa.c | 550 +------------------------------\n arch/powerpc/mm/vphn.c | 574 ++++++++++++++++++++++++++++++++\n arch/powerpc/platforms/pseries/dlpar.c | 2 \n 4 files changed, 583 insertions(+), 549 deletions(-)", "diff": "diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h\nindex 85d6428..600e1c6 100644\n--- a/arch/powerpc/include/asm/topology.h\n+++ b/arch/powerpc/include/asm/topology.h\n@@ -106,12 +106,6 @@ static inline int prrn_is_enabled(void)\n #endif /* CONFIG_PPC_SPLPAR */\n #endif /* CONFIG_HOTPLUG_CPU || CONFIG_NEED_MULTIPLE_NODES */\n \n-#if defined(CONFIG_PPC_SPLPAR)\n-extern void shared_topology_update(void);\n-#else\n-#define\tshared_topology_update()\t0\n-#endif /* CONFIG_PPC_SPLPAR */\n-\n #include <asm-generic/topology.h>\n \n #ifdef CONFIG_SMP\ndiff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c\nindex 2e8258a..a66f0da 100644\n--- a/arch/powerpc/mm/numa.c\n+++ b/arch/powerpc/mm/numa.c\n@@ -42,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@@ -61,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@@ -143,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@@ -159,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@@ -234,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@@ -1001,8 +1004,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@@ -1179,536 +1180,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-#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 vphn_enabled;\n-static int prrn_enabled;\n-static void reset_topology_timer(void);\n-static int topology_timer_secs = TOPOLOGY_DEF_TIMER_SECS;\n-static int topology_inited;\n-static int topology_update_needed;\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__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\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\tpr_info(\"Assoc chg gives same node %d for cpu%d\\n\",\n-\t\t\t\t\tnew_nid, 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;\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-void 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-EXPORT_SYMBOL(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 */\ndiff --git a/arch/powerpc/mm/vphn.c b/arch/powerpc/mm/vphn.c\nindex 5f8ef50..3859c9c 100644\n--- a/arch/powerpc/mm/vphn.c\n+++ b/arch/powerpc/mm/vphn.c\n@@ -1,6 +1,70 @@\n+/*\n+ * pSeries VPHN support\n+ *\n+ * Copyright (C) 2015 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+#define pr_fmt(fmt) \"vphn: \" fmt\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 #include <asm/byteorder.h>\n+\n+/* Virtual Processor Home Node (VPHN) support */\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+#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 vphn_enabled;\n+static int prrn_enabled;\n+static void reset_topology_timer(void);\n+static int topology_timer_secs = TOPOLOGY_DEF_TIMER_SECS;\n+static int topology_inited;\n+static int topology_update_needed;\n+\n /*\n * The associativity domain numbers are returned from the hypervisor as a\n * stream of mixed 16-bit and 32-bit fields. The stream is terminated by the\n@@ -68,3 +132,513 @@ int vphn_unpack_associativity(const long *packed, __be32 *unpacked)\n \n \treturn nr_assoc_doms;\n }\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__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\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\tpr_info(\"Assoc chg gives same node %d for cpu%d\\n\",\n+\t\t\t\t\tnew_nid, 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+\tif (i)\n+\t\tupdates[i-1].next = NULL;\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 void 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+\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 */\ndiff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c\nindex ba9a4a0..3918769 100644\n--- a/arch/powerpc/platforms/pseries/dlpar.c\n+++ b/arch/powerpc/platforms/pseries/dlpar.c\n@@ -592,8 +592,6 @@ static ssize_t dlpar_show(struct class *class, struct class_attribute *attr,\n \n static int __init pseries_dlpar_init(void)\n {\n-\tshared_topology_update();\n-\n \tpseries_hp_wq = alloc_workqueue(\"pseries hotplug workqueue\",\n \t\t\t\t\tWQ_UNBOUND, 1);\n \treturn sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);\n", "prefixes": [ "V11", "3/3" ] }