get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 783381,
    "url": "http://patchwork.ozlabs.org/api/patches/783381/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/1499074673-30576-4-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": "<1499074673-30576-4-git-send-email-anju@linux.vnet.ibm.com>",
    "list_archive_url": "https://lore.kernel.org/linuxppc-dev/1499074673-30576-4-git-send-email-anju@linux.vnet.ibm.com/",
    "date": "2017-07-03T09:37:49",
    "name": "[v12,03/10] powerpc/powernv: Detect supported IMC units and its events",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "256aa0bfc0bff279d76f7ec92da42ff6d586923e",
    "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/1499074673-30576-4-git-send-email-anju@linux.vnet.ibm.com/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/783381/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/783381/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 3x1MdX4pg6z9rxl\n\tfor <patchwork-incoming@ozlabs.org>;\n\tMon,  3 Jul 2017 19:43:28 +1000 (AEST)",
            "from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3x1MdX44qXzDrFy\n\tfor <patchwork-incoming@ozlabs.org>;\n\tMon,  3 Jul 2017 19:43:28 +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 3x1MWW5zDQzDr6s\n\tfor <linuxppc-dev@lists.ozlabs.org>;\n\tMon,  3 Jul 2017 19:38:15 +1000 (AEST)",
            "from pps.filterd (m0098413.ppops.net [127.0.0.1])\n\tby mx0b-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id\n\tv639Xf4t142215\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 3 Jul 2017 05:38:13 -0400",
            "from e23smtp01.au.ibm.com (e23smtp01.au.ibm.com [202.81.31.143])\n\tby mx0b-001b2d01.pphosted.com with ESMTP id 2bfdbccgft-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:38:12 -0400",
            "from localhost\n\tby e23smtp01.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:38:10 +1000",
            "from d23relay06.au.ibm.com (202.81.31.225)\n\tby e23smtp01.au.ibm.com (202.81.31.207) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tMon, 3 Jul 2017 19:38:08 +1000",
            "from d23av03.au.ibm.com (d23av03.au.ibm.com [9.190.234.97])\n\tby d23relay06.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id\n\tv639c8gW44695628\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 3 Jul 2017 19:38:08 +1000",
            "from d23av03.au.ibm.com (localhost [127.0.0.1])\n\tby d23av03.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id\n\tv639bxZS027896\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 3 Jul 2017 19:37:59 +1000",
            "from xenial-xerus.in.ibm.com (xenial-xerus.in.ibm.com [9.124.35.20]\n\t(may be forged))\n\tby d23av03.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id\n\tv639bkFQ027271; Mon, 3 Jul 2017 19:37:56 +1000"
        ],
        "From": "Anju T Sudhakar <anju@linux.vnet.ibm.com>",
        "To": "mpe@ellerman.id.au",
        "Subject": "[PATCH v12 03/10] powerpc/powernv: Detect supported IMC units and\n\tits events",
        "Date": "Mon,  3 Jul 2017 15:07:49 +0530",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1499074673-30576-1-git-send-email-anju@linux.vnet.ibm.com>",
        "References": "<1499074673-30576-1-git-send-email-anju@linux.vnet.ibm.com>",
        "X-TM-AS-MML": "disable",
        "x-cbid": "17070309-1617-0000-0000-000001F0CF0F",
        "X-IBM-AV-DETECTION": "SAVI=unused REMOTE=unused XFE=unused",
        "x-cbparentid": "17070309-1618-0000-0000-000048381599",
        "Message-Id": "<1499074673-30576-4-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=4\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-1707030160",
        "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, anton@samba.org, 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\nParse device tree to detect IMC units. Traverse through each IMC unit\nnode to find supported events and corresponding unit/scale files (if any).\n\nThe device tree for IMC counters starts at the node \"imc-counters\".\nThis node contains all the IMC PMU nodes and event nodes\nfor these IMC PMUs. The PMU nodes have an \"events\" property which has a\nphandle value for the actual events node. The events are separated from\nthe PMU nodes to abstract out the common events. For example, PMU node\n\"mcs0\", \"mcs1\" etc. will contain a pointer to \"nest-mcs-events\" since,\nthe events are common between these PMUs. These events have a different\nprefix based on their relation to different PMUs, and hence, the PMU\nnodes themselves contain an \"events-prefix\" property. The value for this\nproperty concatenated to the event name, forms the actual event\nname. Also, the PMU have a \"reg\" field as the base offset for the events\nwhich belong to this PMU. This \"reg\" field is added to event's \"reg\" field\nin the \"events\" node, which gives us the location of the counter data. Kernel\ncode uses this offset as event configuration value.\n\nDevice tree parser code also looks for scale/unit property in the event\nnode and passes on the value as an event attr for perf interface to use\nin the post processing by the perf tool. Some PMUs may have common scale\nand unit properties which implies that all events supported by this PMU\ninherit the scale and unit properties of the PMU itself. For those\nevents, we need to set the common unit and scale values.\n\nFor failure to initialize any unit or any event, disable that unit and\ncontinue setting up the rest of them.\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/imc-pmu.h        |   5 +\n arch/powerpc/platforms/powernv/opal-imc.c | 439 +++++++++++++++++++++++++++++-\n 2 files changed, 443 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/arch/powerpc/include/asm/imc-pmu.h b/arch/powerpc/include/asm/imc-pmu.h\nindex ffaea0b9c13e..2a0239e2590d 100644\n--- a/arch/powerpc/include/asm/imc-pmu.h\n+++ b/arch/powerpc/include/asm/imc-pmu.h\n@@ -91,6 +91,11 @@ struct imc_pmu {\n \tconst struct attribute_group *attr_groups[4];\n };\n \n+/* In-Memory Collection Counters Type */\n+enum {\n+\tIMC_COUNTER_PER_CHIP            = 0x10,\n+};\n+\n /*\n  * Domains for IMC PMUs\n  */\ndiff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c\nindex 5b1045c81af4..839c25718110 100644\n--- a/arch/powerpc/platforms/powernv/opal-imc.c\n+++ b/arch/powerpc/platforms/powernv/opal-imc.c\n@@ -34,9 +34,437 @@\n #include <asm/cputable.h>\n #include <asm/imc-pmu.h>\n \n+struct imc_pmu *per_nest_pmu_arr[IMC_MAX_PMUS];\n+\n+static int imc_event_prop_update(char *name, struct imc_events *events)\n+{\n+\tchar *buf;\n+\n+\tif (!events || !name)\n+\t\treturn -EINVAL;\n+\n+\t/* memory for content */\n+\tbuf = kzalloc(IMC_MAX_NAME_VAL_LEN, GFP_KERNEL);\n+\tif (!buf)\n+\t\treturn -ENOMEM;\n+\n+\tevents->ev_name = name;\n+\tevents->ev_value = buf;\n+\treturn 0;\n+}\n+\n+static int imc_event_prop_str(struct property *pp, char *name,\n+\t\t\t      struct imc_events *events)\n+{\n+\tint ret;\n+\n+\tret = imc_event_prop_update(name, events);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (!pp->value || (strnlen(pp->value, pp->length) == pp->length) ||\n+\t   (pp->length > IMC_MAX_NAME_VAL_LEN))\n+\t\treturn -EINVAL;\n+\tstrncpy(events->ev_value, (const char *)pp->value, pp->length);\n+\n+\treturn 0;\n+}\n+\n+static int imc_event_prop_val(char *name, u32 val,\n+\t\t\t      struct imc_events *events)\n+{\n+\tint ret;\n+\n+\tret = imc_event_prop_update(name, events);\n+\tif (ret)\n+\t\treturn ret;\n+\tsnprintf(events->ev_value, IMC_MAX_NAME_VAL_LEN, \"event=0x%x\", val);\n+\n+\treturn 0;\n+}\n+\n+static int set_event_property(struct property *pp, char *event_prop,\n+\t\t\t      struct imc_events *events, char *ev_name)\n+{\n+\tchar *buf;\n+\tint ret;\n+\n+\tbuf = kzalloc(IMC_MAX_NAME_VAL_LEN, GFP_KERNEL);\n+\tif (!buf)\n+\t\treturn -ENOMEM;\n+\n+\tsprintf(buf, \"%s.%s\", ev_name, event_prop);\n+\tret = imc_event_prop_str(pp, buf, events);\n+\tif (ret) {\n+\t\tif (events->ev_name)\n+\t\t\tkfree(events->ev_name);\n+\t\tif (events->ev_value)\n+\t\t\tkfree(events->ev_value);\n+\t}\n+\treturn ret;\n+}\n+\n+/*\n+ * imc_events_node_parser: Parse the event node \"dev\" and assign the parsed\n+ *                         information to event \"events\".\n+ *\n+ * Parses the \"reg\", \"scale\" and \"unit\" properties of this event.\n+ * \"reg\" gives us the event offset in the counter memory.\n+ */\n+static int imc_events_node_parser(struct device_node *dev,\n+\t\t\t\t  struct imc_events *events,\n+\t\t\t\t  struct property *event_scale,\n+\t\t\t\t  struct property *event_unit,\n+\t\t\t\t  struct property *name_prefix,\n+\t\t\t\t  u32 reg, int pmu_domain)\n+{\n+\tstruct property *name, *pp;\n+\tchar *ev_name;\n+\tu32 val;\n+\tint idx = 0, ret;\n+\n+\tif (!dev)\n+\t\tgoto fail;\n+\n+\t/* Check for \"event-name\" property, which is the perfix for event names */\n+\tname = of_find_property(dev, \"event-name\", NULL);\n+\tif (!name)\n+\t\treturn -ENODEV;\n+\n+\tif (!name->value ||\n+\t  (strnlen(name->value, name->length) == name->length) ||\n+\t  (name->length > IMC_MAX_NAME_VAL_LEN))\n+\t\treturn -EINVAL;\n+\n+\tev_name = kzalloc(IMC_MAX_NAME_VAL_LEN, GFP_KERNEL);\n+\tif (!ev_name)\n+\t\treturn -ENOMEM;\n+\n+\tsnprintf(ev_name, IMC_MAX_NAME_VAL_LEN, \"%s%s\",\n+\t\t (char *)name_prefix->value,\n+\t\t (char *)name->value);\n+\n+\t/*\n+\t * Parse each property of this event node \"dev\". Property \"reg\" has\n+\t * the offset which is assigned to the event name. Other properties\n+\t * like \"scale\" and \"unit\" are assigned to event.scale and event.unit\n+\t * accordingly.\n+\t */\n+\tfor_each_property_of_node(dev, pp) {\n+\t\t/*\n+\t\t * If there is an issue in parsing a single property of\n+\t\t * this event, we just clean up the buffers, but we still\n+\t\t * continue to parse. TODO: This could be rewritten to skip the\n+\t\t * entire event node incase of parsing issues, but that can be\n+\t\t * done later.\n+\t\t */\n+\t\tif (strncmp(pp->name, \"reg\", 3) == 0) {\n+\t\t\tof_property_read_u32(dev, pp->name, &val);\n+\t\t\tval += reg;\n+\t\t\tret = imc_event_prop_val(ev_name, val, &events[idx]);\n+\t\t\tif (ret) {\n+\t\t\t\tif (events[idx].ev_name)\n+\t\t\t\t\tkfree(events[idx].ev_name);\n+\t\t\t\tif (events[idx].ev_value)\n+\t\t\t\t\tkfree(events[idx].ev_value);\n+\t\t\t\tgoto fail;\n+\t\t\t}\n+\t\t\tidx++;\n+\t\t\t/*\n+\t\t\t * If the common scale and unit properties available,\n+\t\t\t * then, assign them to this event\n+\t\t\t */\n+\t\t\tif (event_scale) {\n+\t\t\t\tret = set_event_property(event_scale, \"scale\",\n+\t\t\t\t\t\t\t &events[idx],\n+\t\t\t\t\t\t\t ev_name);\n+\t\t\t\tif (ret)\n+\t\t\t\t\tgoto fail;\n+\t\t\t\tidx++;\n+\t\t\t}\n+\t\t\tif (event_unit) {\n+\t\t\t\tret = set_event_property(event_unit, \"unit\",\n+\t\t\t\t\t\t\t &events[idx],\n+\t\t\t\t\t\t\t ev_name);\n+\t\t\t\tif (ret)\n+\t\t\t\t\tgoto fail;\n+\t\t\t\tidx++;\n+\t\t\t}\n+\t\t} else if (strncmp(pp->name, \"unit\", 4) == 0) {\n+\t\t\t/*\n+\t\t\t * The event's unit and scale properties can override the\n+\t\t\t * PMU's event and scale properties, if present.\n+\t\t\t */\n+\t\t\tret = set_event_property(pp, \"unit\", &events[idx],\n+\t\t\t\t\t\t ev_name);\n+\t\t\tif (ret)\n+\t\t\t\tgoto fail;\n+\t\t\tidx++;\n+\t\t} else if (strncmp(pp->name, \"scale\", 5) == 0) {\n+\t\t\tret = set_event_property(pp, \"scale\", &events[idx],\n+\t\t\t\t\t\t ev_name);\n+\t\t\tif (ret)\n+\t\t\t\tgoto fail;\n+\t\t\tidx++;\n+\t\t}\n+\t}\n+\n+\treturn idx;\n+fail:\n+\treturn -EINVAL;\n+}\n+\n+/*\n+ * get_nr_children : Returns the number of events(along with scale and unit)\n+ * \t\t     for a pmu device node.\n+ */\n+static int get_nr_children(struct device_node *pmu_node)\n+{\n+\tstruct device_node *child;\n+\tint i = 0;\n+\n+\tfor_each_child_of_node(pmu_node, child)\n+\t\ti++;\n+\treturn i;\n+}\n+\n+/*\n+ * imc_free_events : Cleanup the \"events\" list having \"nr_entries\" entries.\n+ */\n+static void imc_free_events(struct imc_events *events, int nr_entries)\n+{\n+\tint i;\n+\n+\t/* Nothing to clean, return */\n+\tif (!events)\n+\t\treturn;\n+\n+\tfor (i = 0; i < nr_entries; i++) {\n+\t\tif (events[i].ev_name)\n+\t\t\tkfree(events[i].ev_name);\n+\t\tif (events[i].ev_value)\n+\t\t\tkfree(events[i].ev_value);\n+\t}\n+\n+\tkfree(events);\n+}\n+\n+/*\n+ * imc_events_setup() : First finds the event node for the pmu and\n+ *                      gets the number of supported events, then\n+ * allocates memory for the same and parse the events.\n+ */\n+static int imc_events_setup(struct device_node *parent,\n+\t\t\t\t\t   int pmu_index,\n+\t\t\t\t\t   struct imc_pmu *pmu_ptr,\n+\t\t\t\t\t   u32 prop,\n+\t\t\t\t\t   int *idx)\n+{\n+\tstruct device_node *ev_node = NULL, *dir = NULL;\n+\tu32 reg;\n+\tstruct property *scale_pp, *unit_pp, *name_prefix;\n+\tint ret = 0, nr_children = 0;\n+\n+\t/*\n+\t * Fetch the actual node where the events for this PMU exist.\n+\t */\n+\tdir = of_find_node_by_phandle(prop);\n+\tif (!dir)\n+\t\treturn -ENODEV;\n+\t/*\n+\t * Get the maximum no. of events in this node.\n+\t * Multiply by 3 to account for .scale and .unit properties\n+\t * This number suggests the amount of memory needed to setup the\n+\t * events for this pmu.\n+\t */\n+\tnr_children = get_nr_children(dir) * 3;\n+\n+\tpmu_ptr->events = kzalloc((sizeof(struct imc_events) * nr_children),\n+\t\t\t GFP_KERNEL);\n+\tif (!pmu_ptr->events)\n+\t\treturn -ENOMEM;\n+\n+\t/*\n+\t * Check if there is a common \"scale\" and \"unit\" properties inside\n+\t * the PMU node for all the events supported by this PMU.\n+\t */\n+\tscale_pp = of_find_property(parent, \"scale\", NULL);\n+\tunit_pp = of_find_property(parent, \"unit\", NULL);\n+\n+\t/*\n+\t * Get the event-prefix property from the PMU node\n+\t * which needs to be attached with the event names.\n+\t */\n+\tname_prefix = of_find_property(parent, \"events-prefix\", NULL);\n+\tif (!name_prefix)\n+\t\tgoto free_events;\n+\n+\t/*\n+\t * \"reg\" property gives out the base offset of the counters data\n+\t * for this PMU.\n+\t */\n+\tof_property_read_u32(parent, \"reg\", &reg);\n+\n+\tif (!name_prefix->value ||\n+\t   (strnlen(name_prefix->value, name_prefix->length) == name_prefix->length) ||\n+\t   (name_prefix->length > IMC_MAX_NAME_VAL_LEN))\n+\t\tgoto free_events;\n+\n+\t/* Loop through event nodes */\n+\tfor_each_child_of_node(dir, ev_node) {\n+\t\tret = imc_events_node_parser(ev_node, &pmu_ptr->events[*idx], scale_pp,\n+\t\t\t\tunit_pp, name_prefix, reg, pmu_ptr->domain);\n+\t\tif (ret < 0) {\n+\t\t\t/* Unable to parse this event */\n+\t\t\tif (ret == -ENOMEM)\n+\t\t\t\tgoto free_events;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/*\n+\t\t * imc_event_node_parser will return number of\n+\t\t * event entries created for this. This could include\n+\t\t * event scale and unit files also.\n+\t\t */\n+\t\t*idx += ret;\n+\t}\n+\treturn 0;\n+\n+free_events:\n+\timc_free_events(pmu_ptr->events, *idx);\n+\treturn -ENODEV;\n+\n+}\n+\n+/* imc_get_mem_addr_nest: Function to get nest counter memory region for each chip */\n+static int imc_get_mem_addr_nest(struct device_node *node,\n+\t\t\t\t struct imc_pmu *pmu_ptr,\n+\t\t\t\t u32 offset)\n+{\n+\tint nr_chips = 0, i, j;\n+\tu64 *base_addr_arr, baddr;\n+\tu32 *chipid_arr, size = pmu_ptr->counter_mem_size, pages;\n+\n+\tnr_chips = of_property_count_u32_elems(node, \"chip-id\");\n+\tif (!nr_chips)\n+\t\treturn -ENODEV;\n+\n+\tbase_addr_arr = kzalloc((sizeof(u64) * nr_chips), GFP_KERNEL);\n+\tchipid_arr = kzalloc((sizeof(u32) * nr_chips), GFP_KERNEL);\n+\tif (!base_addr_arr || !chipid_arr)\n+\t\treturn -ENOMEM;\n+\n+\tof_property_read_u32_array(node, \"chip-id\", chipid_arr, nr_chips);\n+\tof_property_read_u64_array(node, \"base-addr\", base_addr_arr, nr_chips);\n+\n+\tpmu_ptr->mem_info = kzalloc((sizeof(struct imc_mem_info) * nr_chips), GFP_KERNEL);\n+\tif (!pmu_ptr->mem_info) {\n+\t\tif (base_addr_arr)\n+\t\t\tkfree(base_addr_arr);\n+\t\tif (chipid_arr)\n+\t\t\tkfree(chipid_arr);\n+\n+\t\treturn -ENOMEM;\n+\t\t}\n+\n+\tfor (i = 0; i < nr_chips; i++) {\n+\t\tpmu_ptr->mem_info[i].id = chipid_arr[i];\n+\t\tbaddr = base_addr_arr[i] + offset;\n+\t\tfor (j = 0; j < (size/PAGE_SIZE); j++) {\n+\t\t\tpages = PAGE_SIZE * j;\n+\t\t\tpmu_ptr->mem_info[i].vbase[j] = phys_to_virt(baddr + pages);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+/*\n+ * imc_pmu_create : Takes the parent device which is the pmu unit, pmu_index\n+ *\t\t    and domain as the inputs.\n+ * Allocates memory for the pmu, sets up its domain (NEST), and\n+ * calls imc_events_setup() to allocate memory for the events supported\n+ * by this pmu. Assigns a name for the pmu.\n+ *\n+ * If everything goes fine, it calls, init_imc_pmu() to setup the pmu device\n+ * and register it.\n+ */\n+static int imc_pmu_create(struct device_node *parent, int pmu_index, int domain)\n+{\n+\tu32 prop = 0;\n+\tstruct property *pp;\n+\tchar *buf;\n+\tint idx = 0, ret = 0;\n+\tstruct imc_pmu *pmu_ptr;\n+\tu32 offset;\n+\n+\tif (!parent)\n+\t\treturn -EINVAL;\n+\n+\t/* memory for pmu */\n+\tpmu_ptr = kzalloc(sizeof(struct imc_pmu), GFP_KERNEL);\n+\tif (!pmu_ptr)\n+\t\treturn -ENOMEM;\n+\n+\tpmu_ptr->domain = domain;\n+\n+\t/* Needed for hotplug/migration */\n+\tper_nest_pmu_arr[pmu_index] = pmu_ptr;\n+\n+\tpp = of_find_property(parent, \"name\", NULL);\n+\tif (!pp) {\n+\t\tret = -ENODEV;\n+\t\tgoto free_pmu;\n+\t}\n+\n+\tif (!pp->value ||\n+\t   (strnlen(pp->value, pp->length) == pp->length) ||\n+\t   (pp->length > IMC_MAX_NAME_VAL_LEN)) {\n+\t\tret = -EINVAL;\n+\t\tgoto free_pmu;\n+\t}\n+\n+\tbuf = kzalloc(IMC_MAX_NAME_VAL_LEN, GFP_KERNEL);\n+\tif (!buf) {\n+\t\tret = -ENOMEM;\n+\t\tgoto free_pmu;\n+\t}\n+\t/* Save the name to register it later */\n+\tsprintf(buf, \"nest_%s\", (char *)pp->value);\n+\tpmu_ptr->pmu.name = (char *)buf;\n+\n+\tif (of_property_read_u32(parent, \"size\", &pmu_ptr->counter_mem_size))\n+\t\tpmu_ptr->counter_mem_size = 0;\n+\n+\tif (!of_property_read_u32(parent, \"offset\", &offset)) {\n+\t\tif (imc_get_mem_addr_nest(parent, pmu_ptr, offset))\n+\t\t\tgoto free_pmu;\n+\t\tpmu_ptr->imc_counter_mmaped = 1;\n+\t}\n+\n+\t/*\n+\t * \"events\" property inside a PMU node contains the phandle value\n+\t * for the actual events node. The \"events\" node for the IMC PMU\n+\t * is not in this node, rather inside \"imc-counters\" node, since,\n+\t * we want to factor out the common events (thereby, reducing the\n+\t * size of the device tree)\n+\t */\n+\tif (!of_property_read_u32(parent, \"events\", &prop)) {\n+\t\tif (prop)\n+\t\t\timc_events_setup(parent, pmu_index, pmu_ptr, prop, &idx);\n+\t}\n+\treturn 0;\n+\n+free_pmu:\n+\tif (pmu_ptr)\n+\t\tkfree(pmu_ptr);\n+\treturn ret;\n+}\n+\n static int opal_imc_counters_probe(struct platform_device *pdev)\n {\n \tstruct device_node *imc_dev = NULL;\n+\tint pmu_count = 0, domain;\n+\tu32 type;\n \n \tif (!pdev || !pdev->dev.of_node)\n \t\treturn -ENODEV;\n@@ -50,7 +478,16 @@ static int opal_imc_counters_probe(struct platform_device *pdev)\n \timc_dev = pdev->dev.of_node;\n \tif (!imc_dev)\n \t\treturn -ENODEV;\n-\n+\tfor_each_compatible_node(imc_dev, NULL, IMC_DTB_UNIT_COMPAT) {\n+\t\tif (of_property_read_u32(imc_dev, \"type\", &type))\n+\t\t\tcontinue;\n+\t\tif (type == IMC_COUNTER_PER_CHIP)\n+\t\t\tdomain = IMC_DOMAIN_NEST;\n+\t\telse\n+\t\t\tcontinue;\n+\t\tif (!imc_pmu_create(imc_dev, pmu_count, domain))\n+\t\t\tpmu_count++;\n+\t}\n \treturn 0;\n }\n \n",
    "prefixes": [
        "v12",
        "03/10"
    ]
}