Received: by 2002:a25:d7c1:0:0:0:0:0 with SMTP id o184csp73489ybg; Fri, 25 Oct 2019 16:56:32 -0700 (PDT) X-Google-Smtp-Source: APXvYqzet2dJkNl851/tkiS1sp1My4VjZ+04VzrCjCe+yCI55twbwZyzOmoj9FNZ/+cnAHN5E0bH X-Received: by 2002:a17:907:42cc:: with SMTP id nz20mr5738359ejb.324.1572047792793; Fri, 25 Oct 2019 16:56:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1572047792; cv=none; d=google.com; s=arc-20160816; b=X2AsBXw+z98NrtfzUBhi0/gOUHbHINkNjeQ1VJoCQ8+pjT/JNM5v+k5FrdgjNwix1a rh0RFCWH/TUaCFn6OakMxM1BDDsJb005CFKeGrOt62z7Us6Q7+4tmYMvmu5NMn/w9ak7 h3vwfAVQuhDT1QIsmdX/oXbuuZMTzSYPgUh/0lm2xvwGVH0+smVwsjNLTr6jqTS3PuFT Uk4QEvFmfSinPk4Uv/Tq3zJampuoY6T7zDs9rKDhFqnCNy6g9n3U6hlGL+v66rcXQC7x DGmmkz7DYLTE9ml9+/13Mp0llrwagFQBpA2EgWAiR3g6jZ8mAj0kxUUE/M3ISeqLD3xO 1DGA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:from:subject:mime-version :message-id:date:dkim-signature; bh=KnfaRBhkOtHWNKkkUS56gRLOAqFL2VhO104CkKgAj7o=; b=kJlEj+CMA+hOYgE4xJgrIQFZFsgq9LtKpcXakSNLtxxilAk/u7Rgeg4qZEtYtp3/Ku AvYJ/Oka88zh7UjnYFoa3TccuuGhuMNQ/H4qwJaPb3i/euUEXzeUKsIPpKq7WOAFzfB+ 1kBHVe9EVZDSIXYdEWzE6EhTGmRfcwxJfFI8Hrg2oYbOBnLeKarH3y3dsYnCX7xLvzzY tNiYhinPauHw/yiWX2pxo1+niyzrHe2FPKgj3yT06D49RSoFtQV2sZ/IXEpJt47UGJt8 da4ABBi8YCvloedwrwupVjNvcaUlDh5bDeONOEdcrVbtG5O+P+wz+fPPjMbeJvWibFND OTKQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=AuGhkHR8; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l48si2382457edc.276.2019.10.25.16.56.08; Fri, 25 Oct 2019 16:56:32 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=AuGhkHR8; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725965AbfJYXx0 (ORCPT + 99 others); Fri, 25 Oct 2019 19:53:26 -0400 Received: from mail-vs1-f74.google.com ([209.85.217.74]:46683 "EHLO mail-vs1-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725881AbfJYXx0 (ORCPT ); Fri, 25 Oct 2019 19:53:26 -0400 Received: by mail-vs1-f74.google.com with SMTP id p1so632434vsg.13 for ; Fri, 25 Oct 2019 16:53:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:message-id:mime-version:subject:from:to:cc; bh=KnfaRBhkOtHWNKkkUS56gRLOAqFL2VhO104CkKgAj7o=; b=AuGhkHR8iBMzEcCPPn4V14Su+r21HbFFTMMS6A7pf5C9wbtJctuUA48d+H1tJ+bEoC 3Tg70X/TGlsYsmU4GOtVroAQFOCaJ1aEtF1/76VJsN/gU9nvfquUVFBuSIpE2LOScpfN 0CEpGHcamMjTHDSIA2hDnznXKU/2CThei57JKVfViiQlwzec/2wlIXe7awj9dfgFmrs5 si6T2Nrz0gPRWUrMA0FSEnoynyhsPD8ht3Y9ySprePWyysKePQj8ImP3zktI6AmnhQXx 9JYXSqSc+fVYt6D3HjAZJwfL0//2dojiW5F2TFEIFYW3o9WCctCDXJEgvY9D2QB0Jrb2 nmVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:mime-version:subject:from:to:cc; bh=KnfaRBhkOtHWNKkkUS56gRLOAqFL2VhO104CkKgAj7o=; b=fnl9Yx+wLgSyiDNzu3l1yT7c36QJJyxswbRGfV812uJpVAbJeKyi2ZkIJ5uEA8XY67 4wjpJEN8nXV4Mo7PCW/YOcj5elEMGOUXJg2rB22fcY74JkcY3ENe87Sd5QEF5l3GsJMp ls1hqDNZ96RlqSa1ycj6nr0PDWFRchYm2HGQKlYHy8zlNp1jPSrEcA2XXRrZkBy2sNuY OZKz8bYRaVjUFayul5/xXVy/weeGKws6dmBxI6G/+ljCBgwlC2GAdbsPEkgaj9A//Mc1 qAX51j++26qxZWyynZ4/jmmm8EMVwKUXcSOmxY9KRiLXl+P3Idsai5xxOXtheKitqrnr 8+Gw== X-Gm-Message-State: APjAAAWujo12vrZ/rpjT8mRXfV/KFXA8ZT/VpLAridXyZnwZQfMTlinP pR5FhaJIbhVlff0U3LP3/XLsSYn3ww== X-Received: by 2002:ab0:2e9c:: with SMTP id f28mr3115278uaa.20.1572047604815; Fri, 25 Oct 2019 16:53:24 -0700 (PDT) Date: Fri, 25 Oct 2019 16:53:21 -0700 Message-Id: <20191025235321.181897-1-yabinc@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.24.0.rc0.303.g954a862665-goog Subject: [PATCH v5] coresight: Serialize enabling/disabling a link device. From: Yabin Cui To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Yabin Cui Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When tracing etm data of multiple threads on multiple cpus through perf interface, some link devices are shared between paths of different cpus. It creates race conditions when different cpus wants to enable/disable the same link device at the same time. Example 1: Two cpus want to enable different ports of a coresight funnel, thus calling the funnel enable operation at the same time. But the funnel enable operation isn't reentrantable. Example 2: For an enabled coresight dynamic replicator with refcnt=1, one cpu wants to disable it, while another cpu wants to enable it. Ideally we still have an enabled replicator with refcnt=1 at the end. But in reality the result is uncertain. Since coresight devices claim themselves when enabled for self-hosted usage, the race conditions above usually make the link devices not usable after many cycles. To fix the race conditions, this patch uses spinlocks to serialize enabling/disabling link devices. Fixes: a06ae8609b3d ("coresight: add CoreSight core layer framework") Signed-off-by: Yabin Cui --- Sorry for the delay! v4 -> v5: added document for spinlock fields. moved dev_dbg() out of lock section, and verified printed debug msgs. split atomic_inc_return() into atomic_read() and atomic_inc() as commented. checked drvdata->reading before refcnt. --- .../hwtracing/coresight/coresight-funnel.c | 36 +++++++++++---- .../coresight/coresight-replicator.c | 35 ++++++++++++--- .../hwtracing/coresight/coresight-tmc-etf.c | 26 ++++++++--- drivers/hwtracing/coresight/coresight.c | 45 ++++++------------- 4 files changed, 90 insertions(+), 52 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 05f7896c3a01..b605889b507a 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -38,12 +38,14 @@ DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel"); * @atclk: optional clock for the core parts of the funnel. * @csdev: component vitals needed by the framework. * @priority: port selection order. + * @spinlock: serialize enable/disable operations. */ struct funnel_drvdata { void __iomem *base; struct clk *atclk; struct coresight_device *csdev; unsigned long priority; + spinlock_t spinlock; }; static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port) @@ -76,11 +78,21 @@ static int funnel_enable(struct coresight_device *csdev, int inport, { int rc = 0; struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - - if (drvdata->base) - rc = dynamic_funnel_enable_hw(drvdata, inport); - + unsigned long flags; + bool first_enable = false; + + spin_lock_irqsave(&drvdata->spinlock, flags); + if (atomic_read(&csdev->refcnt[inport]) == 0) { + if (drvdata->base) + rc = dynamic_funnel_enable_hw(drvdata, inport); + if (!rc) + first_enable = true; + } if (!rc) + atomic_inc(&csdev->refcnt[inport]); + spin_unlock_irqrestore(&drvdata->spinlock, flags); + + if (first_enable) dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport); return rc; } @@ -107,11 +119,19 @@ static void funnel_disable(struct coresight_device *csdev, int inport, int outport) { struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + unsigned long flags; + bool last_disable = false; + + spin_lock_irqsave(&drvdata->spinlock, flags); + if (atomic_dec_return(&csdev->refcnt[inport]) == 0) { + if (drvdata->base) + dynamic_funnel_disable_hw(drvdata, inport); + last_disable = true; + } + spin_unlock_irqrestore(&drvdata->spinlock, flags); - if (drvdata->base) - dynamic_funnel_disable_hw(drvdata, inport); - - dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport); + if (last_disable) + dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport); } static const struct coresight_ops_link funnel_link_ops = { diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index b29ba640eb25..43304196a1a6 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -31,11 +31,13 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator"); * whether this one is programmable or not. * @atclk: optional clock for the core parts of the replicator. * @csdev: component vitals needed by the framework + * @spinlock: serialize enable/disable operations. */ struct replicator_drvdata { void __iomem *base; struct clk *atclk; struct coresight_device *csdev; + spinlock_t spinlock; }; static void dynamic_replicator_reset(struct replicator_drvdata *drvdata) @@ -97,10 +99,22 @@ static int replicator_enable(struct coresight_device *csdev, int inport, { int rc = 0; struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - - if (drvdata->base) - rc = dynamic_replicator_enable(drvdata, inport, outport); + unsigned long flags; + bool first_enable = false; + + spin_lock_irqsave(&drvdata->spinlock, flags); + if (atomic_read(&csdev->refcnt[outport]) == 0) { + if (drvdata->base) + rc = dynamic_replicator_enable(drvdata, inport, + outport); + if (!rc) + first_enable = true; + } if (!rc) + atomic_inc(&csdev->refcnt[outport]); + spin_unlock_irqrestore(&drvdata->spinlock, flags); + + if (first_enable) dev_dbg(&csdev->dev, "REPLICATOR enabled\n"); return rc; } @@ -137,10 +151,19 @@ static void replicator_disable(struct coresight_device *csdev, int inport, int outport) { struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + unsigned long flags; + bool last_disable = false; + + spin_lock_irqsave(&drvdata->spinlock, flags); + if (atomic_dec_return(&csdev->refcnt[outport]) == 0) { + if (drvdata->base) + dynamic_replicator_disable(drvdata, inport, outport); + last_disable = true; + } + spin_unlock_irqrestore(&drvdata->spinlock, flags); - if (drvdata->base) - dynamic_replicator_disable(drvdata, inport, outport); - dev_dbg(&csdev->dev, "REPLICATOR disabled\n"); + if (last_disable) + dev_dbg(&csdev->dev, "REPLICATOR disabled\n"); } static const struct coresight_ops_link replicator_link_ops = { diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 807416b75ecc..d0cc3985b72a 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -334,9 +334,10 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) static int tmc_enable_etf_link(struct coresight_device *csdev, int inport, int outport) { - int ret; + int ret = 0; unsigned long flags; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + bool first_enable = false; spin_lock_irqsave(&drvdata->spinlock, flags); if (drvdata->reading) { @@ -344,12 +345,18 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, return -EBUSY; } - ret = tmc_etf_enable_hw(drvdata); + if (atomic_read(&csdev->refcnt[0]) == 0) { + ret = tmc_etf_enable_hw(drvdata); + if (!ret) { + drvdata->mode = CS_MODE_SYSFS; + first_enable = true; + } + } if (!ret) - drvdata->mode = CS_MODE_SYSFS; + atomic_inc(&csdev->refcnt[0]); spin_unlock_irqrestore(&drvdata->spinlock, flags); - if (!ret) + if (first_enable) dev_dbg(&csdev->dev, "TMC-ETF enabled\n"); return ret; } @@ -359,6 +366,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev, { unsigned long flags; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + bool last_disable = false; spin_lock_irqsave(&drvdata->spinlock, flags); if (drvdata->reading) { @@ -366,11 +374,15 @@ static void tmc_disable_etf_link(struct coresight_device *csdev, return; } - tmc_etf_disable_hw(drvdata); - drvdata->mode = CS_MODE_DISABLED; + if (atomic_dec_return(&csdev->refcnt[0]) == 0) { + tmc_etf_disable_hw(drvdata); + drvdata->mode = CS_MODE_DISABLED; + last_disable = true; + } spin_unlock_irqrestore(&drvdata->spinlock, flags); - dev_dbg(&csdev->dev, "TMC-ETF disabled\n"); + if (last_disable) + dev_dbg(&csdev->dev, "TMC-ETF disabled\n"); } static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 6453c67a4d01..0bbce0d29158 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -253,9 +253,9 @@ static int coresight_enable_link(struct coresight_device *csdev, struct coresight_device *parent, struct coresight_device *child) { - int ret; + int ret = 0; int link_subtype; - int refport, inport, outport; + int inport, outport; if (!parent || !child) return -EINVAL; @@ -264,29 +264,17 @@ static int coresight_enable_link(struct coresight_device *csdev, outport = coresight_find_link_outport(csdev, child); link_subtype = csdev->subtype.link_subtype; - if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) - refport = inport; - else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) - refport = outport; - else - refport = 0; - - if (refport < 0) - return refport; + if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && inport < 0) + return inport; + if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0) + return outport; - if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { - if (link_ops(csdev)->enable) { - ret = link_ops(csdev)->enable(csdev, inport, outport); - if (ret) { - atomic_dec(&csdev->refcnt[refport]); - return ret; - } - } - } - - csdev->enable = true; + if (link_ops(csdev)->enable) + ret = link_ops(csdev)->enable(csdev, inport, outport); + if (!ret) + csdev->enable = true; - return 0; + return ret; } static void coresight_disable_link(struct coresight_device *csdev, @@ -295,7 +283,7 @@ static void coresight_disable_link(struct coresight_device *csdev, { int i, nr_conns; int link_subtype; - int refport, inport, outport; + int inport, outport; if (!parent || !child) return; @@ -305,20 +293,15 @@ static void coresight_disable_link(struct coresight_device *csdev, link_subtype = csdev->subtype.link_subtype; if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) { - refport = inport; nr_conns = csdev->pdata->nr_inport; } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) { - refport = outport; nr_conns = csdev->pdata->nr_outport; } else { - refport = 0; nr_conns = 1; } - if (atomic_dec_return(&csdev->refcnt[refport]) == 0) { - if (link_ops(csdev)->disable) - link_ops(csdev)->disable(csdev, inport, outport); - } + if (link_ops(csdev)->disable) + link_ops(csdev)->disable(csdev, inport, outport); for (i = 0; i < nr_conns; i++) if (atomic_read(&csdev->refcnt[i]) != 0) -- 2.24.0.rc0.303.g954a862665-goog