get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 833362,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/833362/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/ubuntu-kernel/patch/20171102140501.87671-4-gwalbon@linux.vnet.ibm.com/",
    "project": {
        "id": 15,
        "url": "http://patchwork.ozlabs.org/api/1.2/projects/15/?format=api",
        "name": "Ubuntu Kernel",
        "link_name": "ubuntu-kernel",
        "list_id": "kernel-team.lists.ubuntu.com",
        "list_email": "kernel-team@lists.ubuntu.com",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20171102140501.87671-4-gwalbon@linux.vnet.ibm.com>",
    "list_archive_url": null,
    "date": "2017-11-02T14:04:52",
    "name": "[Artful,03/12] powerpc/perf: Add nest IMC PMU support",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "f242f37e21feaa500d887f51a6fc40ac451f19bd",
    "submitter": {
        "id": 71662,
        "url": "http://patchwork.ozlabs.org/api/1.2/people/71662/?format=api",
        "name": "Gustavo Walbon",
        "email": "gwalbon@linux.vnet.ibm.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/ubuntu-kernel/patch/20171102140501.87671-4-gwalbon@linux.vnet.ibm.com/mbox/",
    "series": [
        {
            "id": 11509,
            "url": "http://patchwork.ozlabs.org/api/1.2/series/11509/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/ubuntu-kernel/list/?series=11509",
            "date": "2017-11-02T14:04:50",
            "name": "Backport for Power9 Nest PMU Instrumentation",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/11509/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/833362/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/833362/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<kernel-team-bounces@lists.ubuntu.com>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com\n\t(client-ip=91.189.94.19; helo=huckleberry.canonical.com;\n\tenvelope-from=kernel-team-bounces@lists.ubuntu.com;\n\treceiver=<UNKNOWN>)",
        "Received": [
            "from huckleberry.canonical.com (huckleberry.canonical.com\n\t[91.189.94.19])\n\tby ozlabs.org (Postfix) with ESMTP id 3ySRgR6Yzbz9t39;\n\tFri,  3 Nov 2017 01:05:23 +1100 (AEDT)",
            "from localhost ([127.0.0.1] helo=huckleberry.canonical.com)\n\tby huckleberry.canonical.com with esmtp (Exim 4.86_2)\n\t(envelope-from <kernel-team-bounces@lists.ubuntu.com>)\n\tid 1eAG7S-00029z-9f; Thu, 02 Nov 2017 14:05:18 +0000",
            "from mx0a-001b2d01.pphosted.com ([148.163.156.1])\n\tby huckleberry.canonical.com with esmtps\n\t(TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2)\n\t(envelope-from <gwalbon@linux.vnet.ibm.com>) id 1eAG7O-00027f-Pk\n\tfor kernel-team@lists.ubuntu.com; Thu, 02 Nov 2017 14:05:15 +0000",
            "from pps.filterd (m0098396.ppops.net [127.0.0.1])\n\tby mx0a-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tvA2E4Sr7062388\n\tfor <kernel-team@lists.ubuntu.com>; Thu, 2 Nov 2017 10:05:13 -0400",
            "from e11.ny.us.ibm.com (e11.ny.us.ibm.com [129.33.205.201])\n\tby mx0a-001b2d01.pphosted.com with ESMTP id 2e038upf01-1\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT)\n\tfor <kernel-team@lists.ubuntu.com>; Thu, 02 Nov 2017 10:05:12 -0400",
            "from localhost\n\tby e11.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use\n\tOnly! Violators will be prosecuted\n\tfor <kernel-team@lists.ubuntu.com> from <gwalbon@linux.vnet.ibm.com>; \n\tThu, 2 Nov 2017 10:05:11 -0400",
            "from b01cxnp23032.gho.pok.ibm.com (9.57.198.27)\n\tby e11.ny.us.ibm.com (146.89.104.198) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tThu, 2 Nov 2017 10:05:10 -0400",
            "from b01ledav005.gho.pok.ibm.com (b01ledav005.gho.pok.ibm.com\n\t[9.57.199.110])\n\tby b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP\n\tid vA2E55D737880020; Thu, 2 Nov 2017 14:05:10 GMT",
            "from b01ledav005.gho.pok.ibm.com (unknown [127.0.0.1])\n\tby IMSVA (Postfix) with ESMTP id 9D266AE052;\n\tThu,  2 Nov 2017 10:05:56 -0400 (EDT)",
            "from localhost (unknown [9.85.138.60])\n\tby b01ledav005.gho.pok.ibm.com (Postfix) with ESMTP id AFF70AE04B;\n\tThu,  2 Nov 2017 10:05:55 -0400 (EDT)"
        ],
        "From": "Gustavo Walbon <gwalbon@linux.vnet.ibm.com>",
        "To": "kernel-team@lists.ubuntu.com",
        "Subject": "[Artful][PATCH 03/12] powerpc/perf: Add nest IMC PMU support",
        "Date": "Thu,  2 Nov 2017 12:04:52 -0200",
        "X-Mailer": "git-send-email 2.13.3",
        "In-Reply-To": "<20171102140501.87671-1-gwalbon@linux.vnet.ibm.com>",
        "References": "<20171102140501.87671-1-gwalbon@linux.vnet.ibm.com>",
        "X-TM-AS-GCONF": "00",
        "x-cbid": "17110214-2213-0000-0000-000002356DA1",
        "X-IBM-SpamModules-Scores": "",
        "X-IBM-SpamModules-Versions": "BY=3.00007997; HX=3.00000241; KW=3.00000007;\n\tPH=3.00000004; SC=3.00000239; SDB=6.00940090; UDB=6.00474019;\n\tIPR=6.00720346; \n\tBA=6.00005666; 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.00017836;\n\tXFM=3.00000015; UTC=2017-11-02 14:05:11",
        "X-IBM-AV-DETECTION": "SAVI=unused REMOTE=unused XFE=unused",
        "x-cbparentid": "17110214-2214-0000-0000-0000580A875A",
        "Message-Id": "<20171102140501.87671-4-gwalbon@linux.vnet.ibm.com>",
        "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-11-02_05:, , signatures=0",
        "X-Proofpoint-Spam-Details": "rule=outbound_notspam policy=outbound score=0\n\tpriorityscore=1501\n\tmalwarescore=0 suspectscore=3 phishscore=0 bulkscore=0 spamscore=0\n\tclxscore=1011 lowpriorityscore=0 impostorscore=0 adultscore=0\n\tclassifier=spam adjust=0 reason=mlx scancount=1\n\tengine=8.0.1-1707230000\n\tdefinitions=main-1711020178",
        "X-BeenThere": "kernel-team@lists.ubuntu.com",
        "X-Mailman-Version": "2.1.20",
        "Precedence": "list",
        "List-Id": "Kernel team discussions <kernel-team.lists.ubuntu.com>",
        "List-Unsubscribe": "<https://lists.ubuntu.com/mailman/options/kernel-team>,\n\t<mailto:kernel-team-request@lists.ubuntu.com?subject=unsubscribe>",
        "List-Archive": "<https://lists.ubuntu.com/archives/kernel-team>",
        "List-Post": "<mailto:kernel-team@lists.ubuntu.com>",
        "List-Help": "<mailto:kernel-team-request@lists.ubuntu.com?subject=help>",
        "List-Subscribe": "<https://lists.ubuntu.com/mailman/listinfo/kernel-team>,\n\t<mailto:kernel-team-request@lists.ubuntu.com?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "kernel-team-bounces@lists.ubuntu.com",
        "Sender": "\"kernel-team\" <kernel-team-bounces@lists.ubuntu.com>"
    },
    "content": "From: Anju T Sudhakar <anju@linux.vnet.ibm.com>\n\nBugLink: https://bugs.launchpad.net/bugs/1481347\n\nAdd support to register Nest In-Memory Collection PMU counters.\nPatch adds a new device file called \"imc-pmu.c\" under powerpc/perf\nfolder to contain all the device PMU functions.\n\nDevice tree parser code added to parse the PMU events information\nand create sysfs event attributes for the PMU.\n\nCpumask attribute added along with Cpu hotplug online/offline functions\nspecific for nest PMU. A new state \"CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE\"\nadded for the cpu hotplug callbacks. Error handle path frees the memory\nand unregisters the CPU hotplug callbacks.\n\nSigned-off-by: Anju T Sudhakar <anju@linux.vnet.ibm.com>\nSigned-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com>\nSigned-off-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>\nSigned-off-by: Michael Ellerman <mpe@ellerman.id.au>\n(cherry-picked from 885dcd709ba9120b9935415b8b0f9d1b94e5826b)\nSigned-off-by: Gustavo Walbon <gwalbon@linux.vnet.ibm.com>\n---\n arch/powerpc/perf/Makefile                |   1 +\n arch/powerpc/perf/imc-pmu.c               | 749 ++++++++++++++++++++++++++++++\n arch/powerpc/platforms/powernv/opal-imc.c |   5 +\n include/linux/cpuhotplug.h                |   1 +\n 4 files changed, 756 insertions(+)\n create mode 100644 arch/powerpc/perf/imc-pmu.c",
    "diff": "diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile\nindex 4d606b99a5cb..3f3a5ce66495 100644\n--- a/arch/powerpc/perf/Makefile\n+++ b/arch/powerpc/perf/Makefile\n@@ -8,6 +8,7 @@ obj64-$(CONFIG_PPC_PERF_CTRS)\t+= power4-pmu.o ppc970-pmu.o power5-pmu.o \\\n \t\t\t\t   isa207-common.o power8-pmu.o power9-pmu.o\n obj32-$(CONFIG_PPC_PERF_CTRS)\t+= mpc7450-pmu.o\n \n+obj-$(CONFIG_PPC_POWERNV)\t+= imc-pmu.o\n obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o\n obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o e6500-pmu.o\n \ndiff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c\nnew file mode 100644\nindex 000000000000..4543faa1bb0d\n--- /dev/null\n+++ b/arch/powerpc/perf/imc-pmu.c\n@@ -0,0 +1,749 @@\n+/*\n+ * In-Memory Collection (IMC) Performance Monitor counter support.\n+ *\n+ * Copyright (C) 2017 Madhavan Srinivasan, IBM Corporation.\n+ *           (C) 2017 Anju T Sudhakar, IBM Corporation.\n+ *           (C) 2017 Hemant K Shaw, IBM Corporation.\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 later version.\n+ */\n+#include <linux/perf_event.h>\n+#include <linux/slab.h>\n+#include <asm/opal.h>\n+#include <asm/imc-pmu.h>\n+#include <asm/cputhreads.h>\n+#include <asm/smp.h>\n+#include <linux/string.h>\n+\n+/* Nest IMC data structures and variables */\n+\n+/*\n+ * Used to avoid races in counting the nest-pmu units during hotplug\n+ * register and unregister\n+ */\n+static DEFINE_MUTEX(nest_init_lock);\n+static DEFINE_PER_CPU(struct imc_pmu_ref *, local_nest_imc_refc);\n+static struct imc_pmu *per_nest_pmu_arr[IMC_MAX_PMUS];\n+static cpumask_t nest_imc_cpumask;\n+struct imc_pmu_ref *nest_imc_refc;\n+static int nest_pmus;\n+\n+struct imc_pmu *imc_event_to_pmu(struct perf_event *event)\n+{\n+\treturn container_of(event->pmu, struct imc_pmu, pmu);\n+}\n+\n+PMU_FORMAT_ATTR(event, \"config:0-40\");\n+PMU_FORMAT_ATTR(offset, \"config:0-31\");\n+PMU_FORMAT_ATTR(rvalue, \"config:32\");\n+PMU_FORMAT_ATTR(mode, \"config:33-40\");\n+static struct attribute *imc_format_attrs[] = {\n+\t&format_attr_event.attr,\n+\t&format_attr_offset.attr,\n+\t&format_attr_rvalue.attr,\n+\t&format_attr_mode.attr,\n+\tNULL,\n+};\n+\n+static struct attribute_group imc_format_group = {\n+\t.name = \"format\",\n+\t.attrs = 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+\tstruct imc_pmu *imc_pmu = container_of(pmu, struct imc_pmu, pmu);\n+\tcpumask_t *active_mask;\n+\n+\t/* Subsequenct patch will add more pmu types here */\n+\tswitch(imc_pmu->domain){\n+\tcase IMC_DOMAIN_NEST:\n+\t\tactive_mask = &nest_imc_cpumask;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+\n+\treturn cpumap_print_to_pagebuf(true, buf, active_mask);\n+}\n+\n+static DEVICE_ATTR(cpumask, S_IRUGO, imc_pmu_cpumask_get_attr, NULL);\n+\n+static struct attribute *imc_pmu_cpumask_attrs[] = {\n+\t&dev_attr_cpumask.attr,\n+\tNULL,\n+};\n+\n+static struct attribute_group imc_pmu_cpumask_attr_group = {\n+\t.attrs = imc_pmu_cpumask_attrs,\n+};\n+\n+/* device_str_attr_create : Populate event \"name\" and string \"str\" in attribute */\n+static struct attribute *device_str_attr_create(const char *name, const char *str)\n+{\n+\tstruct perf_pmu_events_attr *attr;\n+\n+\tattr = kzalloc(sizeof(*attr), GFP_KERNEL);\n+\tif (!attr)\n+\t\treturn NULL;\n+\tsysfs_attr_init(&attr->attr.attr);\n+\n+\tattr->event_str = str;\n+\tattr->attr.attr.name = name;\n+\tattr->attr.attr.mode = 0444;\n+\tattr->attr.show = perf_event_sysfs_show;\n+\n+\treturn &attr->attr.attr;\n+}\n+\n+struct imc_events *imc_parse_event(struct device_node *np, const char *scale,\n+\t\t\t\t  const char *unit, const char *prefix, u32 base)\n+{\n+\tstruct imc_events *event;\n+\tconst char *s;\n+\tu32 reg;\n+\n+\tevent = kzalloc(sizeof(struct imc_events), GFP_KERNEL);\n+\tif (!event)\n+\t\treturn NULL;\n+\n+\tif (of_property_read_u32(np, \"reg\", &reg))\n+\t\tgoto error;\n+\t/* Add the base_reg value to the \"reg\" */\n+\tevent->value = base + reg;\n+\n+\tif (of_property_read_string(np, \"event-name\", &s))\n+\t\tgoto error;\n+\n+\tevent->name = kasprintf(GFP_KERNEL, \"%s%s\", prefix, s);\n+\tif (!event->name)\n+\t\tgoto error;\n+\n+\tif (of_property_read_string(np, \"scale\", &s))\n+\t\ts = scale;\n+\n+\tif (s) {\n+\t\tevent->scale = kstrdup(s, GFP_KERNEL);\n+\t\tif (!event->scale)\n+\t\t\tgoto error;\n+\t}\n+\n+\tif (of_property_read_string(np, \"unit\", &s))\n+\t\ts = unit;\n+\n+\tif (s) {\n+\t\tevent->unit = kstrdup(s, GFP_KERNEL);\n+\t\tif (!event->unit)\n+\t\t\tgoto error;\n+\t}\n+\n+\treturn event;\n+error:\n+\tkfree(event->unit);\n+\tkfree(event->scale);\n+\tkfree(event->name);\n+\tkfree(event);\n+\n+\treturn NULL;\n+}\n+\n+/*\n+ * update_events_in_group: Update the \"events\" information in an attr_group\n+ *                         and assign the attr_group to the pmu \"pmu\".\n+ */\n+static int update_events_in_group(struct device_node *node, struct imc_pmu *pmu)\n+{\n+\tstruct attribute_group *attr_group;\n+\tstruct attribute **attrs, *dev_str;\n+\tstruct device_node *np, *pmu_events;\n+\tstruct imc_events *ev;\n+\tu32 handle, base_reg;\n+\tint i=0, j=0, ct;\n+\tconst char *prefix, *g_scale, *g_unit;\n+\tconst char *ev_val_str, *ev_scale_str, *ev_unit_str;\n+\n+\tif (!of_property_read_u32(node, \"events\", &handle))\n+\t\tpmu_events = of_find_node_by_phandle(handle);\n+\telse\n+\t\treturn 0;\n+\n+\t/* Did not find any node with a given phandle */\n+\tif (!pmu_events)\n+\t\treturn 0;\n+\n+\t/* Get a count of number of child nodes */\n+\tct = of_get_child_count(pmu_events);\n+\n+\t/* Get the event prefix */\n+\tif (of_property_read_string(node, \"events-prefix\", &prefix))\n+\t\treturn 0;\n+\n+\t/* Get a global unit and scale data if available */\n+\tif (of_property_read_string(node, \"scale\", &g_scale))\n+\t\tg_scale = NULL;\n+\n+\tif (of_property_read_string(node, \"unit\", &g_unit))\n+\t\tg_unit = NULL;\n+\n+\t/* \"reg\" property gives out the base offset of the counters data */\n+\tof_property_read_u32(node, \"reg\", &base_reg);\n+\n+\t/* Allocate memory for the events */\n+\tpmu->events = kcalloc(ct, sizeof(struct imc_events), GFP_KERNEL);\n+\tif (!pmu->events)\n+\t\treturn -ENOMEM;\n+\n+\tct = 0;\n+\t/* Parse the events and update the struct */\n+\tfor_each_child_of_node(pmu_events, np) {\n+\t\tev = imc_parse_event(np, g_scale, g_unit, prefix, base_reg);\n+\t\tif (ev)\n+\t\t\tpmu->events[ct++] = ev;\n+\t}\n+\n+\t/* Allocate memory for attribute group */\n+\tattr_group = kzalloc(sizeof(*attr_group), GFP_KERNEL);\n+\tif (!attr_group)\n+\t\treturn -ENOMEM;\n+\n+\t/*\n+\t * Allocate memory for attributes.\n+\t * Since we have count of events for this pmu, we also allocate\n+\t * memory for the scale and unit attribute for now.\n+\t * \"ct\" has the total event structs added from the events-parent node.\n+\t * So allocate three times the \"ct\" (this includes event, event_scale and\n+\t * event_unit).\n+\t */\n+\tattrs = kcalloc(((ct * 3) + 1), sizeof(struct attribute *), GFP_KERNEL);\n+\tif (!attrs) {\n+\t\tkfree(attr_group);\n+\t\tkfree(pmu->events);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tattr_group->name = \"events\";\n+\tattr_group->attrs = attrs;\n+\tdo {\n+\t\tev_val_str = kasprintf(GFP_KERNEL, \"event=0x%x\", pmu->events[i]->value);\n+\t\tdev_str = device_str_attr_create(pmu->events[i]->name, ev_val_str);\n+\t\tif (!dev_str)\n+\t\t\tcontinue;\n+\n+\t\tattrs[j++] = dev_str;\n+\t\tif (pmu->events[i]->scale) {\n+\t\t\tev_scale_str = kasprintf(GFP_KERNEL, \"%s.scale\",pmu->events[i]->name);\n+\t\t\tdev_str = device_str_attr_create(ev_scale_str, pmu->events[i]->scale);\n+\t\t\tif (!dev_str)\n+\t\t\t\tcontinue;\n+\n+\t\t\tattrs[j++] = dev_str;\n+\t\t}\n+\n+\t\tif (pmu->events[i]->unit) {\n+\t\t\tev_unit_str = kasprintf(GFP_KERNEL, \"%s.unit\",pmu->events[i]->name);\n+\t\t\tdev_str = device_str_attr_create(ev_unit_str, pmu->events[i]->unit);\n+\t\t\tif (!dev_str)\n+\t\t\t\tcontinue;\n+\n+\t\t\tattrs[j++] = dev_str;\n+\t\t}\n+\t} while (++i < ct);\n+\n+\t/* Save the event attribute */\n+\tpmu->attr_groups[IMC_EVENT_ATTR] = attr_group;\n+\n+\tkfree(pmu->events);\n+\treturn 0;\n+}\n+\n+/* get_nest_pmu_ref: Return the imc_pmu_ref struct for the given node */\n+static struct imc_pmu_ref *get_nest_pmu_ref(int cpu)\n+{\n+\treturn per_cpu(local_nest_imc_refc, cpu);\n+}\n+\n+static void nest_change_cpu_context(int old_cpu, int new_cpu)\n+{\n+\tstruct imc_pmu **pn = per_nest_pmu_arr;\n+\tint i;\n+\n+\tif (old_cpu < 0 || new_cpu < 0)\n+\t\treturn;\n+\n+\tfor (i = 0; *pn && i < IMC_MAX_PMUS; i++, pn++)\n+\t\tperf_pmu_migrate_context(&(*pn)->pmu, old_cpu, new_cpu);\n+}\n+\n+static int ppc_nest_imc_cpu_offline(unsigned int cpu)\n+{\n+\tint nid, target = -1;\n+\tconst struct cpumask *l_cpumask;\n+\tstruct imc_pmu_ref *ref;\n+\n+\t/*\n+\t * Check in the designated list for this cpu. Dont bother\n+\t * if not one of them.\n+\t */\n+\tif (!cpumask_test_and_clear_cpu(cpu, &nest_imc_cpumask))\n+\t\treturn 0;\n+\n+\t/*\n+\t * Now that this cpu is one of the designated,\n+\t * find a next cpu a) which is online and b) in same chip.\n+\t */\n+\tnid = cpu_to_node(cpu);\n+\tl_cpumask = cpumask_of_node(nid);\n+\ttarget = cpumask_any_but(l_cpumask, cpu);\n+\n+\t/*\n+\t * Update the cpumask with the target cpu and\n+\t * migrate the context if needed\n+\t */\n+\tif (target >= 0 && target < nr_cpu_ids) {\n+\t\tcpumask_set_cpu(target, &nest_imc_cpumask);\n+\t\tnest_change_cpu_context(cpu, target);\n+\t} else {\n+\t\topal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST,\n+\t\t\t\t       get_hard_smp_processor_id(cpu));\n+\t\t/*\n+\t\t * If this is the last cpu in this chip then, skip the reference\n+\t\t * count mutex lock and make the reference count on this chip zero.\n+\t\t */\n+\t\tref = get_nest_pmu_ref(cpu);\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 ppc_nest_imc_cpu_online(unsigned int cpu)\n+{\n+\tconst struct cpumask *l_cpumask;\n+\tstatic struct cpumask tmp_mask;\n+\tint res;\n+\n+\t/* Get the cpumask of this node */\n+\tl_cpumask = cpumask_of_node(cpu_to_node(cpu));\n+\n+\t/*\n+\t * If this is not the first online CPU on this node, then\n+\t * just return.\n+\t */\n+\tif (cpumask_and(&tmp_mask, l_cpumask, &nest_imc_cpumask))\n+\t\treturn 0;\n+\n+\t/*\n+\t * If this is the first online cpu on this node\n+\t * disable the nest counters by making an OPAL call.\n+\t */\n+\tres = opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST,\n+\t\t\t\t     get_hard_smp_processor_id(cpu));\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* Make this CPU the designated target for counter collection */\n+\tcpumask_set_cpu(cpu, &nest_imc_cpumask);\n+\treturn 0;\n+}\n+\n+static int nest_pmu_cpumask_init(void)\n+{\n+\treturn cpuhp_setup_state(CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE,\n+\t\t\t\t \"perf/powerpc/imc:online\",\n+\t\t\t\t ppc_nest_imc_cpu_online,\n+\t\t\t\t ppc_nest_imc_cpu_offline);\n+}\n+\n+static void nest_imc_counters_release(struct perf_event *event)\n+{\n+\tint rc, node_id;\n+\tstruct imc_pmu_ref *ref;\n+\n+\tif (event->cpu < 0)\n+\t\treturn;\n+\n+\tnode_id = cpu_to_node(event->cpu);\n+\n+\t/*\n+\t * See if we need to disable the nest 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 nest counters.\n+\t */\n+\tref = get_nest_pmu_ref(event->cpu);\n+\tif (!ref)\n+\t\treturn;\n+\n+\t/* Take the mutex lock for this node and then decrement the reference count */\n+\tmutex_lock(&ref->lock);\n+\tref->refc--;\n+\tif (ref->refc == 0) {\n+\t\trc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST,\n+\t\t\t\t\t    get_hard_smp_processor_id(event->cpu));\n+\t\tif (rc) {\n+\t\t\tmutex_unlock(&nest_imc_refc[node_id].lock);\n+\t\t\tpr_err(\"nest-imc: Unable to stop the counters for core %d\\n\", node_id);\n+\t\t\treturn;\n+\t\t}\n+\t} else if (ref->refc < 0) {\n+\t\tWARN(1, \"nest-imc: Invalid event reference count\\n\");\n+\t\tref->refc = 0;\n+\t}\n+\tmutex_unlock(&ref->lock);\n+}\n+\n+static int nest_imc_event_init(struct perf_event *event)\n+{\n+\tint chip_id, rc, node_id;\n+\tu32 l_config, config = event->attr.config;\n+\tstruct imc_mem_info *pcni;\n+\tstruct imc_pmu *pmu;\n+\tstruct imc_pmu_ref *ref;\n+\tbool flag = false;\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+\tpmu = imc_event_to_pmu(event);\n+\n+\t/* Sanity check for config (event offset) */\n+\tif ((config & IMC_EVENT_OFFSET_MASK) > pmu->counter_mem_size)\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * Nest HW counter memory resides in a per-chip reserve-memory (HOMER).\n+\t * Get the base memory addresss for this cpu.\n+\t */\n+\tchip_id = topology_physical_package_id(event->cpu);\n+\tpcni = pmu->mem_info;\n+\tdo {\n+\t\tif (pcni->id == chip_id) {\n+\t\t\tflag = true;\n+\t\t\tbreak;\n+\t\t}\n+\t\tpcni++;\n+\t} while (pcni);\n+\n+\tif (!flag)\n+\t\treturn -ENODEV;\n+\n+\t/*\n+\t * Add the event offset to the base address.\n+\t */\n+\tl_config = config & IMC_EVENT_OFFSET_MASK;\n+\tevent->hw.event_base = (u64)pcni->vbase + l_config;\n+\tnode_id = cpu_to_node(event->cpu);\n+\n+\t/*\n+\t * Get the imc_pmu_ref struct for this node.\n+\t * Take the mutex lock and then increment the count of nest pmu events\n+\t * inited.\n+\t */\n+\tref = get_nest_pmu_ref(event->cpu);\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_NEST,\n+\t\t\t\t\t     get_hard_smp_processor_id(event->cpu));\n+\t\tif (rc) {\n+\t\t\tmutex_unlock(&nest_imc_refc[node_id].lock);\n+\t\t\tpr_err(\"nest-imc: Unable to start the counters for node %d\\n\",\n+\t\t\t\t\t\t\t\t\tnode_id);\n+\t\t\treturn rc;\n+\t\t}\n+\t}\n+\t++ref->refc;\n+\tmutex_unlock(&ref->lock);\n+\n+\tevent->destroy = nest_imc_counters_release;\n+\treturn 0;\n+}\n+\n+static u64 * get_event_base_addr(struct perf_event *event)\n+{\n+\t/*\n+\t * Subsequent patch will add code to detect caller imc pmu\n+\t * and return accordingly.\n+\t */\n+\treturn (u64 *)event->hw.event_base;\n+}\n+\n+static u64 imc_read_counter(struct perf_event *event)\n+{\n+\tu64 *addr, data;\n+\n+\t/*\n+\t * In-Memory Collection (IMC) counters are free flowing counters.\n+\t * So we take a snapshot of the counter value on enable and save it\n+\t * to calculate the delta at later stage to present the event counter\n+\t * value.\n+\t */\n+\taddr = get_event_base_addr(event);\n+\tdata = be64_to_cpu(READ_ONCE(*addr));\n+\tlocal64_set(&event->hw.prev_count, data);\n+\n+\treturn data;\n+}\n+\n+static void imc_event_update(struct perf_event *event)\n+{\n+\tu64 counter_prev, counter_new, final_count;\n+\n+\tcounter_prev = local64_read(&event->hw.prev_count);\n+\tcounter_new = imc_read_counter(event);\n+\tfinal_count = counter_new - counter_prev;\n+\n+\t/* Update the delta to the event count */\n+\tlocal64_add(final_count, &event->count);\n+}\n+\n+static void imc_event_start(struct perf_event *event, int flags)\n+{\n+\t/*\n+\t * In Memory Counters are free flowing counters. HW or the microcode\n+\t * keeps adding to the counter offset in memory. To get event\n+\t * counter value, we snapshot the value here and we calculate\n+\t * delta at later point.\n+\t */\n+\timc_read_counter(event);\n+}\n+\n+static void imc_event_stop(struct perf_event *event, int flags)\n+{\n+\t/*\n+\t * Take a snapshot and calculate the delta and update\n+\t * the event counter values.\n+\t */\n+\timc_event_update(event);\n+}\n+\n+static int imc_event_add(struct perf_event *event, int flags)\n+{\n+\tif (flags & PERF_EF_START)\n+\t\timc_event_start(event, flags);\n+\n+\treturn 0;\n+}\n+\n+/* update_pmu_ops : Populate the appropriate operations for \"pmu\" */\n+static int update_pmu_ops(struct imc_pmu *pmu)\n+{\n+\tpmu->pmu.task_ctx_nr = perf_invalid_context;\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_event_update;\n+\tpmu->pmu.attr_groups = pmu->attr_groups;\n+\tpmu->attr_groups[IMC_FORMAT_ATTR] = &imc_format_group;\n+\n+\t/* Subsequenct patch will add more pmu types here */\n+\tswitch (pmu->domain) {\n+\tcase IMC_DOMAIN_NEST:\n+\t\tpmu->pmu.event_init = nest_imc_event_init;\n+\t\tpmu->attr_groups[IMC_CPUMASK_ATTR] = &imc_pmu_cpumask_attr_group;\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* init_nest_pmu_ref: Initialize the imc_pmu_ref struct for all the nodes */\n+static int init_nest_pmu_ref(void)\n+{\n+\tint nid, i, cpu;\n+\n+\tnest_imc_refc = kcalloc(num_possible_nodes(), sizeof(*nest_imc_refc),\n+\t\t\t\t\t\t\t\tGFP_KERNEL);\n+\n+\tif (!nest_imc_refc)\n+\t\treturn -ENOMEM;\n+\n+\ti = 0;\n+\tfor_each_node(nid) {\n+\t\t/*\n+\t\t * Mutex lock to avoid races while tracking the number of\n+\t\t * sessions using the chip's nest pmu units.\n+\t\t */\n+\t\tmutex_init(&nest_imc_refc[i].lock);\n+\n+\t\t/*\n+\t\t * Loop to init the \"id\" with the node_id. Variable \"i\" initialized to\n+\t\t * 0 and will be used as index to the array. \"i\" will not go off the\n+\t\t * end of the array since the \"for_each_node\" loops for \"N_POSSIBLE\"\n+\t\t * nodes only.\n+\t\t */\n+\t\tnest_imc_refc[i++].id = nid;\n+\t}\n+\n+\t/*\n+\t * Loop to init the per_cpu \"local_nest_imc_refc\" with the proper\n+\t * \"nest_imc_refc\" index. This makes get_nest_pmu_ref() alot simple.\n+\t */\n+\tfor_each_possible_cpu(cpu) {\n+\t\tnid = cpu_to_node(cpu);\n+\t\tfor_each_online_node(i) {\n+\t\t\tif (nest_imc_refc[i].id == nid) {\n+\t\t\t\tper_cpu(local_nest_imc_refc, cpu) = &nest_imc_refc[i];\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+/*\n+ * Common function to unregister cpu hotplug callback and\n+ * free the memory.\n+ * TODO: Need to handle pmu unregistering, which will be\n+ * done in followup series.\n+ */\n+static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)\n+{\n+\tif (pmu_ptr->domain == IMC_DOMAIN_NEST) {\n+\t\tmutex_unlock(&nest_init_lock);\n+\t\tif (nest_pmus == 1) {\n+\t\t\tcpuhp_remove_state(CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE);\n+\t\t\tkfree(nest_imc_refc);\n+\t\t}\n+\n+\t\tif (nest_pmus > 0)\n+\t\t\tnest_pmus--;\n+\t\tmutex_unlock(&nest_init_lock);\n+\t}\n+\n+\t/* Only free the attr_groups which are dynamically allocated  */\n+\tkfree(pmu_ptr->attr_groups[IMC_EVENT_ATTR]->attrs);\n+\tkfree(pmu_ptr->attr_groups[IMC_EVENT_ATTR]);\n+\tkfree(pmu_ptr);\n+\treturn;\n+}\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, struct device_node *parent,\n+\t\t\t\t\t\t\t\tint pmu_index)\n+{\n+\tconst char *s;\n+\n+\tif (of_property_read_string(parent, \"name\", &s))\n+\t\treturn -ENODEV;\n+\n+\t/* Subsequenct patch will add more pmu types here */\n+\tswitch (pmu_ptr->domain) {\n+\tcase IMC_DOMAIN_NEST:\n+\t\t/* Update the pmu name */\n+\t\tpmu_ptr->pmu.name = kasprintf(GFP_KERNEL, \"%s%s_imc\", \"nest_\", s);\n+\t\tif (!pmu_ptr->pmu.name)\n+\t\t\treturn -ENOMEM;\n+\n+\t\t/* Needed for hotplug/migration */\n+\t\tper_nest_pmu_arr[pmu_index] = pmu_ptr;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * init_imc_pmu : Setup and register the IMC pmu device.\n+ *\n+ * @parent:\tDevice tree unit node\n+ * @pmu_ptr:\tmemory allocated for this pmu\n+ * @pmu_idx:\tCount of nest pmc registered\n+ *\n+ * init_imc_pmu() setup pmu cpumask and registers for a cpu hotplug callback.\n+ * Handles failure cases and accordingly frees memory.\n+ */\n+int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_idx)\n+{\n+\tint ret;\n+\n+\tret = imc_mem_init(pmu_ptr, parent, pmu_idx);\n+\tif (ret)\n+\t\tgoto err_free;\n+\n+\t/* Subsequenct patch will add more pmu types here */\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*/\n+\t\tmutex_lock(&nest_init_lock);\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(&nest_init_lock);\n+\t\t\t\tgoto err_free;\n+\t\t\t}\n+\t\t\t/* Register for cpu hotplug notification. */\n+\t\t\tret = nest_pmu_cpumask_init();\n+\t\t\tif (ret) {\n+\t\t\t\tmutex_unlock(&nest_init_lock);\n+\t\t\t\tgoto err_free;\n+\t\t\t}\n+\t\t}\n+\t\tnest_pmus++;\n+\t\tmutex_unlock(&nest_init_lock);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn  -1;\t/* Unknown domain */\n+\t}\n+\n+\tret = update_events_in_group(parent, pmu_ptr);\n+\tif (ret)\n+\t\tgoto err_free;\n+\n+\tret = update_pmu_ops(pmu_ptr);\n+\tif (ret)\n+\t\tgoto err_free;\n+\n+\tret = perf_pmu_register(&pmu_ptr->pmu, pmu_ptr->pmu.name, -1);\n+\tif (ret)\n+\t\tgoto err_free;\n+\n+\tpr_info(\"%s performance monitor hardware support registered\\n\",\n+\t\t\t\t\t\t\tpmu_ptr->pmu.name);\n+\n+\treturn 0;\n+\n+err_free:\n+\timc_common_cpuhp_mem_free(pmu_ptr);\n+\treturn ret;\n+}\ndiff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c\nindex f57a6fbd3f57..b903bf5e6006 100644\n--- a/arch/powerpc/platforms/powernv/opal-imc.c\n+++ b/arch/powerpc/platforms/powernv/opal-imc.c\n@@ -108,6 +108,11 @@ static int imc_pmu_create(struct device_node *parent, int pmu_index, int domain)\n \t\t}\n \t}\n \n+\t/* Function to register IMC pmu */\n+\tret = init_imc_pmu(parent, pmu_ptr, pmu_index);\n+\tif (ret)\n+\t\tpr_err(\"IMC PMU %s Register failed\\n\", pmu_ptr->pmu.name);\n+\n \treturn 0;\n \n free_pmu:\ndiff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h\nindex 82b30e638430..05d1907713e9 100644\n--- a/include/linux/cpuhotplug.h\n+++ b/include/linux/cpuhotplug.h\n@@ -137,6 +137,7 @@ enum cpuhp_state {\n \tCPUHP_AP_PERF_ARM_L2X0_ONLINE,\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_WORKQUEUE_ONLINE,\n \tCPUHP_AP_RCUTREE_ONLINE,\n \tCPUHP_AP_ONLINE_DYN,\n",
    "prefixes": [
        "Artful",
        "03/12"
    ]
}