From patchwork Fri Mar 10 06:28:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anurup M X-Patchwork-Id: 9615143 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id BDA1860417 for ; Fri, 10 Mar 2017 06:32:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AD13028528 for ; Fri, 10 Mar 2017 06:32:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A0EB928581; Fri, 10 Mar 2017 06:32:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, DKIM_VALID, FREEMAIL_FROM autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D688A28528 for ; Fri, 10 Mar 2017 06:32:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=3MPLnFyemwFVUyb2Bjv/rFByVNKNIU4MgAz9y1IUorc=; b=BtX CR3y4n+uwSCFBeNYKdgE7VbVagNL4L57kA5/54yjJvVaWqSIWWcvn0BqD7hhmR07MuK8xaImFWedj p8U2FS1cONHaycafqiKpQ/AutAecC20No70CgYOzNotync2a9vgmRLLoQDJBsLK3K8f8AdzMUKGOK /RVop3vxBlXk/VUNlbFtMuTAnomcqfsejR7l9ZUvIgL16xxHtugZWzJU+tGmvQB9xX4JVSUVWaYmS TnB/WIt3uDP8tgWydpwN+nCa+KsxD3ftucFaU0ooNrmn6HZZmKHcbH79uJmJEgzi4Qt0OmzG756L6 UiqyM8H7NDAmGOukyb3Hquf1icRpshQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1cmE5z-00044H-8Y; Fri, 10 Mar 2017 06:32:11 +0000 Received: from mail-pg0-x241.google.com ([2607:f8b0:400e:c05::241]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1cmE3F-0000zz-H5 for linux-arm-kernel@lists.infradead.org; Fri, 10 Mar 2017 06:29:26 +0000 Received: by mail-pg0-x241.google.com with SMTP id g2so4755401pge.2 for ; Thu, 09 Mar 2017 22:29:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=GvaMU6joJ+6+NpU+To+rlUdpB0pwgCES7U9sCN7IfFA=; b=vglh3HaH+g3IEXazIJfScHUfjOi7MqCxNb2tGr5aWCQAdlzT1D2szZGxybZM+4Nkmu qrjEOeJr5hm+MyzxdcKI5KSCqNAMUyFux8LExn32ALYYUtmE8ZfgW146LJp7IJfZ/Ygh VBKNKgC7JLLinENPqJOiNOuD3AZdclkMis/CythL4RCOtVEnHE+IWIFdGO+I4bF+L8/t UZlFKe5Ub9Ok//IIG+DjgxLwbkn0uOncrzp6npvo+LeebJJ0+NvRTFNdk5qrovEnJGpa L2nrjQMVMpbwMhVS0IPgvLa+O+EO916ojpHvmlfBgqn2rsJ0+KPzzHbnRuvNnaV2Eis+ 9T+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=GvaMU6joJ+6+NpU+To+rlUdpB0pwgCES7U9sCN7IfFA=; b=R+p9TbCeRqCoXX8zKOvm6sJMByc3Vwu+LePy/4uN9IKzHtBdqhbYE0u1Ut1wyty8YX 1NVIWYqijZ/O6vnpIQEOGrKIy+Ir4XN7Zvt/yrlMqXUON3qdyb4pAQGTnXEeLBauuHAt JjlDBGs5/63t+91lbx5WJXYy9MF5qq+WqWrAJuRX9glp4g5iEjvrXx6o6I7C5mKRSOXZ 5EG7Woogq2II5pd9PSSHL3spabuLF4ZLxgn9Jo93B5PxrWo4CYmNlOwhsxEisfv8siLv eKLDR0nFdndHzdkzU3UOlPMlq1ftLrMdRKBJvGkRB3bkuIANfUwIPynOm03hgvmFPuEF xQZg== X-Gm-Message-State: AMke39lH53k3WbBzEgI7eHVni3S3xOJCFuQIlCnfG7doTkLlCUBOO3QU0pAnwexz7P2mtQ== X-Received: by 10.84.197.1 with SMTP id m1mr23395915pld.123.1489127340942; Thu, 09 Mar 2017 22:29:00 -0800 (PST) Received: from localhost.localdomain ([14.141.5.98]) by smtp.gmail.com with ESMTPSA id h3sm16046512pfc.82.2017.03.09.22.28.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 09 Mar 2017 22:29:00 -0800 (PST) From: Anurup M X-Google-Original-From: Anurup M To: mark.rutland@arm.com, will.deacon@arm.com Subject: [PATCH v6 09/11] drivers: perf: hisi: Miscellanous node(MN) event counting in perf Date: Fri, 10 Mar 2017 01:28:53 -0500 Message-Id: <1489127333-112865-1-git-send-email-anurup.m@huawei.com> X-Mailer: git-send-email 2.1.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170309_222922_007360_BC238C6E X-CRM114-Status: GOOD ( 21.92 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dikshit.n@huawei.com, shyju.pv@huawei.com, anurupvasu@gmail.com, gabriele.paoloni@huawei.com, huangdaode@hisilicon.com, john.garry@huawei.com, linux-kernel@vger.kernel.org, xuwei5@hisilicon.com, linuxarm@huawei.com, zhangshaokun@hisilicon.com, sanil.kumar@hisilicon.com, linux-arm-kernel@lists.infradead.org, shiju.jose@huawei.com, tanxiaojun@huawei.com, anurup.m@huawei.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Shaokun Zhang 1. Add support to count MN hardware events. 2. Mn events are listed in sysfs at /sys/devices/hisi_mn_2/events/ The events can be selected as shown in perf list e.g.: For MN_READ_REQUEST event for Super CPU cluster 2 the event format is -e "hisi_mn_2/read_req/" Signed-off-by: Shaokun Zhang Signed-off-by: Anurup M --- drivers/perf/hisilicon/Makefile | 2 +- drivers/perf/hisilicon/hisi_uncore_mn.c | 489 ++++++++++++++++++++++++++++++++ 2 files changed, 490 insertions(+), 1 deletion(-) create mode 100644 drivers/perf/hisilicon/hisi_uncore_mn.c diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile index 0887b56..26b2507 100644 --- a/drivers/perf/hisilicon/Makefile +++ b/drivers/perf/hisilicon/Makefile @@ -1 +1 @@ -obj-$(CONFIG_HISI_PMU) += djtag.o hisi_uncore_pmu.o hisi_uncore_l3c.o +obj-$(CONFIG_HISI_PMU) += djtag.o hisi_uncore_pmu.o hisi_uncore_l3c.o hisi_uncore_mn.o diff --git a/drivers/perf/hisilicon/hisi_uncore_mn.c b/drivers/perf/hisilicon/hisi_uncore_mn.c new file mode 100644 index 0000000..18316dc --- /dev/null +++ b/drivers/perf/hisilicon/hisi_uncore_mn.c @@ -0,0 +1,489 @@ +/* + * HiSilicon SoC MN Hardware event counters support + * + * Copyright (C) 2017 Hisilicon Limited + * Author: Shaokun Zhang + * + * This code is based on the uncore PMU's like arm-cci and + * arm-ccn. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include "hisi_uncore_pmu.h" + +/* + * ARMv8 HiSilicon MN event types. + */ +enum armv8_hisi_mn_event_types { + HISI_HWEVENT_MN_EO_BARR_REQ = 0x0, + HISI_HWEVENT_MN_EC_BARR_REQ = 0x01, + HISI_HWEVENT_MN_DVM_OP_REQ = 0x02, + HISI_HWEVENT_MN_DVM_SYNC_REQ = 0x03, + HISI_HWEVENT_MN_READ_REQ = 0x04, + HISI_HWEVENT_MN_WRITE_REQ = 0x05, + HISI_HWEVENT_MN_EVENT_MAX = 0x08, +}; + +/* + * ARMv8 HiSilicon Hardware counter Index. + */ +enum armv8_hisi_mn_counters { + HISI_IDX_MN_COUNTER0 = 0x0, + HISI_IDX_MN_COUNTER_MAX = 0x4, +}; + +#define HISI_MAX_CFG_MN_CNTR 0x04 +#define MN1_EVTYPE_REG_OFF 0x48 +#define MN1_EVCTRL_REG_OFF 0x40 +#define MN1_CNT0_REG_OFF 0x30 +#define MN1_EVENT_EN 0x01 +#define MN1_BANK_SELECT 0x01 + +#define GET_MODULE_ID(hwmod_data) hwmod_data->mn_hwcfg.module_id + +struct hisi_mn_hwcfg { + u32 module_id; +}; + +struct hisi_mn_data { + struct hisi_djtag_client *client; + DECLARE_BITMAP(event_used_mask, HISI_MAX_CFG_MN_CNTR); + struct hisi_mn_hwcfg mn_hwcfg; +}; + +static inline int hisi_mn_counter_valid(int idx) +{ + return (idx >= HISI_IDX_MN_COUNTER0 && + idx < HISI_IDX_MN_COUNTER_MAX); +} + +/* Select the counter register offset from the index */ +static inline u32 get_counter_reg_off(int cntr_idx) +{ + return (MN1_CNT0_REG_OFF + (cntr_idx * 4)); +} + +static u32 hisi_mn_read_counter(struct hisi_mn_data *mn_data, int cntr_idx) +{ + struct hisi_djtag_client *client = mn_data->client; + u32 module_id = GET_MODULE_ID(mn_data); + u32 reg_off, value; + + reg_off = get_counter_reg_off(cntr_idx); + hisi_djtag_readreg(module_id, MN1_BANK_SELECT, reg_off, + client, &value); + + return value; +} + +static u64 hisi_mn_event_update(struct perf_event *event, + struct hw_perf_event *hwc, int idx) +{ + struct hisi_pmu *mn_pmu = to_hisi_pmu(event->pmu); + struct hisi_mn_data *mn_data = mn_pmu->hwmod_data; + u64 delta, prev_raw_count, new_raw_count = 0; + + if (!hisi_mn_counter_valid(idx)) { + dev_err(mn_pmu->dev, + "Unsupported event index:%d!\n", idx); + return 0; + } + + do { + /* Get count from the MN */ + prev_raw_count = local64_read(&hwc->prev_count); + new_raw_count = hisi_mn_read_counter(mn_data, idx); + delta = (new_raw_count - prev_raw_count) & HISI_MAX_PERIOD; + + local64_add(delta, &event->count); + } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count) != prev_raw_count); + + return new_raw_count; +} + +static void hisi_mn_set_evtype(struct hisi_pmu *mn_pmu, int idx, u32 val) +{ + struct hisi_mn_data *mn_data = mn_pmu->hwmod_data; + struct hisi_djtag_client *client = mn_data->client; + u32 module_id = GET_MODULE_ID(mn_data); + u32 event_value, value = 0; + + event_value = (val - HISI_HWEVENT_MN_EO_BARR_REQ); + + /* + * Value to write to event select register + * Each byte in the 32 bit select register is used to + * configure the event code. Each byte correspond to a + * counter register to use. + */ + val = event_value << (8 * idx); + + /* + * Set the event in MN_EVENT_TYPE Register + */ + hisi_djtag_readreg(module_id, MN1_BANK_SELECT, MN1_EVTYPE_REG_OFF, + client, &value); + value &= ~(0xff << (8 * idx)); + value |= val; + hisi_djtag_writereg(module_id, MN1_BANK_SELECT, MN1_EVTYPE_REG_OFF, + value, client); +} + +static void hisi_mn_clear_evtype(struct hisi_pmu *mn_pmu, int idx) +{ + struct hisi_mn_data *mn_data = mn_pmu->hwmod_data; + struct hisi_djtag_client *client = mn_data->client; + u32 module_id = GET_MODULE_ID(mn_data); + u32 value; + + if (!hisi_mn_counter_valid(idx)) { + dev_err(mn_pmu->dev, + "Unsupported event index:%d!\n", idx); + return; + } + + /* + * Clear the event in MN_EVENT_TYPE Register + */ + hisi_djtag_readreg(module_id, MN1_BANK_SELECT, MN1_EVTYPE_REG_OFF, + client, &value); + value &= ~(0xff << (8 * idx)); + value |= (0xff << (8 * idx)); + hisi_djtag_writereg(module_id, MN1_BANK_SELECT, MN1_EVTYPE_REG_OFF, + value, client); +} + +static u32 hisi_mn_write_counter(struct hisi_pmu *mn_pmu, + struct hw_perf_event *hwc, u32 value) +{ + struct hisi_mn_data *mn_data = mn_pmu->hwmod_data; + struct hisi_djtag_client *client = mn_data->client; + u32 module_id = GET_MODULE_ID(mn_data); + u32 reg_off; + int idx = GET_CNTR_IDX(hwc); + int ret; + + if (!hisi_mn_counter_valid(idx)) { + dev_err(mn_pmu->dev, "Unsupported event index:%d!\n", idx); + return -EINVAL; + } + + reg_off = get_counter_reg_off(idx); + ret = hisi_djtag_writereg(module_id, MN1_BANK_SELECT, reg_off, + value, client); + if (!ret) + ret = value; + + return ret; +} + +static void hisi_mn_start_counters(struct hisi_pmu *mn_pmu) +{ + struct hisi_mn_data *mn_data = mn_pmu->hwmod_data; + struct hisi_djtag_client *client = mn_data->client; + unsigned long *used_mask = mn_data->event_used_mask; + u32 module_id = GET_MODULE_ID(mn_data); + u32 num_counters = mn_pmu->num_counters; + u32 value; + int enabled = bitmap_weight(used_mask, num_counters); + + if (!enabled) + return; + + /* + * Set the event_bus_en bit in MN_EVENT_CTRL to start counting + * for the L3C bank + */ + hisi_djtag_readreg(module_id, MN1_BANK_SELECT, MN1_EVCTRL_REG_OFF, + client, &value); + value |= MN1_EVENT_EN; + hisi_djtag_writereg(module_id, MN1_BANK_SELECT, MN1_EVCTRL_REG_OFF, + value, client); +} + +static void hisi_mn_stop_counters(struct hisi_pmu *mn_pmu) +{ + struct hisi_mn_data *mn_data = mn_pmu->hwmod_data; + struct hisi_djtag_client *client = mn_data->client; + u32 module_id = GET_MODULE_ID(mn_data); + u32 value; + + /* + * Clear the event_bus_en bit in MN_EVENT_CTRL + */ + hisi_djtag_readreg(module_id, MN1_BANK_SELECT, MN1_EVCTRL_REG_OFF, + client, &value); + value &= ~(MN1_EVENT_EN); + hisi_djtag_writereg(module_id, MN1_BANK_SELECT, MN1_EVCTRL_REG_OFF, + value, client); +} + +static void hisi_mn_clear_event_idx(struct hisi_pmu *mn_pmu, int idx) +{ + struct hisi_mn_data *mn_data = mn_pmu->hwmod_data; + void *bitmap_addr; + + if (!hisi_mn_counter_valid(idx)) { + dev_err(mn_pmu->dev, "Unsupported event index:%d!\n", idx); + return; + } + + bitmap_addr = mn_data->event_used_mask; + clear_bit(idx, bitmap_addr); +} + +static int hisi_mn_get_event_idx(struct hisi_pmu *mn_pmu) +{ + struct hisi_mn_data *mn_data = mn_pmu->hwmod_data; + const unsigned long *used_mask = mn_data->event_used_mask; + u32 num_counters = mn_pmu->num_counters; + int event_idx; + + event_idx = find_first_zero_bit(used_mask, num_counters); + if (event_idx == num_counters) + return -EAGAIN; + + set_bit(event_idx, mn_data->event_used_mask); + + return event_idx; +} + +static const struct of_device_id mn_of_match[] = { + { .compatible = "hisilicon,hip05-pmu-mn-v1", }, + { .compatible = "hisilicon,hip06-pmu-mn-v1", }, + { .compatible = "hisilicon,hip07-pmu-mn-v2", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mn_of_match); + +static int hisi_mn_init_data(struct hisi_pmu *mn_pmu, + struct hisi_djtag_client *client) +{ + struct hisi_mn_data *mn_data; + struct hisi_mn_hwcfg *mn_hwcfg; + struct device *dev = &client->dev; + int ret; + + mn_data = devm_kzalloc(dev, sizeof(*mn_data), GFP_KERNEL); + if (!mn_data) + return -ENOMEM; + + /* Set the djtag Identifier */ + mn_data->client = client; + mn_pmu->hw_perf_events = devm_kcalloc(dev, mn_pmu->num_counters, + sizeof(*mn_pmu->hw_perf_events), + GFP_KERNEL); + if (!mn_pmu->hw_perf_events) + return -ENOMEM; + + raw_spin_lock_init(&mn_pmu->lock); + mn_pmu->hwmod_data = mn_data; + mn_hwcfg = &mn_data->mn_hwcfg; + + if (dev->of_node) { + const struct of_device_id *of_id; + + of_id = of_match_device(mn_of_match, dev); + if (!of_id) { + dev_err(dev, "DT: Match device fail!\n"); + return -EINVAL; + } + + ret = device_property_read_u32(dev, "hisilicon,module-id", + &mn_hwcfg->module_id); + if (ret < 0) { + dev_err(dev, "DT: Could not read module-id!\n"); + return -EINVAL; + } + } else + return -EINVAL; + + return 0; +} + +static struct attribute *hisi_mn_format_attr[] = { + HISI_PMU_FORMAT_ATTR(event, "config:0-11"), + NULL, +}; + +static const struct attribute_group hisi_mn_format_group = { + .name = "format", + .attrs = hisi_mn_format_attr, +}; + +static struct attribute *hisi_mn_events_attr[] = { + HISI_PMU_EVENT_ATTR_STR(eo_barrier_req, "event=0x0"), + HISI_PMU_EVENT_ATTR_STR(ec_barrier_req, "event=0x01"), + HISI_PMU_EVENT_ATTR_STR(dvm_op_req, "event=0x02"), + HISI_PMU_EVENT_ATTR_STR(dvm_sync_req, "event=0x03"), + HISI_PMU_EVENT_ATTR_STR(read_req, "event=0x04"), + HISI_PMU_EVENT_ATTR_STR(write_req, "event=0x05"), + NULL, +}; + +static const struct attribute_group hisi_mn_events_group = { + .name = "events", + .attrs = hisi_mn_events_attr, +}; + +static struct attribute *hisi_mn_attrs[] = { + NULL, +}; + +static const struct attribute_group hisi_mn_attr_group = { + .attrs = hisi_mn_attrs, +}; + +static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); + +static struct attribute *hisi_mn_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL, +}; + +static const struct attribute_group hisi_mn_cpumask_attr_group = { + .attrs = hisi_mn_cpumask_attrs, +}; + +static const struct attribute_group *hisi_mn_pmu_attr_groups[] = { + &hisi_mn_attr_group, + &hisi_mn_format_group, + &hisi_mn_events_group, + &hisi_mn_cpumask_attr_group, + NULL, +}; + +static struct hisi_uncore_ops hisi_uncore_mn_ops = { + .set_evtype = hisi_mn_set_evtype, + .clear_evtype = hisi_mn_clear_evtype, + .set_event_period = hisi_pmu_set_event_period, + .get_event_idx = hisi_mn_get_event_idx, + .clear_event_idx = hisi_mn_clear_event_idx, + .event_update = hisi_mn_event_update, + .start_counters = hisi_mn_start_counters, + .stop_counters = hisi_mn_stop_counters, + .write_counter = hisi_mn_write_counter, +}; + +static int hisi_mn_pmu_init(struct hisi_pmu *mn_pmu, + struct hisi_djtag_client *client) +{ + struct device *dev = &client->dev; + + mn_pmu->num_events = HISI_HWEVENT_MN_EVENT_MAX; + mn_pmu->num_counters = HISI_IDX_MN_COUNTER_MAX; + mn_pmu->scl_id = hisi_djtag_get_sclid(client); + + mn_pmu->name = kasprintf(GFP_KERNEL, "hisi_mn_%d", mn_pmu->scl_id); + mn_pmu->ops = &hisi_uncore_mn_ops; + mn_pmu->dev = dev; + + /* Pick one core to use for cpumask attributes */ + cpumask_set_cpu(smp_processor_id(), &mn_pmu->cpu); + + return 0; +} + +static int hisi_pmu_mn_dev_probe(struct hisi_djtag_client *client) +{ + struct hisi_pmu *mn_pmu; + struct device *dev = &client->dev; + int ret; + + mn_pmu = hisi_pmu_alloc(dev); + if (!mn_pmu) + return -ENOMEM; + + ret = hisi_mn_pmu_init(mn_pmu, client); + if (ret) + return ret; + + ret = hisi_mn_init_data(mn_pmu, client); + if (ret) + return ret; + + mn_pmu->pmu = (struct pmu) { + .name = mn_pmu->name, + .task_ctx_nr = perf_invalid_context, + .event_init = hisi_uncore_pmu_event_init, + .pmu_enable = hisi_uncore_pmu_enable, + .pmu_disable = hisi_uncore_pmu_disable, + .add = hisi_uncore_pmu_add, + .del = hisi_uncore_pmu_del, + .start = hisi_uncore_pmu_start, + .stop = hisi_uncore_pmu_stop, + .read = hisi_uncore_pmu_read, + .attr_groups = hisi_mn_pmu_attr_groups, + }; + + ret = hisi_uncore_pmu_setup(mn_pmu, mn_pmu->name); + if (ret) { + dev_err(mn_pmu->dev, "hisi_uncore_pmu_init FAILED!!\n"); + return ret; + } + + /* Set the drv data to MN pmu */ + dev_set_drvdata(dev, mn_pmu); + + return 0; +} + +static int hisi_pmu_mn_dev_remove(struct hisi_djtag_client *client) +{ + struct hisi_pmu *mn_pmu = NULL; + struct device *dev = &client->dev; + + mn_pmu = dev_get_drvdata(dev); + perf_pmu_unregister(&mn_pmu->pmu); + + return 0; +} + +static struct hisi_djtag_driver hisi_pmu_mn_driver = { + .driver = { + .name = "hisi-pmu-mn", + .of_match_table = mn_of_match, + }, + .probe = hisi_pmu_mn_dev_probe, + .remove = hisi_pmu_mn_dev_remove, +}; + +static int __init hisi_pmu_mn_init(void) +{ + int rc; + + rc = hisi_djtag_register_driver(THIS_MODULE, &hisi_pmu_mn_driver); + if (rc < 0) { + pr_err("hisi pmu MN init failed, rc=%d\n", rc); + return rc; + } + + return 0; +} +module_init(hisi_pmu_mn_init); + +static void __exit hisi_pmu_mn_exit(void) +{ + hisi_djtag_unregister_driver(&hisi_pmu_mn_driver); +} +module_exit(hisi_pmu_mn_exit); + +MODULE_DESCRIPTION("HiSilicon SoC HIP0x MN PMU driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Shaokun Zhang");