From patchwork Thu Oct 20 09:30:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Glauber X-Patchwork-Id: 9386401 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 0267160487 for ; Thu, 20 Oct 2016 09:33:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E4B2029B8D for ; Thu, 20 Oct 2016 09:33:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D962A29B8F; Thu, 20 Oct 2016 09:33:01 +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=-3.7 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RCVD_IN_SORBS_SPAM autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id B9BE729B8D for ; Thu, 20 Oct 2016 09:33:00 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bx9hM-0000lH-Px; Thu, 20 Oct 2016 09:31:40 +0000 Received: from mail-lf0-f65.google.com ([209.85.215.65]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bx9h4-0000ee-2x for linux-arm-kernel@lists.infradead.org; Thu, 20 Oct 2016 09:31:24 +0000 Received: by mail-lf0-f65.google.com with SMTP id x23so6597319lfi.1 for ; Thu, 20 Oct 2016 02:31:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=opE18n9goWJyzizj14QcuHdTMz4tfSYj0O4nAvaSZmY=; b=d2neo5bg7S2+NGKuKeVAk3/Bm4YYQDwLIWZRv4PX7sRjiU7i/IoF3TZLfX7+nRcRos qOZUyqsscP+bee4AP4xQUimNBrIJszdaxu3k/frykRq+TjKUyWkqE6GRSRdQ092F+3tY iiIjamSQGCYR/9N0wcujyhcSpbJ8OB4gFmewqzY5Y35GUmMcSuJOac2vHYtOXMz3YY0R Y0hhzErLASy3+7DlY9gQ1rSvt7L0/0oS9g3i1RhKJyncpyDz8EC9ZPl5ECxahWkjAp7g mQFuFThWGFA+RCgQuWiEVyrFA10i59GBMZ0lSQhVwt/BJ1G5Whf2ZQUp03LljK+jMPu3 A5vQ== X-Gm-Message-State: AA6/9Rkqk/MNS9grpTlQKdTX1f5l1xBzt9VNyETnGo8+qgeIMapTGKqwtXkJyl4dmlcrzQ== X-Received: by 10.25.72.14 with SMTP id v14mr215543lfa.12.1476955864234; Thu, 20 Oct 2016 02:31:04 -0700 (PDT) Received: from wintermute.fritz.box (HSI-KBW-46-223-67-241.hsi.kabel-badenwuerttemberg.de. [46.223.67.241]) by smtp.gmail.com with ESMTPSA id s63sm5183791lja.3.2016.10.20.02.31.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 20 Oct 2016 02:31:03 -0700 (PDT) From: Jan Glauber To: Mark Rutland , Will Deacon Subject: [PATCH v3 5/5] arm64: perf: Cavium ThunderX OCX TLK uncore support Date: Thu, 20 Oct 2016 11:30:41 +0200 Message-Id: <1476955841-27898-6-git-send-email-jglauber@cavium.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1476955841-27898-1-git-send-email-jglauber@cavium.com> References: <1476955841-27898-1-git-send-email-jglauber@cavium.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161020_023122_589328_49969EB1 X-CRM114-Status: GOOD ( 22.97 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Jan Glauber 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 Support for the OCX transmit link counters. Signed-off-by: Jan Glauber --- drivers/perf/uncore/Makefile | 3 +- drivers/perf/uncore/uncore_cavium.c | 1 + drivers/perf/uncore/uncore_cavium.h | 1 + drivers/perf/uncore/uncore_cavium_ocx_tlk.c | 344 ++++++++++++++++++++++++++++ 4 files changed, 348 insertions(+), 1 deletion(-) create mode 100644 drivers/perf/uncore/uncore_cavium_ocx_tlk.c diff --git a/drivers/perf/uncore/Makefile b/drivers/perf/uncore/Makefile index ef04a2b9..7e2e8e5 100644 --- a/drivers/perf/uncore/Makefile +++ b/drivers/perf/uncore/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_UNCORE_PMU_CAVIUM) += uncore_cavium.o \ uncore_cavium_l2c_tad.o \ uncore_cavium_l2c_cbc.o \ - uncore_cavium_lmc.o + uncore_cavium_lmc.o \ + uncore_cavium_ocx_tlk.o diff --git a/drivers/perf/uncore/uncore_cavium.c b/drivers/perf/uncore/uncore_cavium.c index fd9e49e..46ced45 100644 --- a/drivers/perf/uncore/uncore_cavium.c +++ b/drivers/perf/uncore/uncore_cavium.c @@ -349,6 +349,7 @@ static int __init thunder_uncore_init(void) thunder_uncore_l2c_tad_setup(); thunder_uncore_l2c_cbc_setup(); thunder_uncore_lmc_setup(); + thunder_uncore_ocx_tlk_setup(); return 0; } late_initcall(thunder_uncore_init); diff --git a/drivers/perf/uncore/uncore_cavium.h b/drivers/perf/uncore/uncore_cavium.h index 3897586..43ab426 100644 --- a/drivers/perf/uncore/uncore_cavium.h +++ b/drivers/perf/uncore/uncore_cavium.h @@ -72,3 +72,4 @@ ssize_t thunder_events_sysfs_show(struct device *dev, int thunder_uncore_l2c_tad_setup(void); int thunder_uncore_l2c_cbc_setup(void); int thunder_uncore_lmc_setup(void); +int thunder_uncore_ocx_tlk_setup(void); diff --git a/drivers/perf/uncore/uncore_cavium_ocx_tlk.c b/drivers/perf/uncore/uncore_cavium_ocx_tlk.c new file mode 100644 index 0000000..b50cd67 --- /dev/null +++ b/drivers/perf/uncore/uncore_cavium_ocx_tlk.c @@ -0,0 +1,344 @@ +/* + * Cavium Thunder uncore PMU support, + * CCPI interface controller (OCX) Transmit link (TLK) counters. + * + * Copyright 2016 Cavium Inc. + * Author: Jan Glauber + */ + +#include +#include + +#include "uncore_cavium.h" + +struct thunder_uncore *thunder_uncore_ocx_tlk; + +#define OCX_TLK_NR_UNITS 3 +#define OCX_TLK_UNIT_OFFSET 0x2000 +#define OCX_TLK_STAT_CTL 0x10040 +#define OCX_TLK_STAT_OFFSET 0x10400 + +#define OCX_TLK_STAT_ENABLE_BIT BIT_ULL(0) +#define OCX_TLK_STAT_RESET_BIT BIT_ULL(1) + +/* OCX TLK event list */ +#define OCX_TLK_EVENT_STAT_IDLE_CNT 0x00 +#define OCX_TLK_EVENT_STAT_DATA_CNT 0x08 +#define OCX_TLK_EVENT_STAT_SYNC_CNT 0x10 +#define OCX_TLK_EVENT_STAT_RETRY_CNT 0x18 +#define OCX_TLK_EVENT_STAT_ERR_CNT 0x20 +#define OCX_TLK_EVENT_STAT_MAT0_CNT 0x40 +#define OCX_TLK_EVENT_STAT_MAT1_CNT 0x48 +#define OCX_TLK_EVENT_STAT_MAT2_CNT 0x50 +#define OCX_TLK_EVENT_STAT_MAT3_CNT 0x58 +#define OCX_TLK_EVENT_STAT_VC0_CMD 0x80 +#define OCX_TLK_EVENT_STAT_VC1_CMD 0x88 +#define OCX_TLK_EVENT_STAT_VC2_CMD 0x90 +#define OCX_TLK_EVENT_STAT_VC3_CMD 0x98 +#define OCX_TLK_EVENT_STAT_VC4_CMD 0xa0 +#define OCX_TLK_EVENT_STAT_VC5_CMD 0xa8 +#define OCX_TLK_EVENT_STAT_VC0_PKT 0x100 +#define OCX_TLK_EVENT_STAT_VC1_PKT 0x108 +#define OCX_TLK_EVENT_STAT_VC2_PKT 0x110 +#define OCX_TLK_EVENT_STAT_VC3_PKT 0x118 +#define OCX_TLK_EVENT_STAT_VC4_PKT 0x120 +#define OCX_TLK_EVENT_STAT_VC5_PKT 0x128 +#define OCX_TLK_EVENT_STAT_VC6_PKT 0x130 +#define OCX_TLK_EVENT_STAT_VC7_PKT 0x138 +#define OCX_TLK_EVENT_STAT_VC8_PKT 0x140 +#define OCX_TLK_EVENT_STAT_VC9_PKT 0x148 +#define OCX_TLK_EVENT_STAT_VC10_PKT 0x150 +#define OCX_TLK_EVENT_STAT_VC11_PKT 0x158 +#define OCX_TLK_EVENT_STAT_VC12_PKT 0x160 +#define OCX_TLK_EVENT_STAT_VC13_PKT 0x168 +#define OCX_TLK_EVENT_STAT_VC0_CON 0x180 +#define OCX_TLK_EVENT_STAT_VC1_CON 0x188 +#define OCX_TLK_EVENT_STAT_VC2_CON 0x190 +#define OCX_TLK_EVENT_STAT_VC3_CON 0x198 +#define OCX_TLK_EVENT_STAT_VC4_CON 0x1a0 +#define OCX_TLK_EVENT_STAT_VC5_CON 0x1a8 +#define OCX_TLK_EVENT_STAT_VC6_CON 0x1b0 +#define OCX_TLK_EVENT_STAT_VC7_CON 0x1b8 +#define OCX_TLK_EVENT_STAT_VC8_CON 0x1c0 +#define OCX_TLK_EVENT_STAT_VC9_CON 0x1c8 +#define OCX_TLK_EVENT_STAT_VC10_CON 0x1d0 +#define OCX_TLK_EVENT_STAT_VC11_CON 0x1d8 +#define OCX_TLK_EVENT_STAT_VC12_CON 0x1e0 +#define OCX_TLK_EVENT_STAT_VC13_CON 0x1e8 + +static int ocx_tlk_events[] = { + OCX_TLK_EVENT_STAT_IDLE_CNT, + OCX_TLK_EVENT_STAT_DATA_CNT, + OCX_TLK_EVENT_STAT_SYNC_CNT, + OCX_TLK_EVENT_STAT_RETRY_CNT, + OCX_TLK_EVENT_STAT_ERR_CNT, + OCX_TLK_EVENT_STAT_MAT0_CNT, + OCX_TLK_EVENT_STAT_MAT1_CNT, + OCX_TLK_EVENT_STAT_MAT2_CNT, + OCX_TLK_EVENT_STAT_MAT3_CNT, + OCX_TLK_EVENT_STAT_VC0_CMD, + OCX_TLK_EVENT_STAT_VC1_CMD, + OCX_TLK_EVENT_STAT_VC2_CMD, + OCX_TLK_EVENT_STAT_VC3_CMD, + OCX_TLK_EVENT_STAT_VC4_CMD, + OCX_TLK_EVENT_STAT_VC5_CMD, + OCX_TLK_EVENT_STAT_VC0_PKT, + OCX_TLK_EVENT_STAT_VC1_PKT, + OCX_TLK_EVENT_STAT_VC2_PKT, + OCX_TLK_EVENT_STAT_VC3_PKT, + OCX_TLK_EVENT_STAT_VC4_PKT, + OCX_TLK_EVENT_STAT_VC5_PKT, + OCX_TLK_EVENT_STAT_VC6_PKT, + OCX_TLK_EVENT_STAT_VC7_PKT, + OCX_TLK_EVENT_STAT_VC8_PKT, + OCX_TLK_EVENT_STAT_VC9_PKT, + OCX_TLK_EVENT_STAT_VC10_PKT, + OCX_TLK_EVENT_STAT_VC11_PKT, + OCX_TLK_EVENT_STAT_VC12_PKT, + OCX_TLK_EVENT_STAT_VC13_PKT, + OCX_TLK_EVENT_STAT_VC0_CON, + OCX_TLK_EVENT_STAT_VC1_CON, + OCX_TLK_EVENT_STAT_VC2_CON, + OCX_TLK_EVENT_STAT_VC3_CON, + OCX_TLK_EVENT_STAT_VC4_CON, + OCX_TLK_EVENT_STAT_VC5_CON, + OCX_TLK_EVENT_STAT_VC6_CON, + OCX_TLK_EVENT_STAT_VC7_CON, + OCX_TLK_EVENT_STAT_VC8_CON, + OCX_TLK_EVENT_STAT_VC9_CON, + OCX_TLK_EVENT_STAT_VC10_CON, + OCX_TLK_EVENT_STAT_VC11_CON, + OCX_TLK_EVENT_STAT_VC12_CON, + OCX_TLK_EVENT_STAT_VC13_CON, +}; + +/* + * The OCX devices have a single device per node, therefore picking the + * first device from the list is correct. + */ +static inline void __iomem *map_offset(struct thunder_uncore_node *node, + unsigned long addr, int offset, int nr) +{ + struct thunder_uncore_unit *unit; + + unit = list_first_entry(&node->unit_list, struct thunder_uncore_unit, + entry); + return (void __iomem *)(addr + unit->map + nr * offset); +} + +static void __iomem *map_offset_ocx_tlk(struct thunder_uncore_node *node, + unsigned long addr, int nr) +{ + return (void __iomem *)map_offset(node, addr, nr, OCX_TLK_UNIT_OFFSET); +} + +/* + * The OCX TLK counters can only be enabled/disabled as a set so we do + * this in pmu_enable/disable instead of start/stop. + */ +static void thunder_uncore_pmu_enable_ocx_tlk(struct pmu *pmu) +{ + struct thunder_uncore *uncore = + container_of(pmu, struct thunder_uncore, pmu); + int node = 0, i; + + while (uncore->nodes[node++]) { + for (i = 0; i < OCX_TLK_NR_UNITS; i++) { + /* reset all TLK counters to zero */ + writeb(OCX_TLK_STAT_RESET_BIT, + map_offset_ocx_tlk(uncore->nodes[node], + OCX_TLK_STAT_CTL, i)); + /* enable all TLK counters */ + writeb(OCX_TLK_STAT_ENABLE_BIT, + map_offset_ocx_tlk(uncore->nodes[node], + OCX_TLK_STAT_CTL, i)); + } + } +} + +/* + * The OCX TLK counters can only be enabled/disabled as a set so we do + * this in pmu_enable/disable instead of start/stop. + */ +static void thunder_uncore_pmu_disable_ocx_tlk(struct pmu *pmu) +{ + struct thunder_uncore *uncore = + container_of(pmu, struct thunder_uncore, pmu); + int node = 0, i; + + while (uncore->nodes[node++]) { + for (i = 0; i < OCX_TLK_NR_UNITS; i++) { + /* disable all TLK counters */ + writeb(0, map_offset_ocx_tlk(uncore->nodes[node], + OCX_TLK_STAT_CTL, i)); + } + } +} + +/* + * Summarize counters across all TLK's. Different from the other uncore + * PMUs because all TLK's are on one PCI device. + */ +static void thunder_uncore_read_ocx_tlk(struct perf_event *event) +{ + struct thunder_uncore *uncore = to_uncore(event->pmu); + struct hw_perf_event *hwc = &event->hw; + struct thunder_uncore_node *node; + u64 new = 0; + int i; + + /* read counter values from all units */ + node = get_node(hwc->config, uncore); + for (i = 0; i < OCX_TLK_NR_UNITS; i++) + new += readq(map_offset_ocx_tlk(node, hwc->event_base, i)); + + local64_add(new, &hwc->prev_count); + local64_add(new, &event->count); +} + +static void thunder_uncore_start_ocx_tlk(struct perf_event *event, int flags) +{ + struct thunder_uncore *uncore = to_uncore(event->pmu); + struct hw_perf_event *hwc = &event->hw; + struct thunder_uncore_node *node; + u64 new = 0; + int i; + + /* read counter values from all units on the node */ + node = get_node(hwc->config, uncore); + for (i = 0; i < OCX_TLK_NR_UNITS; i++) + new += readq(map_offset_ocx_tlk(node, hwc->event_base, i)); + local64_set(&hwc->prev_count, new); + + hwc->state = 0; + perf_event_update_userpage(event); +} + +static int thunder_uncore_add_ocx_tlk(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + + return thunder_uncore_add(event, flags, + OCX_TLK_STAT_CTL, + OCX_TLK_STAT_OFFSET + ocx_tlk_events[get_id(hwc->config)]); +} + +PMU_FORMAT_ATTR(event, "config:0-5"); + +static struct attribute *thunder_ocx_tlk_format_attr[] = { + &format_attr_event.attr, + &format_attr_node.attr, + NULL, +}; + +static struct attribute_group thunder_ocx_tlk_format_group = { + .name = "format", + .attrs = thunder_ocx_tlk_format_attr, +}; + +static struct attribute *thunder_ocx_tlk_events_attr[] = { + UC_EVENT_ENTRY(idle_cnt, 0), + UC_EVENT_ENTRY(data_cnt, 1), + UC_EVENT_ENTRY(sync_cnt, 2), + UC_EVENT_ENTRY(retry_cnt, 3), + UC_EVENT_ENTRY(err_cnt, 4), + UC_EVENT_ENTRY(mat0_cnt, 5), + UC_EVENT_ENTRY(mat1_cnt, 6), + UC_EVENT_ENTRY(mat2_cnt, 7), + UC_EVENT_ENTRY(mat3_cnt, 8), + UC_EVENT_ENTRY(vc0_cmd, 9), + UC_EVENT_ENTRY(vc1_cmd, 10), + UC_EVENT_ENTRY(vc2_cmd, 11), + UC_EVENT_ENTRY(vc3_cmd, 12), + UC_EVENT_ENTRY(vc4_cmd, 13), + UC_EVENT_ENTRY(vc5_cmd, 14), + UC_EVENT_ENTRY(vc0_pkt, 15), + UC_EVENT_ENTRY(vc1_pkt, 16), + UC_EVENT_ENTRY(vc2_pkt, 17), + UC_EVENT_ENTRY(vc3_pkt, 18), + UC_EVENT_ENTRY(vc4_pkt, 19), + UC_EVENT_ENTRY(vc5_pkt, 20), + UC_EVENT_ENTRY(vc6_pkt, 21), + UC_EVENT_ENTRY(vc7_pkt, 22), + UC_EVENT_ENTRY(vc8_pkt, 23), + UC_EVENT_ENTRY(vc9_pkt, 24), + UC_EVENT_ENTRY(vc10_pkt, 25), + UC_EVENT_ENTRY(vc11_pkt, 26), + UC_EVENT_ENTRY(vc12_pkt, 27), + UC_EVENT_ENTRY(vc13_pkt, 28), + UC_EVENT_ENTRY(vc0_con, 29), + UC_EVENT_ENTRY(vc1_con, 30), + UC_EVENT_ENTRY(vc2_con, 31), + UC_EVENT_ENTRY(vc3_con, 32), + UC_EVENT_ENTRY(vc4_con, 33), + UC_EVENT_ENTRY(vc5_con, 34), + UC_EVENT_ENTRY(vc6_con, 35), + UC_EVENT_ENTRY(vc7_con, 36), + UC_EVENT_ENTRY(vc8_con, 37), + UC_EVENT_ENTRY(vc9_con, 38), + UC_EVENT_ENTRY(vc10_con, 39), + UC_EVENT_ENTRY(vc11_con, 40), + UC_EVENT_ENTRY(vc12_con, 41), + UC_EVENT_ENTRY(vc13_con, 42), + NULL, +}; + +static struct attribute_group thunder_ocx_tlk_events_group = { + .name = "events", + .attrs = thunder_ocx_tlk_events_attr, +}; + +static const struct attribute_group *thunder_ocx_tlk_attr_groups[] = { + &thunder_uncore_attr_group, + &thunder_ocx_tlk_format_group, + &thunder_ocx_tlk_events_group, + NULL, +}; + +struct pmu thunder_ocx_tlk_pmu = { + .name = "thunder_ocx_tlk", + .task_ctx_nr = perf_sw_context, + .pmu_enable = thunder_uncore_pmu_enable_ocx_tlk, + .pmu_disable = thunder_uncore_pmu_disable_ocx_tlk, + .event_init = thunder_uncore_event_init, + .add = thunder_uncore_add_ocx_tlk, + .del = thunder_uncore_del, + .start = thunder_uncore_start_ocx_tlk, + .stop = thunder_uncore_stop, + .read = thunder_uncore_read_ocx_tlk, + .attr_groups = thunder_ocx_tlk_attr_groups, +}; + +static bool event_valid(u64 config) +{ + if (config < ARRAY_SIZE(ocx_tlk_events)) + return true; + + return false; +} + +int __init thunder_uncore_ocx_tlk_setup(void) +{ + int ret; + + thunder_uncore_ocx_tlk = kzalloc(sizeof(*thunder_uncore_ocx_tlk), + GFP_KERNEL); + if (!thunder_uncore_ocx_tlk) { + ret = -ENOMEM; + goto fail_nomem; + } + + ret = thunder_uncore_setup(thunder_uncore_ocx_tlk, 0xa013, + &thunder_ocx_tlk_pmu, + ARRAY_SIZE(ocx_tlk_events)); + if (ret) + goto fail; + + thunder_uncore_ocx_tlk->event_valid = event_valid; + return 0; + +fail: + kfree(thunder_uncore_ocx_tlk); +fail_nomem: + return ret; +}