From nobody Tue Sep 9 22:50:34 2025 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A148EC0015E for ; Wed, 26 Jul 2023 15:05:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234750AbjGZPFI (ORCPT ); Wed, 26 Jul 2023 11:05:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46984 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234760AbjGZPEu (ORCPT ); Wed, 26 Jul 2023 11:04:50 -0400 Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::225]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4914CCE; Wed, 26 Jul 2023 08:04:11 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 7C18F1C0012; Wed, 26 Jul 2023 15:03:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1690383816; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7yiNLw5nDUpcYCeFDYdubmFw7vFjT2EHbzA38n55h4I=; b=IFchB5o6X7SbzmZodghbEA3X0dqPzvyoq6P/jnPgb98RG0MnstLgXOpXiT6axNl72Cfleq qJ6+EOYKojCJjd1sBy5X9dNG42vwVJNbK2yHNTk8TpKn1TY6W+HUB0/+ZLY16+Yw3fwUif BmKg4eX+T/ShUvqumUO1rVnooVPFvN739gWdagIKu0rT6tjS8N7yJlgK5w/eM97E0GOIf8 UU/P4gkKRilgs2vhMmnKCKw8yCwsmOYO16Y5ouT498FeYK4q59tZYINQeT0uzdcmEhLVzM xF2n4CggQQ6Au7ptcWiet+QqyaUBLzu/Aas3zOriuTLxpdWaWhsi+u8BIob2UQ== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Thomas Petazzoni Subject: [PATCH v2 16/28] soc: fsl: cpm1: qmc: Handle timeslot entries at channel start() and stop() Date: Wed, 26 Jul 2023 17:02:12 +0200 Message-ID: <20230726150225.483464-17-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230726150225.483464-1-herve.codina@bootlin.com> References: <20230726150225.483464-1-herve.codina@bootlin.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-GND-Sasl: herve.codina@bootlin.com Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" In order to support runtime timeslot route changes, enable the channel timeslot entries at channel start() and disable them at channel stop(). Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 175 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 163 insertions(+), 12 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index dc113463fbc7..258a34641551 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -177,6 +177,7 @@ struct qmc_chan { struct qmc *qmc; void __iomem *s_param; enum qmc_mode mode; + spinlock_t ts_lock; /* Protect timeslots */ u64 tx_ts_mask_avail; u64 tx_ts_mask; u64 rx_ts_mask_avail; @@ -265,6 +266,7 @@ static inline void qmc_setbits32(void __iomem *addr, u3= 2 set) int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) { struct tsa_serial_info tsa_info; + unsigned long flags; int ret; =20 /* Retrieve info from the TSA related serial */ @@ -272,6 +274,8 @@ int qmc_chan_get_info(struct qmc_chan *chan, struct qmc= _chan_info *info) if (ret) return ret; =20 + spin_lock_irqsave(&chan->ts_lock, flags); + info->mode =3D chan->mode; info->rx_fs_rate =3D tsa_info.rx_fs_rate; info->rx_bit_rate =3D tsa_info.rx_bit_rate; @@ -280,6 +284,8 @@ int qmc_chan_get_info(struct qmc_chan *chan, struct qmc= _chan_info *info) info->tx_bit_rate =3D tsa_info.tx_bit_rate; info->nb_rx_ts =3D hweight64(chan->rx_ts_mask); =20 + spin_unlock_irqrestore(&chan->ts_lock, flags); + return 0; } EXPORT_SYMBOL(qmc_chan_get_info); @@ -683,6 +689,40 @@ static int qmc_chan_setup_tsa_32tx(struct qmc_chan *ch= an, const struct tsa_seria return 0; } =20 +static int qmc_chan_setup_tsa_tx(struct qmc_chan *chan, bool enable) +{ + struct tsa_serial_info info; + int ret; + + /* Retrieve info from the TSA related serial */ + ret =3D tsa_serial_get_info(chan->qmc->tsa_serial, &info); + if (ret) + return ret; + + /* Setup entries */ + if (chan->qmc->is_tsa_64rxtx) + return qmc_chan_setup_tsa_64rxtx(chan, &info, enable); + + return qmc_chan_setup_tsa_32tx(chan, &info, enable); +} + +static int qmc_chan_setup_tsa_rx(struct qmc_chan *chan, bool enable) +{ + struct tsa_serial_info info; + int ret; + + /* Retrieve info from the TSA related serial */ + ret =3D tsa_serial_get_info(chan->qmc->tsa_serial, &info); + if (ret) + return ret; + + /* Setup entries */ + if (chan->qmc->is_tsa_64rxtx) + return qmc_chan_setup_tsa_64rxtx(chan, &info, enable); + + return qmc_chan_setup_tsa_32rx(chan, &info, enable); +} + static int qmc_chan_setup_tsa(struct qmc_chan *chan, bool enable) { struct tsa_serial_info info; @@ -719,6 +759,12 @@ static int qmc_chan_stop_rx(struct qmc_chan *chan) =20 spin_lock_irqsave(&chan->rx_lock, flags); =20 + if (chan->is_rx_stopped) { + /* The channel is already stopped -> simply return ok */ + ret =3D 0; + goto end; + } + /* Send STOP RECEIVE command */ ret =3D qmc_chan_command(chan, 0x0); if (ret) { @@ -729,6 +775,15 @@ static int qmc_chan_stop_rx(struct qmc_chan *chan) =20 chan->is_rx_stopped =3D true; =20 + if (!chan->qmc->is_tsa_64rxtx || chan->is_tx_stopped) { + ret =3D qmc_chan_setup_tsa_rx(chan, false); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n", + chan->id, ret); + goto end; + } + } + end: spin_unlock_irqrestore(&chan->rx_lock, flags); return ret; @@ -741,6 +796,12 @@ static int qmc_chan_stop_tx(struct qmc_chan *chan) =20 spin_lock_irqsave(&chan->tx_lock, flags); =20 + if (chan->is_tx_stopped) { + /* The channel is already stopped -> simply return ok */ + ret =3D 0; + goto end; + } + /* Send STOP TRANSMIT command */ ret =3D qmc_chan_command(chan, 0x1); if (ret) { @@ -751,37 +812,82 @@ static int qmc_chan_stop_tx(struct qmc_chan *chan) =20 chan->is_tx_stopped =3D true; =20 + if (!chan->qmc->is_tsa_64rxtx || chan->is_rx_stopped) { + ret =3D qmc_chan_setup_tsa_tx(chan, false); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n", + chan->id, ret); + goto end; + } + } + end: spin_unlock_irqrestore(&chan->tx_lock, flags); return ret; } =20 +static int qmc_chan_start_rx(struct qmc_chan *chan); + int qmc_chan_stop(struct qmc_chan *chan, int direction) { - int ret; + bool is_rx_rollback_needed =3D false; + unsigned long flags; + int ret =3D 0; + + spin_lock_irqsave(&chan->ts_lock, flags); =20 if (direction & QMC_CHAN_READ) { + is_rx_rollback_needed =3D !chan->is_rx_stopped; ret =3D qmc_chan_stop_rx(chan); if (ret) - return ret; + goto end; } =20 if (direction & QMC_CHAN_WRITE) { ret =3D qmc_chan_stop_tx(chan); - if (ret) - return ret; + if (ret) { + /* Restart rx if needed */ + if (is_rx_rollback_needed) + qmc_chan_start_rx(chan); + goto end; + } } =20 - return 0; +end: + spin_unlock_irqrestore(&chan->ts_lock, flags); + return ret; } EXPORT_SYMBOL(qmc_chan_stop); =20 -static void qmc_chan_start_rx(struct qmc_chan *chan) +static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan); + +static int qmc_chan_start_rx(struct qmc_chan *chan) { unsigned long flags; + int ret; =20 spin_lock_irqsave(&chan->rx_lock, flags); =20 + if (!chan->is_rx_stopped) { + /* The channel is already started -> simply return ok */ + ret =3D 0; + goto end; + } + + ret =3D qmc_chan_setup_tsa_rx(chan, true); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: Enable tsa entries failed (%d)\n", + chan->id, ret); + goto end; + } + + ret =3D qmc_setup_chan_trnsync(chan->qmc, chan); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n", + chan->id, ret); + goto end; + } + /* Restart the receiver */ if (chan->mode =3D=3D QMC_TRANSPARENT) qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); @@ -792,15 +898,38 @@ static void qmc_chan_start_rx(struct qmc_chan *chan) =20 chan->is_rx_stopped =3D false; =20 +end: spin_unlock_irqrestore(&chan->rx_lock, flags); + return ret; } =20 -static void qmc_chan_start_tx(struct qmc_chan *chan) +static int qmc_chan_start_tx(struct qmc_chan *chan) { unsigned long flags; + int ret; =20 spin_lock_irqsave(&chan->tx_lock, flags); =20 + if (!chan->is_tx_stopped) { + /* The channel is already started -> simply return ok */ + ret =3D 0; + goto end; + } + + ret =3D qmc_chan_setup_tsa_tx(chan, true); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: Enable tsa entries failed (%d)\n", + chan->id, ret); + goto end; + } + + ret =3D qmc_setup_chan_trnsync(chan->qmc, chan); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n", + chan->id, ret); + goto end; + } + /* * Enable channel transmitter as it could be disabled if * qmc_chan_reset() was called. @@ -812,18 +941,39 @@ static void qmc_chan_start_tx(struct qmc_chan *chan) =20 chan->is_tx_stopped =3D false; =20 +end: spin_unlock_irqrestore(&chan->tx_lock, flags); + return ret; } =20 int qmc_chan_start(struct qmc_chan *chan, int direction) { - if (direction & QMC_CHAN_READ) - qmc_chan_start_rx(chan); + bool is_rx_rollback_needed =3D false; + unsigned long flags; + int ret =3D 0; =20 - if (direction & QMC_CHAN_WRITE) - qmc_chan_start_tx(chan); + spin_lock_irqsave(&chan->ts_lock, flags); =20 - return 0; + if (direction & QMC_CHAN_READ) { + is_rx_rollback_needed =3D chan->is_rx_stopped; + ret =3D qmc_chan_start_rx(chan); + if (ret) + goto end; + } + + if (direction & QMC_CHAN_WRITE) { + ret =3D qmc_chan_start_tx(chan); + if (ret) { + /* Restop rx if needed */ + if (is_rx_rollback_needed) + qmc_chan_stop_rx(chan); + goto end; + } + } + +end: + spin_unlock_irqrestore(&chan->ts_lock, flags); + return ret; } EXPORT_SYMBOL(qmc_chan_start); =20 @@ -992,6 +1142,7 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct = device_node *np) } =20 chan->id =3D chan_id; + spin_lock_init(&chan->ts_lock); spin_lock_init(&chan->rx_lock); spin_lock_init(&chan->tx_lock); =20 --=20 2.41.0