get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.2/patches/805683/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 805683,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/805683/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/6a89709d-ee0f-80bf-27fb-c76dde5cde2f@linux.vnet.ibm.com/",
    "project": {
        "id": 2,
        "url": "http://patchwork.ozlabs.org/api/1.2/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": "<6a89709d-ee0f-80bf-27fb-c76dde5cde2f@linux.vnet.ibm.com>",
    "list_archive_url": "https://lore.kernel.org/linuxppc-dev/6a89709d-ee0f-80bf-27fb-c76dde5cde2f@linux.vnet.ibm.com/",
    "date": "2017-08-24T22:07:43",
    "name": "[V10,1/2] powerpc/numa: Update CPU topology when VPHN enabled",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "0f5bae2f39502238ebe08065c925758c44614c07",
    "submitter": {
        "id": 65104,
        "url": "http://patchwork.ozlabs.org/api/1.2/people/65104/?format=api",
        "name": "Michael Bringmann",
        "email": "mwb@linux.vnet.ibm.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/6a89709d-ee0f-80bf-27fb-c76dde5cde2f@linux.vnet.ibm.com/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/805683/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/805683/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 3xddlb1LC3z9t3Z\n\tfor <patchwork-incoming@ozlabs.org>;\n\tFri, 25 Aug 2017 08:10:35 +1000 (AEST)",
            "from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3xddlb0142zDrLQ\n\tfor <patchwork-incoming@ozlabs.org>;\n\tFri, 25 Aug 2017 08:10:35 +1000 (AEST)",
            "from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com\n\t[148.163.156.1])\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 3xddhT0RdczDrKr\n\tfor <linuxppc-dev@lists.ozlabs.org>;\n\tFri, 25 Aug 2017 08:07:52 +1000 (AEST)",
            "from pps.filterd (m0098410.ppops.net [127.0.0.1])\n\tby mx0a-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv7OM7kKQ078080\n\tfor <linuxppc-dev@lists.ozlabs.org>; Thu, 24 Aug 2017 18:07:50 -0400",
            "from e33.co.us.ibm.com (e33.co.us.ibm.com [32.97.110.151])\n\tby mx0a-001b2d01.pphosted.com with ESMTP id 2cj5s150r3-1\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT)\n\tfor <linuxppc-dev@lists.ozlabs.org>; Thu, 24 Aug 2017 18:07:50 -0400",
            "from localhost\n\tby e33.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\tThu, 24 Aug 2017 16:07:49 -0600",
            "from b03cxnp08026.gho.boulder.ibm.com (9.17.130.18)\n\tby e33.co.us.ibm.com (192.168.1.133) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tThu, 24 Aug 2017 16:07:46 -0600",
            "from b03ledav001.gho.boulder.ibm.com\n\t(b03ledav001.gho.boulder.ibm.com [9.17.130.232])\n\tby b03cxnp08026.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with\n\tESMTP id v7OM7kxJ60489924; Thu, 24 Aug 2017 15:07:46 -0700",
            "from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1])\n\tby IMSVA (Postfix) with ESMTP id E9E0E6E035;\n\tThu, 24 Aug 2017 16:07:45 -0600 (MDT)",
            "from oc1554177480.ibm.com (unknown [9.80.214.231])\n\tby b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP id A028D6E03D;\n\tThu, 24 Aug 2017 16:07:44 -0600 (MDT)"
        ],
        "To": "linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org",
        "From": "Michael Bringmann <mwb@linux.vnet.ibm.com>",
        "Subject": "[PATCH V10 1/2] powerpc/numa: Update CPU topology when VPHN enabled",
        "Organization": "IBM Linux Technology Center",
        "In-Reply-To": "<db1b23c1-67bc-fb0f-51f9-af4bc564d9ef@linux.vnet.ibm.com>",
        "Date": "Thu, 24 Aug 2017 17:07:43 -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": "8bit",
        "X-TM-AS-GCONF": "00",
        "x-cbid": "17082422-0008-0000-0000-00000878CACE",
        "X-IBM-SpamModules-Scores": "",
        "X-IBM-SpamModules-Versions": "BY=3.00007605; HX=3.00000241; KW=3.00000007;\n\tPH=3.00000004; SC=3.00000225; SDB=6.00907146; UDB=6.00454739;\n\tIPR=6.00687343; \n\tBA=6.00005552; 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.00016852;\n\tXFM=3.00000015; UTC=2017-08-24 22:07:48",
        "X-IBM-AV-DETECTION": "SAVI=unused REMOTE=unused XFE=unused",
        "x-cbparentid": "17082422-0009-0000-0000-000043B365A7",
        "Message-Id": "<6a89709d-ee0f-80bf-27fb-c76dde5cde2f@linux.vnet.ibm.com>",
        "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-08-24_08:, , 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-1708240340",
        "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/numa: Correct the currently broken capability to set the\ntopology for shared CPUs in LPARs.  At boot time for shared CPU\nlpars, the topology for each shared CPU is set to node zero, however,\nthis is now updated correctly using the Virtual Processor Home Node\n(VPHN) capabilities information provided by the pHyp.\n\nAlso, update initialization checks for device-tree attributes to\nindependently recognize PRRN or VPHN usage.\n\nFinally, try to distinguish the VPHN code from the NUMA code better,\nand move relevant functions to another file.\n\nSigned-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>\n---\nChanges 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(-)",
    "diff": "diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h\nindex 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\ndiff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c\nindex 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 */\ndiff --git a/arch/powerpc/mm/vphn.c b/arch/powerpc/mm/vphn.c\nindex 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 */\ndiff --git a/arch/powerpc/mm/vphn.h b/arch/powerpc/mm/vphn.h\nindex 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.\ndiff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c\nindex 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",
    "prefixes": [
        "V10",
        "1/2"
    ]
}