From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 23753CF8840 for ; Fri, 4 Oct 2024 18:23:47 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 656DE86E; Fri, 4 Oct 2024 20:23:35 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 656DE86E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1728066225; bh=suD76Zl1eWAEObQVqdM37af5ymlLk0z6r4lCRoUv+E8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=KtHoBuRGmXrseEOneigg0Sg4TSdI6+gNuNlC7djms2GtcrUC41ucp+xJy4dVpUtbm PihUtd+Lh8wWkW8TA70djpwlgviGfn9ozavC2gtLhl61nV18blFVx26wPNm+J2uEK/ DVM16GCkot76psuVsZvA0rQcxaxPGaMfcytfwe/8= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 6844DF8058C; Fri, 4 Oct 2024 20:23:25 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id C0841F805B5; Fri, 4 Oct 2024 20:23:24 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 98945F80527; Fri, 4 Oct 2024 20:23:20 +0200 (CEST) Received: from nyc.source.kernel.org (nyc.source.kernel.org [147.75.193.91]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id B36B1F80107 for ; Fri, 4 Oct 2024 20:23:18 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz B36B1F80107 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=TdfxA7Eb Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by nyc.source.kernel.org (Postfix) with ESMTP id 86029A44BA1; Fri, 4 Oct 2024 18:23:08 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A0D8AC4CEC6; Fri, 4 Oct 2024 18:23:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1728066196; bh=suD76Zl1eWAEObQVqdM37af5ymlLk0z6r4lCRoUv+E8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TdfxA7Ebfzki6Gur42/k/ihlkOa8cEGVEamC2/0eGA+0mJcBt8UVQrsQ4pwBjcYRG JH+6UVHWIppNuGOTNBdxtjWCZtA8EeqjszeuFTTrQ8qg1LiZvzrImMRCy04R+eXR4M wG1XW5Atzk3QOJAL0vlDXGzN6DuFMqjJyjYpBsoUgkh3B554XPqS5rglo0YvoDR4GT bUSY9ZiQEyIB2EJAmduGsvhuRYAZmJh4JIf5ZEP+7QqddUUgEhhiWGU5R9kYrIE0OC J2AFV1elJ7lGLQSPgh7phZ+xLXX40VweIxbC6jhNOXUAXmaGSRHUF9PyElijNF/M4x WVuRiRou13aBg== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Pierre-Louis Bossart , Liam Girdwood , Bard Liao , Vinod Koul , Sasha Levin , alsa-devel@alsa-project.org Subject: [PATCH AUTOSEL 6.10 39/70] soundwire: cadence: re-check Peripheral status with delayed_work Date: Fri, 4 Oct 2024 14:20:37 -0400 Message-ID: <20241004182200.3670903-39-sashal@kernel.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241004182200.3670903-1-sashal@kernel.org> References: <20241004182200.3670903-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore X-stable-base: Linux 6.10.13 Content-Transfer-Encoding: 8bit Message-ID-Hash: FYATK3JNJ3N5C2357PP7FGBR64553XJQ X-Message-ID-Hash: FYATK3JNJ3N5C2357PP7FGBR64553XJQ X-MailFrom: sashal@kernel.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.9 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Pierre-Louis Bossart [ Upstream commit f8c35d61ba01afa76846905c67862cdace7f66b0 ] The SoundWire peripheral enumeration is entirely based on interrupts, more specifically sticky bits tracking state changes. This patch adds a defensive programming check on the actual status reported in PING frames. If for some reason an interrupt was lost or delayed, the delayed work would detect a peripheral change of status after the bus starts. The 100ms defined for the delay is not completely arbitrary, if a Peripheral didn't join the bus within that delay then probably the hardware link is broken, and conversely if the detection didn't happen because of software issues the 100ms is still acceptable in terms of user experience. The overhead of the one-shot workqueue is minimal, and the mutual exclusion ensures that the interrupt and delayed work cannot update the status concurrently. Reviewed-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240805114921.88007-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/soundwire/cadence_master.c | 39 ++++++++++++++++++++++++++-- drivers/soundwire/cadence_master.h | 5 ++++ drivers/soundwire/intel.h | 2 ++ drivers/soundwire/intel_auxdevice.c | 1 + drivers/soundwire/intel_bus_common.c | 11 ++++++++ 5 files changed, 56 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 74da99034dab5..ec08e26cef829 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -891,8 +891,14 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, } } - if (is_slave) - return sdw_handle_slave_status(&cdns->bus, status); + if (is_slave) { + int ret; + + mutex_lock(&cdns->status_update_lock); + ret = sdw_handle_slave_status(&cdns->bus, status); + mutex_unlock(&cdns->status_update_lock); + return ret; + } return 0; } @@ -989,6 +995,31 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) } EXPORT_SYMBOL(sdw_cdns_irq); +static void cdns_check_attached_status_dwork(struct work_struct *work) +{ + struct sdw_cdns *cdns = + container_of(work, struct sdw_cdns, attach_dwork.work); + enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; + u32 val; + int ret; + int i; + + val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT); + + for (i = 0; i <= SDW_MAX_DEVICES; i++) { + status[i] = val & 0x3; + if (status[i]) + dev_dbg(cdns->dev, "Peripheral %d status: %d\n", i, status[i]); + val >>= 2; + } + + mutex_lock(&cdns->status_update_lock); + ret = sdw_handle_slave_status(&cdns->bus, status); + mutex_unlock(&cdns->status_update_lock); + if (ret < 0) + dev_err(cdns->dev, "%s: sdw_handle_slave_status failed: %d\n", __func__, ret); +} + /** * cdns_update_slave_status_work - update slave status in a work since we will need to handle * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave @@ -1741,7 +1772,11 @@ int sdw_cdns_probe(struct sdw_cdns *cdns) init_completion(&cdns->tx_complete); cdns->bus.port_ops = &cdns_port_ops; + mutex_init(&cdns->status_update_lock); + INIT_WORK(&cdns->work, cdns_update_slave_status_work); + INIT_DELAYED_WORK(&cdns->attach_dwork, cdns_check_attached_status_dwork); + return 0; } EXPORT_SYMBOL(sdw_cdns_probe); diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index bc84435e420f5..e1d7969ba48ae 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -117,6 +117,8 @@ struct sdw_cdns_dai_runtime { * @link_up: Link status * @msg_count: Messages sent on bus * @dai_runtime_array: runtime context for each allocated DAI. + * @status_update_lock: protect concurrency between interrupt-based and delayed work + * status update */ struct sdw_cdns { struct device *dev; @@ -148,10 +150,13 @@ struct sdw_cdns { bool interrupt_enabled; struct work_struct work; + struct delayed_work attach_dwork; struct list_head list; struct sdw_cdns_dai_runtime **dai_runtime_array; + + struct mutex status_update_lock; /* add mutual exclusion to sdw_handle_slave_status() */ }; #define bus_to_cdns(_bus) container_of(_bus, struct sdw_cdns, bus) diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index b68e74c294e70..c502dfdfe8abf 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -98,6 +98,8 @@ static inline void intel_writew(void __iomem *base, int offset, u16 value) #define INTEL_MASTER_RESET_ITERATIONS 10 +#define SDW_INTEL_DELAYED_ENUMERATION_MS 100 + #define SDW_INTEL_CHECK_OPS(sdw, cb) ((sdw) && (sdw)->link_res && (sdw)->link_res->hw_ops && \ (sdw)->link_res->hw_ops->cb) #define SDW_INTEL_OPS(sdw, cb) ((sdw)->link_res->hw_ops->cb) diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 18517121cc898..58f6b4f33cabd 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -433,6 +433,7 @@ static void intel_link_remove(struct auxiliary_device *auxdev) */ if (!bus->prop.hw_disabled) { sdw_intel_debugfs_exit(sdw); + cancel_delayed_work_sync(&cdns->attach_dwork); sdw_cdns_enable_interrupt(cdns, false); } sdw_bus_master_delete(bus); diff --git a/drivers/soundwire/intel_bus_common.c b/drivers/soundwire/intel_bus_common.c index 179aa0d85951b..db9cf211671a3 100644 --- a/drivers/soundwire/intel_bus_common.c +++ b/drivers/soundwire/intel_bus_common.c @@ -60,6 +60,9 @@ int intel_start_bus(struct sdw_intel *sdw) sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); + schedule_delayed_work(&cdns->attach_dwork, + msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS)); + return 0; } @@ -151,6 +154,9 @@ int intel_start_bus_after_reset(struct sdw_intel *sdw) } sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); + schedule_delayed_work(&cdns->attach_dwork, + msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS)); + return 0; } @@ -184,6 +190,9 @@ int intel_start_bus_after_clock_stop(struct sdw_intel *sdw) sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); + schedule_delayed_work(&cdns->attach_dwork, + msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS)); + return 0; } @@ -194,6 +203,8 @@ int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop) bool wake_enable = false; int ret; + cancel_delayed_work_sync(&cdns->attach_dwork); + if (clock_stop) { ret = sdw_cdns_clock_stop(cdns, true); if (ret < 0) -- 2.43.0