From patchwork Wed May 15 02:58:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dinh Nguyen X-Patchwork-Id: 2569651 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork2.kernel.org (Postfix) with ESMTP id 0B0C7DF24C for ; Wed, 15 May 2013 03:00:48 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UcRv7-0007TU-Ap; Wed, 15 May 2013 02:58:29 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UcRtb-0005kt-UE; Wed, 15 May 2013 02:56:51 +0000 Received: from tx2ehsobe001.messaging.microsoft.com ([65.55.88.11] helo=tx2outboundpool.messaging.microsoft.com) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UcRtY-0005jl-Dc for linux-arm-kernel@lists.infradead.org; Wed, 15 May 2013 02:56:49 +0000 Received: from mail30-tx2-R.bigfish.com (10.9.14.228) by TX2EHSOBE012.bigfish.com (10.9.40.32) with Microsoft SMTP Server id 14.1.225.23; Wed, 15 May 2013 02:56:26 +0000 Received: from mail30-tx2 (localhost [127.0.0.1]) by mail30-tx2-R.bigfish.com (Postfix) with ESMTP id F3BBE3A0232; Wed, 15 May 2013 02:56:25 +0000 (UTC) X-Forefront-Antispam-Report: CIP:66.35.236.232; KIP:(null); UIP:(null); IPV:NLI; H:SJ-ITEXEDGE02.altera.priv.altera.com; RD:none; EFVD:NLI X-SpamScore: 3 X-BigFish: VS3(zzc8kzz1f42h1ee6h1de0h1fdah1202h1e76h1d1ah1d2ah1fc6hzz17326ah8275bh8275dh8275chz2fh2a8h668h839hd24he5bhf0ah1288h12a5h12a9h12bdh12e5h137ah139eh13b6h1441h14ddh1504h1537h162dh1631h1758h1898h18e1h1946h19b5h1ad9h1b0ah1d0ch1d2eh1d3fh1155h) Received-SPF: pass (mail30-tx2: domain of altera.com designates 66.35.236.232 as permitted sender) client-ip=66.35.236.232; envelope-from=dinguyen@altera.com; helo=SJ-ITEXEDGE02.altera.priv.altera.com ; v.altera.com ; Received: from mail30-tx2 (localhost.localdomain [127.0.0.1]) by mail30-tx2 (MessageSwitch) id 1368586584479056_21546; Wed, 15 May 2013 02:56:24 +0000 (UTC) Received: from TX2EHSMHS037.bigfish.com (unknown [10.9.14.225]) by mail30-tx2.bigfish.com (Postfix) with ESMTP id 7065A200072; Wed, 15 May 2013 02:56:24 +0000 (UTC) Received: from SJ-ITEXEDGE02.altera.priv.altera.com (66.35.236.232) by TX2EHSMHS037.bigfish.com (10.9.99.137) with Microsoft SMTP Server (TLS) id 14.1.225.23; Wed, 15 May 2013 02:56:24 +0000 Received: from sj-mail01.altera.com (137.57.1.6) by SJ-ITEXEDGE02.altera.priv.altera.com (66.35.236.232) with Microsoft SMTP Server id 8.3.298.1; Tue, 14 May 2013 19:46:33 -0700 Received: from linux-builds1.altera.com (linux-builds1.altera.com [137.57.188.121]) by sj-mail01.altera.com (8.13.7+Sun/8.13.7) with ESMTP id r4F2uGLw025534; Tue, 14 May 2013 19:56:21 -0700 (PDT) From: To: Subject: [RFC PATCH] ARM: SOCFPGA: Enable PMU through the CTI Date: Tue, 14 May 2013 21:58:02 -0500 Message-ID: <1368586682-19848-1-git-send-email-dinguyen@altera.com> X-Mailer: git-send-email 1.7.9.5 MIME-Version: 1.0 X-OriginatorOrg: altera.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130514_225648_630009_4748CE01 X-CRM114-Status: GOOD ( 28.16 ) X-Spam-Score: -4.2 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [65.55.88.11 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Paul Walmsley , dinh.linux@gmail.com, Arnd Bergmann , Pavel Machek , Ming Lei , Will Deacon , Olof Johansson , Russell King , Dinh Nguyen X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Dinh Nguyen SOCFPGA has a PMU(Performance Measurement Unit) that has its IRQs routed through Coresight using the CTI(Cross-Trigger Interface). This patch enables the PMU and initializes the CTI for usage by oprofile/perfmon. A lot of the code/idea was taken from this: https://patchwork.kernel.org/patch/1432541/ Signed-off-by: Dinh Nguyen CC: Ming Lei CC: Will Deacon Cc: Paul Walmsley Cc: Russell King CC: Arnd Bergmann CC: Olof Johansson Cc: Pavel Machek --- arch/arm/boot/dts/socfpga.dtsi | 18 +++++ arch/arm/include/asm/pmu.h | 3 + arch/arm/kernel/perf_event.c | 16 +++++ arch/arm/mach-socfpga/Makefile | 1 + arch/arm/mach-socfpga/socfpga.c | 21 +++++- arch/arm/mach-socfpga/socfpga_cti.c | 125 +++++++++++++++++++++++++++++++++++ arch/arm/mach-socfpga/socfpga_cti.h | 16 +++++ 7 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-socfpga/socfpga_cti.c create mode 100644 arch/arm/mach-socfpga/socfpga_cti.h diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 16a6e13..0f10a0a 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -255,6 +255,24 @@ cache-level = <2>; }; + pmu { + #address-cells = <1>; + #size-cells = <1>; + compatible = "arm,cortex-a9-pmu"; + interrupts = <0 176 4>, <0 177 4>; + ranges; + + cti0: cti0@ff118000 { + compatible = "arm,coresight-cti"; + reg = <0xff118000 0x100>; + }; + + cti1: cti1@ff119000 { + compatible = "arm,coresight-cti"; + reg = <0xff119000 0x100>; + }; + }; + /* Local timer */ timer@fffec600 { compatible = "arm,cortex-a9-twd-timer"; diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index f24edad..60324b3 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -38,6 +38,9 @@ struct arm_pmu_platdata { irq_handler_t pmu_handler); int (*runtime_resume)(struct device *dev); int (*runtime_suspend)(struct device *dev); + int (*init)(struct platform_device *pdev); + int (*start)(struct platform_device *pdev); + int (*stop)(struct platform_device *pdev); }; #ifdef CONFIG_HW_PERF_EVENTS diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 8c3094d..66e9206 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -305,6 +305,11 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) static void armpmu_release_hardware(struct arm_pmu *armpmu) { + struct platform_device *plat_device = armpmu->plat_device; + struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); + + if (plat->stop) + plat->stop(plat_device); armpmu->free_irq(armpmu); pm_runtime_put_sync(&armpmu->plat_device->dev); } @@ -314,6 +319,7 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) { int err; struct platform_device *pmu_device = armpmu->plat_device; + struct arm_pmu_platdata *plat = dev_get_platdata(&pmu_device->dev); if (!pmu_device) return -ENODEV; @@ -324,6 +330,8 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) armpmu_release_hardware(armpmu); return err; } + if (plat->start) + plat->start(pmu_device); return 0; } @@ -506,10 +514,18 @@ static void armpmu_init(struct arm_pmu *armpmu) int armpmu_register(struct arm_pmu *armpmu, int type) { + struct platform_device *plat_device = armpmu->plat_device; + struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); + armpmu_init(armpmu); pm_runtime_enable(&armpmu->plat_device->dev); pr_info("enabled with %s PMU driver, %d counters available\n", armpmu->name, armpmu->num_events); + + /* Platform specific initialization. ie. CTI enable */ + if (plat->init) + plat->init(plat_device); + return perf_pmu_register(&armpmu->pmu, armpmu->name, type); } diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 6dd7a93..c7401d3 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -4,3 +4,4 @@ obj-y := socfpga.o obj-$(CONFIG_SMP) += headsmp.o platsmp.o +obj-$(CONFIG_HW_PERF_EVENTS) += socfpga_cti.o diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c index 46a0513..64f90a5 100644 --- a/arch/arm/mach-socfpga/socfpga.c +++ b/arch/arm/mach-socfpga/socfpga.c @@ -24,8 +24,10 @@ #include #include #include +#include #include "core.h" +#include "socfpga_cti.h" void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE)); void __iomem *sys_manager_base_addr; @@ -33,6 +35,22 @@ void __iomem *rst_manager_base_addr; void __iomem *clk_mgr_base_addr; unsigned long cpu1start_addr; +#ifdef CONFIG_HW_PERF_EVENTS +static struct arm_pmu_platdata socfpga_pmu_platdata = { + .handle_irq = socfpga_pmu_handler, + .init = socfpga_init_cti, + .start = socfpga_start_cti, + .stop = socfpga_stop_cti, +}; +#endif + +static const struct of_dev_auxdata socfpga_auxdata_lookup[] __initconst = { +#ifdef CONFIG_HW_PERF_EVENTS + OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &socfpga_pmu_platdata), +#endif + { /* sentinel */ } +}; + static struct map_desc scu_io_desc __initdata = { .virtual = SOCFPGA_SCU_VIRT_BASE, .pfn = 0, /* run-time */ @@ -106,7 +124,8 @@ static void socfpga_cyclone5_restart(char mode, const char *cmd) static void __init socfpga_cyclone5_init(void) { l2x0_of_init(0, ~0UL); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + of_platform_populate(NULL, of_default_bus_match_table, + socfpga_auxdata_lookup, NULL); of_clk_init(NULL); socfpga_init_clocks(); } diff --git a/arch/arm/mach-socfpga/socfpga_cti.c b/arch/arm/mach-socfpga/socfpga_cti.c new file mode 100644 index 0000000..10072c8 --- /dev/null +++ b/arch/arm/mach-socfpga/socfpga_cti.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 "core.h" +#include "socfpga_cti.h" + +#define SOCFPGA_NUM_CTI 2 + +struct cti socfpga_cti_data[SOCFPGA_NUM_CTI]; + +irqreturn_t socfpga_pmu_handler(int irq, void *dev, irq_handler_t handler) +{ + unsigned int handled = 0; + int i; + + for (i = 0; i < SOCFPGA_NUM_CTI; i++) + if (irq == socfpga_cti_data[i].irq) { + cti_irq_ack(&socfpga_cti_data[i]); + handled = handler(irq, dev); + } + + return IRQ_RETVAL(handled); +} + +int socfpga_init_cti(struct platform_device *pdev) +{ + struct device_node *np, *np2; + void __iomem *cti0_addr; + void __iomem *cti1_addr; + u32 irq0, irq1; + + np = pdev->dev.of_node; + np2 = of_find_compatible_node(np, NULL, "arm,coresight-cti"); + if (!np2) { + dev_err(&pdev->dev, "PMU: Unable to find coresight-cti\n"); + return -1; + } + cti0_addr = of_iomap(np2, 0); + if (!cti0_addr) { + dev_err(&pdev->dev, "PMU: ioremap for CTI failed\n"); + return -1; + } + + irq0 = platform_get_irq(pdev, 0); + if (irq0 < 0) + goto free_irq0; + + np2 = of_find_compatible_node(np2, NULL, "arm,coresight-cti"); + if (!np2) { + dev_err(&pdev->dev, "PMU: Unable to find coresight-cti\n"); + goto err_iounmap; + } + cti1_addr = of_iomap(np2, 0); + if (!cti1_addr) + goto err_iounmap; + + irq1 = platform_get_irq(pdev, 1); + if (irq1 < 0) + goto free_irq1; + + /*configure CTI0 for pmu irq routing*/ + cti_init(&socfpga_cti_data[0], cti0_addr, + irq0, CTI_MPU_IRQ_TRIG_OUT); + cti_unlock(&socfpga_cti_data[0]); + cti_map_trigger(&socfpga_cti_data[0], + CTI_MPU_IRQ_TRIG_IN, CTI_MPU_IRQ_TRIG_OUT, PMU_CHANNEL_0); + + /*configure CTI1 for pmu irq routing*/ + cti_init(&socfpga_cti_data[1], cti1_addr, + irq1, CTI_MPU_IRQ_TRIG_OUT); + cti_unlock(&socfpga_cti_data[1]); + cti_map_trigger(&socfpga_cti_data[1], + CTI_MPU_IRQ_TRIG_IN, CTI_MPU_IRQ_TRIG_OUT, PMU_CHANNEL_1); + + dev_info(&pdev->dev, "PMU:CTI successfully enabled\n"); + return 0; + +free_irq1: + iounmap(cti1_addr); +err_iounmap: + free_irq(irq0, pdev); +free_irq0: + iounmap(cti0_addr); + return -1; +} + +int socfpga_start_cti(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < SOCFPGA_NUM_CTI; i++) + cti_enable(&socfpga_cti_data[i]); + + return 0; +} + +int socfpga_stop_cti(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < SOCFPGA_NUM_CTI; i++) + cti_disable(&socfpga_cti_data[i]); + + return 0; +} + diff --git a/arch/arm/mach-socfpga/socfpga_cti.h b/arch/arm/mach-socfpga/socfpga_cti.h new file mode 100644 index 0000000..cbeb063 --- /dev/null +++ b/arch/arm/mach-socfpga/socfpga_cti.h @@ -0,0 +1,16 @@ +#ifndef __SOCFPGA_CTI_H +#define __SOCFPGA_CTI_H + +#define CTI_MPU_IRQ_TRIG_IN 1 +#define CTI_MPU_IRQ_TRIG_OUT 6 + +#define PMU_CHANNEL_0 0 +#define PMU_CHANNEL_1 1 + +#ifdef CONFIG_HW_PERF_EVENTS +extern irqreturn_t socfpga_pmu_handler(int irq, void *dev, irq_handler_t handler); +extern int socfpga_init_cti(struct platform_device *pdev); +extern int socfpga_start_cti(struct platform_device *pdev); +extern int socfpga_stop_cti(struct platform_device *pdev); +#endif +#endif /* __SOCFPGA_CTI_H */