Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/783388/?format=api
{ "id": 783388, "url": "http://patchwork.ozlabs.org/api/patches/783388/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/1499074728-30680-2-git-send-email-anju@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": "<1499074728-30680-2-git-send-email-anju@linux.vnet.ibm.com>", "list_archive_url": "https://lore.kernel.org/linuxppc-dev/1499074728-30680-2-git-send-email-anju@linux.vnet.ibm.com/", "date": "2017-07-03T09:38:47", "name": "[v12,07/10] powerpc/perf: PMU functions for Core IMC and hotplugging", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": true, "hash": "d153226b569aeecc52fa468b9084af9d074ec5f6", "submitter": { "id": 67491, "url": "http://patchwork.ozlabs.org/api/people/67491/?format=api", "name": "Anju T Sudhakar", "email": "anju@linux.vnet.ibm.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/1499074728-30680-2-git-send-email-anju@linux.vnet.ibm.com/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/783388/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/783388/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 [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 3x1Mqd5xhtz9s65\n\tfor <patchwork-incoming@ozlabs.org>;\n\tMon, 3 Jul 2017 19:52:13 +1000 (AEST)", "from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3x1Mqd57TpzDrc4\n\tfor <patchwork-incoming@ozlabs.org>;\n\tMon, 3 Jul 2017 19:52:13 +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 3x1Mb90v60zDrCM\n\tfor <linuxppc-dev@lists.ozlabs.org>;\n\tMon, 3 Jul 2017 19:41:24 +1000 (AEST)", "from pps.filterd (m0098421.ppops.net [127.0.0.1])\n\tby mx0a-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id\n\tv639dPdJ077859\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 3 Jul 2017 05:41:21 -0400", "from e23smtp06.au.ibm.com (e23smtp06.au.ibm.com [202.81.31.148])\n\tby mx0a-001b2d01.pphosted.com with ESMTP id 2beytt3eyc-1\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT)\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 03 Jul 2017 05:41:20 -0400", "from localhost\n\tby e23smtp06.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use\n\tOnly! Violators will be prosecuted\n\tfor <linuxppc-dev@lists.ozlabs.org> from <anju@linux.vnet.ibm.com>;\n\tMon, 3 Jul 2017 19:41:16 +1000", "from d23relay10.au.ibm.com (202.81.31.229)\n\tby e23smtp06.au.ibm.com (202.81.31.212) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tMon, 3 Jul 2017 19:41:10 +1000", "from d23av05.au.ibm.com (d23av05.au.ibm.com [9.190.234.119])\n\tby d23relay10.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id\n\tv639dibv5701952\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 3 Jul 2017 19:39:52 +1000", "from d23av05.au.ibm.com (localhost [127.0.0.1])\n\tby d23av05.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id\n\tv639dJFB025288\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 3 Jul 2017 19:39:19 +1000", "from xenial-xerus.in.ibm.com (xenial-xerus.in.ibm.com [9.124.35.20]\n\t(may be forged))\n\tby d23av05.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id\n\tv639dCsv024325; Mon, 3 Jul 2017 19:39:16 +1000" ], "From": "Anju T Sudhakar <anju@linux.vnet.ibm.com>", "To": "mpe@ellerman.id.au", "Subject": "[PATCH v12 07/10] powerpc/perf: PMU functions for Core IMC and\n\thotplugging", "Date": "Mon, 3 Jul 2017 15:08:47 +0530", "X-Mailer": "git-send-email 2.7.4", "In-Reply-To": "<1499074728-30680-1-git-send-email-anju@linux.vnet.ibm.com>", "References": "<1499074728-30680-1-git-send-email-anju@linux.vnet.ibm.com>", "X-TM-AS-MML": "disable", "x-cbid": "17070309-0040-0000-0000-0000033B6EB4", "X-IBM-AV-DETECTION": "SAVI=unused REMOTE=unused XFE=unused", "x-cbparentid": "17070309-0041-0000-0000-00000CB691AE", "Message-Id": "<1499074728-30680-2-git-send-email-anju@linux.vnet.ibm.com>", "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-07-03_06:, , signatures=0", "X-Proofpoint-Spam-Details": "rule=outbound_notspam policy=outbound score=0\n\tspamscore=0 suspectscore=3\n\tmalwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam\n\tadjust=0 reason=mlx scancount=1 engine=8.0.1-1703280000\n\tdefinitions=main-1707030161", "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": "stewart@linux.vnet.ibm.com, ego@linux.vnet.ibm.com, mikey@neuling.org,\n\tmaddy@linux.vnet.ibm.com, hemant@linux.vnet.ibm.com,\n\tlinux-kernel@vger.kernel.org, eranian@google.com,\n\tanju@linux.vnet.ibm.com, \n\tanton@samba.org, tglx@linutronix.de, sukadev@linux.vnet.ibm.com,\n\tlinuxppc-dev@lists.ozlabs.org, dja@axtens.net", "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": "From: Madhavan Srinivasan <maddy@linux.vnet.ibm.com> \n \nCode to add PMU function to initialize a core IMC event. It also \nadds cpumask initialization function for core IMC PMU. For \ninitialization, memory is allocated per core where the data \nfor core IMC counters will be accumulated. The base address for this \npage is sent to OPAL via an OPAL call which initializes various SCOMs \nrelated to Core IMC initialization. Upon any errors, the pages are \nfree'ed and core IMC counters are disabled using the same OPAL call. \n \nFor CPU hotplugging, a cpumask is initialized which contains an online \nCPU from each core. If a cpu goes offline, we check whether that cpu \nbelongs to the core imc cpumask, if yes, then, we migrate the PMU \ncontext to any other online cpu (if available) in that core. If a cpu \ncomes back online, then this cpu will be added to the core imc cpumask \nonly if there was no other cpu from that core in the previous cpumask. \n \nTo register the hotplug functions for core_imc, a new state \nCPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE is added to the list of existing \nstates. \n \nPatch also adds OPAL device shutdown callback. Needed to disable the \nIMC core engine to handle kexec. \n \nSigned-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com> \nSigned-off-by: Anju T Sudhakar <anju@linux.vnet.ibm.com> \nSigned-off-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com> \n---\n arch/powerpc/include/asm/opal-api.h | 1 +\n arch/powerpc/perf/imc-pmu.c | 371 +++++++++++++++++++++++++++---\n arch/powerpc/platforms/powernv/opal-imc.c | 25 ++\n include/linux/cpuhotplug.h | 1 +\n 4 files changed, 371 insertions(+), 27 deletions(-)", "diff": "diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h\nindex fdacb030cd77..0d83427b7467 100644\n--- a/arch/powerpc/include/asm/opal-api.h\n+++ b/arch/powerpc/include/asm/opal-api.h\n@@ -1009,6 +1009,7 @@ enum {\n /* Argument to OPAL_IMC_COUNTERS_* */\n enum {\n \tOPAL_IMC_COUNTERS_NEST = 1,\n+\tOPAL_IMC_COUNTERS_CORE = 2,\n };\n \n #endif /* __ASSEMBLY__ */\ndiff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c\nindex 041d3097d42a..c1a275ed2510 100644\n--- a/arch/powerpc/perf/imc-pmu.c\n+++ b/arch/powerpc/perf/imc-pmu.c\n@@ -1,5 +1,5 @@\n /*\n- * Nest Performance Monitor counter support.\n+ * IMC Performance Monitor counter support.\n *\n * Copyright (C) 2017 Madhavan Srinivasan, IBM Corporation.\n * (C) 2017 Anju T Sudhakar, IBM Corporation.\n@@ -21,6 +21,7 @@\n /* Needed for sanity check */\n struct imc_pmu *per_nest_pmu_arr[IMC_MAX_PMUS];\n static cpumask_t nest_imc_cpumask;\n+static cpumask_t core_imc_cpumask;\n static int nest_imc_cpumask_initialized;\n static int nest_pmus;\n /*\n@@ -30,7 +31,7 @@ static int nest_pmus;\n static DEFINE_MUTEX(imc_nest_inited_reserve);\n \n struct imc_pmu_ref *nest_imc_refc;\n-\n+struct imc_pmu_ref *core_imc_refc;\n struct imc_pmu *core_imc_pmu;\n \n struct imc_pmu *imc_event_to_pmu(struct perf_event *event)\n@@ -55,14 +56,32 @@ static struct attribute_group imc_format_group = {\n \t.attrs = nest_imc_format_attrs,\n };\n \n+static struct attribute *core_imc_format_attrs[] = {\n+\t&format_attr_event.attr,\n+\t&format_attr_offset.attr,\n+\t&format_attr_rvalue.attr,\n+\tNULL,\n+};\n+\n+static struct attribute_group core_imc_format_group = {\n+\t.name = \"format\",\n+\t.attrs = core_imc_format_attrs,\n+};\n+\n /* Get the cpumask printed to a buffer \"buf\" */\n static ssize_t imc_pmu_cpumask_get_attr(struct device *dev,\n \t\t\t\t\tstruct device_attribute *attr,\n \t\t\t\t\tchar *buf)\n {\n+\tstruct pmu *pmu = dev_get_drvdata(dev);\n \tcpumask_t *active_mask;\n \n-\tactive_mask = &nest_imc_cpumask;\n+\tif (!strncmp(pmu->name, \"nest_\", strlen(\"nest_\")))\n+\t\tactive_mask = &nest_imc_cpumask;\n+\telse if (!strncmp(pmu->name, \"core_\", strlen(\"core_\")))\n+\t\tactive_mask = &core_imc_cpumask;\n+\telse\n+\t\treturn 0;\n \treturn cpumap_print_to_pagebuf(true, buf, active_mask);\n }\n \n@@ -313,6 +332,242 @@ static int nest_imc_event_init(struct perf_event *event)\n \treturn 0;\n }\n \n+/*\n+ * core_imc_mem_init : Initializes memory for the current core.\n+ *\n+ * Uses alloc_pages_node() and uses the returned address as an argument to\n+ * an opal call to configure the pdbar. The address sent as an argument is\n+ * converted to physical address before the opal call is made. This is the\n+ * base address at which the core imc counters are populated.\n+ */\n+static int core_imc_mem_init(int cpu, int size)\n+{\n+\tint phys_id, rc = 0, core_id = (cpu / threads_per_core);\n+\tstruct imc_mem_info *mem_info;\n+\n+\t/*\n+\t * alloc_pages_node() will allocate memory for core in the\n+\t * local node only.\n+\t */\n+\tphys_id = topology_physical_package_id(cpu);\n+\tmem_info = &core_imc_pmu->mem_info[core_id];\n+\tmem_info->id = core_id;\n+\n+\t/* We need only vbase[0] for core counters */\n+\tmem_info->vbase[0] = page_address(alloc_pages_node(phys_id,\n+\t\t\t\t\t GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,\n+\t\t\t\t\t get_order(size)));\n+\tif (!mem_info->vbase[0])\n+\t\treturn -ENOMEM;\n+\n+\t/* Init the mutex */\n+\tcore_imc_refc[core_id].id = core_id;\n+\tmutex_init(&core_imc_refc[core_id].lock);\n+\n+\trc = opal_imc_counters_init(OPAL_IMC_COUNTERS_CORE,\n+\t\t\t\t(u64)virt_to_phys((void *)mem_info->vbase[0]),\n+\t\t\t\tget_hard_smp_processor_id(cpu));\n+\tif (rc) {\n+\t\tfree_pages((u64)mem_info->vbase[0], get_order(size));\n+\t\tmem_info->vbase[0] = NULL;\n+\t}\n+\n+\treturn rc;\n+}\n+\n+static bool is_core_imc_mem_inited(int cpu)\n+{\n+\tstruct imc_mem_info *mem_info;\n+\tint core_id = (cpu / threads_per_core);\n+\n+\tmem_info = &core_imc_pmu->mem_info[core_id];\n+\tif ((mem_info->id == core_id) && (mem_info->vbase[0] != NULL))\n+\t\treturn true;\n+\n+\treturn false;\n+}\n+\n+static int ppc_core_imc_cpu_online(unsigned int cpu)\n+{\n+\tconst struct cpumask *l_cpumask;\n+\tstatic struct cpumask tmp_mask;\n+\tint ret = 0;\n+\n+\t/* Get the cpumask for this core */\n+\tl_cpumask = cpu_sibling_mask(cpu);\n+\n+\t/* If a cpu for this core is already set, then, don't do anything */\n+\tif (cpumask_and(&tmp_mask, l_cpumask, &core_imc_cpumask))\n+\t\treturn 0;\n+\n+\tif (!is_core_imc_mem_inited(cpu)) {\n+\t\tret = core_imc_mem_init(cpu, core_imc_pmu->counter_mem_size);\n+\t\tif (ret) {\n+\t\t\tpr_info(\"core_imc memory allocation for cpu %d failed\\n\", cpu);\n+\t\t\treturn ret;\n+\t\t}\n+\t} else {\n+\t\topal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,\n+\t\t\t\t get_hard_smp_processor_id(cpu));\n+\t}\n+\n+\t/* set the cpu in the mask, and change the context */\n+\tcpumask_set_cpu(cpu, &core_imc_cpumask);\n+\treturn 0;\n+}\n+\n+static int ppc_core_imc_cpu_offline(unsigned int cpu)\n+{\n+\tunsigned int ncpu, core_id;\n+\tstruct imc_pmu_ref *ref;\n+\n+\t/*\n+\t * clear this cpu out of the mask, if not present in the mask,\n+\t * don't bother doing anything.\n+\t */\n+\tif (!cpumask_test_and_clear_cpu(cpu, &core_imc_cpumask))\n+\t\treturn 0;\n+\n+\t/* Find any online cpu in that core except the current \"cpu\" */\n+\tncpu = cpumask_any_but(cpu_sibling_mask(cpu), cpu);\n+\n+\tif (ncpu >= 0 && ncpu < nr_cpu_ids) {\n+\t\tcpumask_set_cpu(ncpu, &core_imc_cpumask);\n+\t\tperf_pmu_migrate_context(&core_imc_pmu->pmu, cpu, ncpu);\n+\t} else {\n+\t\t/*\n+\t\t * If this is the last cpu in this core then, skip the lock and\n+\t\t * make the reference count for this core zero.\n+\t\t */\n+\t\topal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,\n+\t\t\t\t get_hard_smp_processor_id(cpu));\n+\t\tcore_id = cpu / threads_per_core;\n+\t\tref = &core_imc_refc[core_id];\n+\t\tif (!ref)\n+\t\t\treturn -EINVAL;\n+\n+\t\tref->refc = 0;\n+\t}\n+\treturn 0;\n+}\n+\n+static int core_imc_pmu_cpumask_init(void)\n+{\n+\treturn cpuhp_setup_state(CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE,\n+\t\t\t\t \"perf/powerpc/imc_core:online\",\n+\t\t\t\t ppc_core_imc_cpu_online,\n+\t\t\t\t ppc_core_imc_cpu_offline);\n+}\n+\n+static void core_imc_counters_release(struct perf_event *event)\n+{\n+\tint rc, core_id;\n+\tstruct imc_pmu_ref *ref;\n+\n+\tif (event->cpu < 0)\n+\t\treturn;\n+\t/*\n+\t * See if we need to disable the IMC PMU.\n+\t * If no events are currently in use, then we have to take a\n+\t * mutex to ensure that we don't race with another task doing\n+\t * enable or disable the core counters.\n+\t */\n+\tcore_id = event->cpu / threads_per_core;\n+\n+\t/* Take the mutex lock and decrement the refernce count for this core */\n+\tref = &core_imc_refc[core_id];\n+\tif (!ref)\n+\t\treturn;\n+\n+\tmutex_lock(&ref->lock);\n+\tref->refc--;\n+\tif (ref->refc == 0) {\n+\t\trc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,\n+\t\t\t\t\t get_hard_smp_processor_id(event->cpu));\n+\t\tif (rc) {\n+\t\t\tmutex_unlock(&ref->lock);\n+\t\t\tpr_err(\"IMC: Unable to stop the counters for core %d\\n\", core_id);\n+\t\t\treturn;\n+\t\t}\n+\t} else if (ref->refc < 0) {\n+\t\tWARN(1, \"core-imc: Invalid event reference count\\n\");\n+\t\tref->refc = 0;\n+\t}\n+\tmutex_unlock(&ref->lock);\n+}\n+\n+static int core_imc_event_init(struct perf_event *event)\n+{\n+\tint core_id, rc;\n+\tu64 config = event->attr.config;\n+\tstruct imc_mem_info *pcmi;\n+\tstruct imc_pmu *pmu;\n+\tstruct imc_pmu_ref *ref;\n+\n+\tif (event->attr.type != event->pmu->type)\n+\t\treturn -ENOENT;\n+\n+\t/* Sampling not supported */\n+\tif (event->hw.sample_period)\n+\t\treturn -EINVAL;\n+\n+\t/* unsupported modes and filters */\n+\tif (event->attr.exclude_user ||\n+\t event->attr.exclude_kernel ||\n+\t event->attr.exclude_hv ||\n+\t event->attr.exclude_idle ||\n+\t event->attr.exclude_host ||\n+\t event->attr.exclude_guest)\n+\t\treturn -EINVAL;\n+\n+\tif (event->cpu < 0)\n+\t\treturn -EINVAL;\n+\n+\tevent->hw.idx = -1;\n+\tpmu = imc_event_to_pmu(event);\n+\n+\t/* Sanity check for config (event offset and rvalue) */\n+\tif (((config & IMC_EVENT_OFFSET_MASK) > pmu->counter_mem_size) ||\n+\t ((config & IMC_EVENT_RVALUE_MASK) != 0))\n+\t\treturn -EINVAL;\n+\n+\tif (!is_core_imc_mem_inited(event->cpu))\n+\t\treturn -ENODEV;\n+\n+\tcore_id = event->cpu / threads_per_core;\n+\tpcmi = &pmu->mem_info[core_id];\n+\tif ((pcmi->id != core_id) || (!pcmi->vbase[0]))\n+\t\treturn -ENODEV;\n+\n+\tevent->hw.event_base = (u64)pcmi->vbase[0] + (config & IMC_EVENT_OFFSET_MASK);\n+\n+\t/*\n+\t * Core pmu units are enabled only when it is used.\n+\t * See if this is triggered for the first time.\n+\t * If yes, take the mutex lock and enable the core counters.\n+\t * If not, just increment the count in core_imc_refc struct.\n+\t */\n+\tref = &core_imc_refc[core_id];\n+\tif (!ref)\n+\t\treturn -EINVAL;\n+\n+\tmutex_lock(&ref->lock);\n+\tif (ref->refc == 0) {\n+\t\trc = opal_imc_counters_start(OPAL_IMC_COUNTERS_CORE,\n+\t\t\t\t\t get_hard_smp_processor_id(event->cpu));\n+\t\tif (rc) {\n+\t\t\tmutex_unlock(&ref->lock);\n+\t\t\tpr_err(\"IMC: Unable to start the counters for core %d\\n\", core_id);\n+\t\t\treturn rc;\n+\t\t}\n+\t}\n+\t++ref->refc;\n+\tmutex_unlock(&ref->lock);\n+\n+\tevent->destroy = core_imc_counters_release;\n+\treturn 0;\n+}\n+\n static void imc_read_counter(struct perf_event *event)\n {\n \tu64 *addr, data;\n@@ -381,14 +636,19 @@ static int update_pmu_ops(struct imc_pmu *pmu)\n \t\treturn -EINVAL;\n \n \tpmu->pmu.task_ctx_nr = perf_invalid_context;\n-\tpmu->pmu.event_init = nest_imc_event_init;\n+\tif (pmu->domain == IMC_DOMAIN_NEST) {\n+\t\tpmu->pmu.event_init = nest_imc_event_init;\n+\t\tpmu->attr_groups[IMC_FORMAT_ATTR] = &imc_format_group;\n+\t} else if (pmu->domain == IMC_DOMAIN_CORE) {\n+\t\tpmu->pmu.event_init = core_imc_event_init;\n+\t\tpmu->attr_groups[IMC_FORMAT_ATTR] = &core_imc_format_group;\n+\t}\n \tpmu->pmu.add = imc_event_add;\n \tpmu->pmu.del = imc_event_stop;\n \tpmu->pmu.start = imc_event_start;\n \tpmu->pmu.stop = imc_event_stop;\n \tpmu->pmu.read = imc_perf_event_update;\n \tpmu->attr_groups[IMC_CPUMASK_ATTR] = &imc_pmu_cpumask_attr_group;\n-\tpmu->attr_groups[IMC_FORMAT_ATTR] = &imc_format_group;\n \tpmu->pmu.attr_groups = pmu->attr_groups;\n \n \treturn 0;\n@@ -474,6 +734,42 @@ static int init_nest_pmu_ref(void)\n \treturn 0;\n }\n \n+static void cleanup_all_core_imc_memory(struct imc_pmu *pmu_ptr)\n+{\n+\tint i, nr_cores = num_present_cpus() / threads_per_core;\n+\tstruct imc_mem_info *ptr = pmu_ptr->mem_info;\n+\n+\tfor (i = 0; i < nr_cores; i++) {\n+\t\tif (&ptr[i] && ptr[i].vbase[0])\n+\t\t\tfree_pages((u64)ptr->vbase[0], 0);\n+\t}\n+\tkfree(pmu_ptr->mem_info);\n+\tkfree(core_imc_refc);\n+}\n+\n+/*\n+ * imc_mem_init : Function to support memory allocation for core imc.\n+ */\n+static int imc_mem_init(struct imc_pmu *pmu_ptr)\n+{\n+\tint nr_cores;\n+\n+\tif (pmu_ptr->imc_counter_mmaped)\n+\t\treturn 0;\n+\n+\tnr_cores = num_present_cpus() / threads_per_core;\n+\tpmu_ptr->mem_info = kzalloc((sizeof(struct imc_mem_info) * nr_cores), GFP_KERNEL);\n+\tif (!pmu_ptr->mem_info)\n+\t\treturn -ENOMEM;\n+\n+\tcore_imc_refc = kzalloc((sizeof(struct imc_pmu_ref) * nr_cores),\n+\t\t\t\t GFP_KERNEL);\n+\tif (!core_imc_refc)\n+\t\treturn -ENOMEM;\n+\n+\treturn 0;\n+}\n+\n /*\n * init_imc_pmu : Setup and register the IMC pmu device.\n *\n@@ -489,32 +785,48 @@ int init_imc_pmu(struct imc_events *events, int idx,\n {\n \tint ret;\n \n-\t/*\n-\t * Register for cpu hotplug notification.\n-\t *\n-\t * Nest imc pmu need only one cpu per chip, we initialize the cpumask\n-\t * for the first nest imc pmu and use the same for the rest.\n-\t * To handle the cpuhotplug callback unregister, we track the number of\n-\t * nest pmus in \"nest_pmus\".\n-\t * \"nest_imc_cpumask_initialized\" is set to zero during cpuhotplug\n-\t * callback unregister.\n-\t */\n-\tmutex_lock(&imc_nest_inited_reserve);\n-\tif (nest_pmus == 0) {\n-\t\tret = init_nest_pmu_ref();\n-\t\tif (ret) {\n-\t\t\tmutex_unlock(&imc_nest_inited_reserve);\n-\t\t\tgoto err_free;\n+\tret = imc_mem_init(pmu_ptr);\n+\tif (ret)\n+\t\tgoto err_free;\n+\n+\t/* Register for cpu hotplug notification. */\n+\tswitch (pmu_ptr->domain) {\n+\tcase IMC_DOMAIN_NEST:\n+\t\t/*\n+\t\t* Nest imc pmu need only one cpu per chip, we initialize the\n+\t\t* cpumask for the first nest imc pmu and use the same for the\n+\t\t* rest. To handle the cpuhotplug callback unregister, we track\n+\t\t* the number of nest pmus in \"nest_pmus\".\n+\t\t* \"nest_imc_cpumask_initialized\" is set to zero during cpuhotplug\n+\t\t* callback unregister.\n+\t\t*/\n+\t\tmutex_lock(&imc_nest_inited_reserve);\n+\t\tif (nest_pmus == 0) {\n+\t\t\tret = init_nest_pmu_ref();\n+\t\t\tif (ret) {\n+\t\t\t\tmutex_unlock(&imc_nest_inited_reserve);\n+\t\t\t\tgoto err_free;\n+\t\t\t}\n+\t\t\tret = nest_pmu_cpumask_init();\n+\t\t\tif (ret) {\n+\t\t\t\tmutex_unlock(&imc_nest_inited_reserve);\n+\t\t\t\tgoto err_free;\n+\t\t\t}\n+\t\t\tnest_imc_cpumask_initialized = 1;\n \t\t}\n-\t\tret = nest_pmu_cpumask_init();\n+\t\tnest_pmus++;\n+\t\tmutex_unlock(&imc_nest_inited_reserve);\n+\t\tbreak;\n+\tcase IMC_DOMAIN_CORE:\n+\t\tret = core_imc_pmu_cpumask_init();\n \t\tif (ret) {\n-\t\t\tmutex_unlock(&imc_nest_inited_reserve);\n-\t\t\tgoto err_free;\n+\t\t\tcleanup_all_core_imc_memory(pmu_ptr);\n+\t\t\treturn ret;\n \t\t}\n-\t\tnest_imc_cpumask_initialized = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -1;\t/* Unknown domain */\n \t}\n-\tnest_pmus++;\n-\tmutex_unlock(&imc_nest_inited_reserve);\n \n \tret = update_events_in_group(events, idx, pmu_ptr);\n \tif (ret)\n@@ -557,5 +869,10 @@ int init_imc_pmu(struct imc_events *events, int idx,\n \t\t}\n \t\tmutex_unlock(&imc_nest_inited_reserve);\n \t}\n+\t/* For core_imc, we have allocated memory, we need to free it */\n+\tif (pmu_ptr->domain == IMC_DOMAIN_CORE) {\n+\t\tcpuhp_remove_state(CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE);\n+\t\tcleanup_all_core_imc_memory(pmu_ptr);\n+\t}\n \treturn ret;\n }\ndiff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c\nindex aeef59b66420..91b8dd8d7619 100644\n--- a/arch/powerpc/platforms/powernv/opal-imc.c\n+++ b/arch/powerpc/platforms/powernv/opal-imc.c\n@@ -33,6 +33,7 @@\n #include <asm/uaccess.h>\n #include <asm/cputable.h>\n #include <asm/imc-pmu.h>\n+#include <asm/cputhreads.h>\n \n static int imc_event_prop_update(char *name, struct imc_events *events)\n {\n@@ -486,6 +487,22 @@ static void disable_nest_pmu_counters(void)\n \t}\n }\n \n+static void disable_core_pmu_counters(void)\n+{\n+\tcpumask_t cores_map;\n+\tint cpu, rc;\n+\n+\t/* Disable the IMC Core functions */\n+\tcores_map = cpu_online_cores_map();\n+\tfor_each_cpu(cpu, &cores_map) {\n+\t\trc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,\n+\t\t\t\t\t get_hard_smp_processor_id(cpu));\n+\t\tif (rc)\n+\t\t\tpr_err(\"%s: Failed to stop Core (cpu = %d)\\n\",\n+\t\t\t\t__FUNCTION__, cpu);\n+\t}\n+}\n+\n static int opal_imc_counters_probe(struct platform_device *pdev)\n {\n \tstruct device_node *imc_dev = NULL;\n@@ -501,6 +518,7 @@ static int opal_imc_counters_probe(struct platform_device *pdev)\n \t */\n \tif (is_kdump_kernel()) {\n \t\tdisable_nest_pmu_counters();\n+\t\tdisable_core_pmu_counters();\n \t\treturn -ENODEV;\n \t}\n \timc_dev = pdev->dev.of_node;\n@@ -521,6 +539,12 @@ static int opal_imc_counters_probe(struct platform_device *pdev)\n \treturn 0;\n }\n \n+static void opal_imc_counters_shutdown(struct platform_device *pdev)\n+{\n+\t/* Disable the IMC Core functions */\n+\tdisable_core_pmu_counters();\n+}\n+\n static const struct of_device_id opal_imc_match[] = {\n \t{ .compatible = IMC_DTB_COMPAT },\n \t{},\n@@ -532,6 +556,7 @@ static struct platform_driver opal_imc_driver = {\n \t\t.of_match_table = opal_imc_match,\n \t},\n \t.probe = opal_imc_counters_probe,\n+\t.shutdown = opal_imc_counters_shutdown,\n };\n \n MODULE_DEVICE_TABLE(of, opal_imc_match);\ndiff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h\nindex dca7f2b07f93..e145fffec093 100644\n--- a/include/linux/cpuhotplug.h\n+++ b/include/linux/cpuhotplug.h\n@@ -140,6 +140,7 @@ enum cpuhp_state {\n \tCPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,\n \tCPUHP_AP_PERF_ARM_QCOM_L3_ONLINE,\n \tCPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE,\n+\tCPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE,\n \tCPUHP_AP_WORKQUEUE_ONLINE,\n \tCPUHP_AP_RCUTREE_ONLINE,\n \tCPUHP_AP_ONLINE_DYN,\n", "prefixes": [ "v12", "07/10" ] }