From patchwork Tue Sep 8 10:47:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joakim Zhang X-Patchwork-Id: 11763231 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A7152112E for ; Tue, 8 Sep 2020 10:55:37 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7D53620732 for ; Tue, 8 Sep 2020 10:55:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="hzr678rJ" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7D53620732 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=nxp.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.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=iyVoz469WfqEZWYo15n1VEpoEA7C7FWEk18PXx89AQc=; b=hzr678rJzaXet8j1qp1+VLjQwx MV0lRNDuABUNZ81mbgYzLOWo3ZPIaL0BW0yiglqhqtahiOZoaIfve+SAMHTLcM79nUj8jHXsonRmh QTfYTn6dU+BIpkwIJVWjJg1RH/Rl0wAITC4CKjZQ0M4nXjDR9eWUEsGQAgSvbCZg5+keueLX6hBbs NGXA3qVSSjN7LcvEZpv63lYGaKDeNZxoii2JYFYLawdie4pLIyUmtGH6vJiDKrE7l3GPiU+q9lpM9 PDSEJ6pp0tjmgbQY+Z5TyzK15gyIaAZvbkDBMu2mpeL9+QANU+vQSwhiLWhxVFREQYpV8aYP3CLi3 canYECog==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kFbGN-0007r9-0y; Tue, 08 Sep 2020 10:54:11 +0000 Received: from inva020.nxp.com ([92.121.34.13]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kFbGJ-0007qB-IT for linux-arm-kernel@lists.infradead.org; Tue, 08 Sep 2020 10:54:08 +0000 Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 11B161A035C; Tue, 8 Sep 2020 12:54:05 +0200 (CEST) Received: from invc005.ap-rdc01.nxp.com (invc005.ap-rdc01.nxp.com [165.114.16.14]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 207831A036C; Tue, 8 Sep 2020 12:54:02 +0200 (CEST) Received: from 10.192.242.69 (shlinux2.ap.freescale.net [10.192.224.44]) by invc005.ap-rdc01.nxp.com (Postfix) with ESMTP id 6C3C2402E2; Tue, 8 Sep 2020 12:53:58 +0200 (CEST) From: Joakim Zhang To: will@kernel.org, mark.rutland@arm.com, robin.murphy@arm.com Subject: [PATCH V2] perf/imx_ddr: Add stop event counters support for i.MX8MP Date: Tue, 8 Sep 2020 18:47:34 +0800 Message-Id: <1599562054-1930-1-git-send-email-qiangqing.zhang@nxp.com> X-Mailer: git-send-email 2.7.4 X-Virus-Scanned: ClamAV using ClamSMTP X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200908_065407_924707_5BA89A6D X-CRM114-Status: GOOD ( 19.75 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [92.121.34.13 listed in list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, Joakim Zhang MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DDR Perf driver only supports free-running event counters(counter1/2/3) now, this patch adds support for stop event counters. Legacy SoCs: Cycle counter(counter0) is a special counter, only count cycles. When cycle counter overflow, it will lock all counters and generate an interrupt. In ddr_perf_irq_handler, disable cycle counter then all counters would stop at the same time, update all counters' count, then enable cycle counter that all counters count again. During this process, only clear cycle counter, no need to clear event counters since they are free-running counters. They would continue counting after overflow and do/while loop from ddr_perf_event_update can handle event counters overflow case. i.MX8MP: Almost all is the same as legacy SoCs, the only difference is that, event counters are not free-running any more. Like cycle counter, when event counters overflow, they would stop counting unless clear the counter, and no interrupt generate for event counters. So we should clear event counters that let them re-count when cycle counter overflow, which ensure event counters will not lose data. This patch adds stop event counters support which would be compatible to free-running event counters. Signed-off-by: Joakim Zhang --- ChangeLogs: V1->V2: * clear event counters in update function, instead of irq handler, so remove spinlock. --- drivers/perf/fsl_imx8_ddr_perf.c | 68 ++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c index 90884d14f95f..c0f0adfcac06 100644 --- a/drivers/perf/fsl_imx8_ddr_perf.c +++ b/drivers/perf/fsl_imx8_ddr_perf.c @@ -361,25 +361,6 @@ static int ddr_perf_event_init(struct perf_event *event) return 0; } - -static void ddr_perf_event_update(struct perf_event *event) -{ - struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - u64 delta, prev_raw_count, new_raw_count; - int counter = hwc->idx; - - do { - prev_raw_count = local64_read(&hwc->prev_count); - new_raw_count = ddr_perf_read_counter(pmu, counter); - } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count, - new_raw_count) != prev_raw_count); - - delta = (new_raw_count - prev_raw_count) & 0xFFFFFFFF; - - local64_add(delta, &event->count); -} - static void ddr_perf_counter_enable(struct ddr_pmu *pmu, int config, int counter, bool enable) { @@ -404,6 +385,52 @@ static void ddr_perf_counter_enable(struct ddr_pmu *pmu, int config, } } +static bool ddr_perf_counter_overflow(struct ddr_pmu *pmu, int counter) +{ + int val; + + val = readl_relaxed(pmu->base + counter * 4 + COUNTER_CNTL); + + return val & CNTL_OVER ? true : false; +} + +static void ddr_perf_event_update(struct perf_event *event) +{ + struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u64 delta, prev_raw_count, new_raw_count; + int counter = hwc->idx; + int ret; + + if (counter == EVENT_CYCLES_COUNTER) { + do { + prev_raw_count = local64_read(&hwc->prev_count); + new_raw_count = ddr_perf_read_counter(pmu, counter); + } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count) != prev_raw_count); + + delta = (new_raw_count - prev_raw_count) & 0xFFFFFFFF; + + local64_add(delta, &event->count); + } else { + /* + * For legacy SoCs: event counters continue counting when overflow, + * no need to clear the counter. + * For new SoCs: event counters stop counting when overflow, need + * clear counter to let it count again. + */ + ret = ddr_perf_counter_overflow(pmu, counter); + if (ret) + dev_warn(pmu->dev, "Event Counter%d overflow happened, data incorrect!!\n", counter); + + new_raw_count = ddr_perf_read_counter(pmu, counter); + local64_add(new_raw_count, &event->count); + + /* Clear event counter, it's fine for both legacy and new SoCs. */ + ddr_perf_counter_enable(pmu, event->attr.config, counter, true); + } +} + static void ddr_perf_event_start(struct perf_event *event, int flags) { struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); @@ -546,7 +573,8 @@ static irqreturn_t ddr_perf_irq_handler(int irq, void *p) /* * When the cycle counter overflows, all counters are stopped, * and an IRQ is raised. If any other counter overflows, it - * continues counting, and no IRQ is raised. + * continues counting (stop counting for new SoCs, such as i.MX8MP), + * and no IRQ is raised. * * Cycles occur at least 4 times as often as other events, so we * can update all events on a cycle counter overflow and not