Received: by 2002:ab2:6857:0:b0:1ef:ffd0:ce49 with SMTP id l23csp3289951lqp; Tue, 26 Mar 2024 05:29:20 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCU8KNskCiUAKsHlGOQlgGTh8yWt+kUI9nOaejVeYjHyXyILs2NaQxIW+Ho3H8DK0OXEfMgA9F5VabFhhtjxkCkTQAcpiAUnc+q/Dfk7ow== X-Google-Smtp-Source: AGHT+IGHe8cu2xyLbcjhfqU6+cEE1zHKzg/5oYTHWfwCTXmMXD+kvwIC1Gj+mWzin1nkl8CkBzbG X-Received: by 2002:a05:6870:a11b:b0:222:7000:8b28 with SMTP id m27-20020a056870a11b00b0022270008b28mr12706797oae.32.1711456160185; Tue, 26 Mar 2024 05:29:20 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1711456160; cv=pass; d=google.com; s=arc-20160816; b=ej0EefXHzMA8PhIiWUIN39IvoirgogbS+AMn4nrZ461WJt3KKofGTAlGsvYmG8Capp +c5QNKl2a6x6fCLShCC3v3j5KLuQAqiJffAtp4hXK8hyIDkY9yrxcsV1URvqSqnEsu3T k0eE5uaG51uHwhEoFl/bL2o1WuVBJ4/kJo/OFfrg68MbYAWrs1lO4utXhYwF/Jb0Rv/o qSJ3l0iU/jG1bItpIkIVa8nFe9vNpGZzKLYZZUxlZkya+SK/dhEs4fcAh2IIBxyXLlsO eZLVgErHDZPtDYF/Cy+NaCNIgOgxL3/i35fmv/WalZ45l1OdGnz/QzIhFDFyvMWO8Nt6 pvew== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:date:subject:cc:to :from:dkim-signature; bh=KDIyZTlIle3JKNVn0YJbDqyvuC6ORc4/Rs9FG3+7Uiw=; fh=nfMhvOatEEQdarHLXWkYAacsO3BAL5U51OthxWThm0s=; b=aqex4yyY+HCTPU4qSU5cDtxKVX2OgCmsuhXWBbxjtV+zMGOC2Cb0Xi5tcRFY6QMXe9 SMrYL4oUCAJlVs8iNBJlNJCl55crJeSra5mXi9gK7JwIIA+6HGeLf4VGOEqOgSf2Dt3j vgARBLeNLXK2lyL8n+0OmPd/kxsO020HN764H9D9bLx8LiHEW2Zq1ynxCAN1p7xs+6FV /vwCINHj44K1uoskOtyJ8cAhdAxIHhbl6Cd1zKhdKMZKKi7Za0CLKDa4EmxbFWJFBCnz xW+raRls1wzBOO24a6wR5vrP2Wsm8AgVFA6W7VrOavbS5zxF/0FbJ3kcndkxYiLhnicb Dhqg==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@geanix.com header.s=default2211 header.b=fYwzi8qg; arc=pass (i=1 spf=pass spfdomain=geanix.com dkim=pass dkdomain=geanix.com dmarc=pass fromdomain=geanix.com); spf=pass (google.com: domain of linux-kernel+bounces-118975-linux.lists.archive=gmail.com@vger.kernel.org designates 139.178.88.99 as permitted sender) smtp.mailfrom="linux-kernel+bounces-118975-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=geanix.com Return-Path: Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [139.178.88.99]) by mx.google.com with ESMTPS id 16-20020a630210000000b005ce087e004dsi9545322pgc.799.2024.03.26.05.29.19 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 Mar 2024 05:29:20 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-118975-linux.lists.archive=gmail.com@vger.kernel.org designates 139.178.88.99 as permitted sender) client-ip=139.178.88.99; Authentication-Results: mx.google.com; dkim=pass header.i=@geanix.com header.s=default2211 header.b=fYwzi8qg; arc=pass (i=1 spf=pass spfdomain=geanix.com dkim=pass dkdomain=geanix.com dmarc=pass fromdomain=geanix.com); spf=pass (google.com: domain of linux-kernel+bounces-118975-linux.lists.archive=gmail.com@vger.kernel.org designates 139.178.88.99 as permitted sender) smtp.mailfrom="linux-kernel+bounces-118975-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=geanix.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id 560143034D7 for ; Tue, 26 Mar 2024 12:28:38 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 2285D7640F; Tue, 26 Mar 2024 12:27:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=geanix.com header.i=@geanix.com header.b="fYwzi8qg" Received: from www530.your-server.de (www530.your-server.de [188.40.30.78]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2E43C75806; Tue, 26 Mar 2024 12:27:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=188.40.30.78 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711456071; cv=none; b=rnXlNp5M4VkQLffSVs4gyGuEauct18A8Tl31bCzHTdEBEci4ShcAMF5HgZeK24hD9pTfSQxUludMmxvGbCQN5Ihrx8LQDmtL2f9wqmUTciRAYbPoyUzQ+ZSbIMmiRU51OmeYOrGscLu0bschKh7FrM6vnIOLeXPdTm5LrACWFGw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711456071; c=relaxed/simple; bh=zzOEjUVQkWqnS4hwzn6x2JGH4Xxki8samoobK81+3iA=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=LcJnsV6w+0XyMoxHopwqptN1+Yzqs3br3+2Ay2fRxjPQ4ObEIEstxY02Nenp/7ULQ91U55RfvuRBoDsht1WjNLl+sRfCa1ldHghwLkppm7gBY7FMd4fGD7BktreRIX3/WXtnLzONgUxthdiQliNIOBJv1pbEQsySSLqhtmkAJZI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=geanix.com; spf=pass smtp.mailfrom=geanix.com; dkim=pass (2048-bit key) header.d=geanix.com header.i=@geanix.com header.b=fYwzi8qg; arc=none smtp.client-ip=188.40.30.78 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=geanix.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=geanix.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=geanix.com; s=default2211; h=Content-Transfer-Encoding:Content-Type:MIME-Version: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References; bh=KDIyZTlIle3JKNVn0YJbDqyvuC6ORc4/Rs9FG3+7Uiw=; b=fYwzi8qgs+EMhEPLUJk3bSuLI9 W4ITKhwVKPEBpcmYoJbIPCzT68ej2ldjp4s1qFKehqHzAlwyUKQJWn6neWKXcuvg2efN3ftxj0nT6 50XmEjnb7SKxdDKyHgkUfl+q73MhE5m0MzqlZxoDcxONNPBBqL9UGB3ibx/wLmxI1JxqVOASUpi+v T/yExL4ekbfn8SlOHzTm74ysh06ILXCYh9k0f/nL1XGNEoLC03z8UM+VQoIUEfFb/naU3GiVHtjPo Dg6pZnf5LOTXMvBBFENbWviT4wnwFh+Cj9WNh1zddw0Bq/cvpGn+TUKDSzbzBX3cJhENVjN3PPx1m afCSvjQA==; Received: from sslproxy04.your-server.de ([78.46.152.42]) by www530.your-server.de with esmtpsa (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rp5u4-000J3B-LB; Tue, 26 Mar 2024 13:27:44 +0100 Received: from [185.17.218.86] (helo=zen..) by sslproxy04.your-server.de with esmtpsa (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rp5u3-000P6m-2s; Tue, 26 Mar 2024 13:27:43 +0100 From: =?UTF-8?q?Martin=20Hundeb=C3=B8ll?= To: Chandrasekar Ramakrishnan , Marc Kleine-Budde , Vincent Mailhol , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: =?UTF-8?q?Martin=20Hundeb=C3=B8ll?= , linux-can@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] can: m_can: don't enable transceiver when probing Date: Tue, 26 Mar 2024 13:26:38 +0100 Message-ID: <20240326122640.706041-1-martin@geanix.com> X-Mailer: git-send-email 2.44.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Authenticated-Sender: martin@geanix.com X-Virus-Scanned: Clear (ClamAV 0.103.10/27226/Tue Mar 26 09:37:28 2024) The m_can driver sets and clears the CCCR.INIT bit during probe (both when testing the NON-ISO bit, and when configuring the chip). After clearing the CCCR.INIT bit, the transceiver enters normal mode, where it affects the CAN bus (i.e. it ACKs frames). This can cause troubles when the m_can node is only used for monitoring the bus, as one cannot setup listen-only mode before the device is probed. Rework the probe flow, so that the CCCR.INIT bit is only cleared when upping the device. First, the tcan4x5x driver is changed to stay in standby mode during/after probe. This in turn requires changes when setting bits in the CCCR register, as its CSR and CSA bits are always high in standby mode. Signed-off-by: Martin Hundebøll --- drivers/net/can/m_can/m_can.c | 129 ++++++++++++++------------ drivers/net/can/m_can/tcan4x5x-core.c | 14 ++- 2 files changed, 79 insertions(+), 64 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 14b231c4d7ec..1ca245846fcd 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -379,38 +379,60 @@ m_can_txe_fifo_read(struct m_can_classdev *cdev, u32 fgi, u32 offset, u32 *val) return cdev->ops->read_fifo(cdev, addr_offset, val, 1); } -static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable) +static bool m_can_cccr_wait_bits(struct m_can_classdev *cdev, u32 mask, u32 val) { - u32 cccr = m_can_read(cdev, M_CAN_CCCR); - u32 timeout = 10; - u32 val = 0; - - /* Clear the Clock stop request if it was set */ - if (cccr & CCCR_CSR) - cccr &= ~CCCR_CSR; - - if (enable) { - /* enable m_can configuration */ - m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT); - udelay(5); - /* CCCR.CCE can only be set/reset while CCCR.INIT = '1' */ - m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT | CCCR_CCE); - } else { - m_can_write(cdev, M_CAN_CCCR, cccr & ~(CCCR_INIT | CCCR_CCE)); - } + u32 val_before = m_can_read(cdev, M_CAN_CCCR); + u32 val_after = (val_before & ~mask) | val; + size_t tries = 5; + + if (!(mask & CCCR_INIT) && !(val_before & CCCR_INIT)) + dev_warn(cdev->dev, + "trying to configure device when in normal mode. Expect failures\n"); + + /* The chip should be in standby mode when changing the CCCR register, + * and some chips set the CSR and CSA bits when in standby. Furthermore, + * the CSR and CSA bits should be written as zeros, even when they read + * ones. + */ + val_after &= ~(CCCR_CSR | CCCR_CSA); + + while (tries--) { + u32 val_read; + + /* Write the desired value in each try, as setting some bits in + * the CCCR register require other bits to be set first. E.g. + * setting the NISO bit requires setting the CCE bit first. + */ + m_can_write(cdev, M_CAN_CCCR, val_after); + + val_read = m_can_read(cdev, M_CAN_CCCR) & ~(CCCR_CSR | CCCR_CSA); - /* there's a delay for module initialization */ - if (enable) - val = CCCR_INIT | CCCR_CCE; - - while ((m_can_read(cdev, M_CAN_CCCR) & (CCCR_INIT | CCCR_CCE)) != val) { - if (timeout == 0) { - netdev_warn(cdev->net, "Failed to init module\n"); - return; - } - timeout--; - udelay(1); + if (val_read == val_after) + return true; + + usleep_range(1, 5); } + + return false; +} + +static void m_can_config_enable(struct m_can_classdev *cdev) +{ + /* CCCR_INIT must be set in order to set CCCR_CCE, but access to + * configuration registers should only be enabled when in standby mode, + * where CCCR_INIT is always set. + */ + if (!m_can_cccr_wait_bits(cdev, CCCR_CCE, CCCR_CCE)) + netdev_err(cdev->net, "failed to enable configuration mode\n"); +} + +static void m_can_config_disable(struct m_can_classdev *cdev) +{ + /* Only clear CCCR_CCE, since CCCR_INIT cannot be cleared while in + * standby mode + */ + if (!m_can_cccr_wait_bits(cdev, CCCR_CCE, 0)) + netdev_err(cdev->net, "failed to disable configuration registers\n"); } static void m_can_interrupt_enable(struct m_can_classdev *cdev, u32 interrupts) @@ -1403,7 +1425,7 @@ static int m_can_chip_config(struct net_device *dev) interrupts &= ~(IR_ARA | IR_ELO | IR_DRX | IR_TEFF | IR_TFE | IR_TCF | IR_HPM | IR_RF1F | IR_RF1W | IR_RF1N | IR_RF0F); - m_can_config_endisable(cdev, true); + m_can_config_enable(cdev); /* RX Buffer/FIFO Element Size 64 bytes data field */ m_can_write(cdev, M_CAN_RXESC, @@ -1521,7 +1543,7 @@ static int m_can_chip_config(struct net_device *dev) FIELD_PREP(TSCC_TCP_MASK, 0xf) | FIELD_PREP(TSCC_TSS_MASK, TSCC_TSS_INTERNAL)); - m_can_config_endisable(cdev, false); + m_can_config_disable(cdev); if (cdev->ops->init) cdev->ops->init(cdev); @@ -1544,12 +1566,15 @@ static int m_can_start(struct net_device *dev) cdev->can.state = CAN_STATE_ERROR_ACTIVE; - m_can_enable_all_interrupts(cdev); - if (cdev->version > 30) cdev->tx_fifo_putidx = FIELD_GET(TXFQS_TFQPI_MASK, m_can_read(cdev, M_CAN_TXFQS)); + m_can_enable_all_interrupts(cdev); + + if (!m_can_cccr_wait_bits(cdev, CCCR_INIT, 0)) + netdev_err(dev, "failed to enter normal mode\n"); + return 0; } @@ -1603,33 +1628,17 @@ static int m_can_check_core_release(struct m_can_classdev *cdev) */ static bool m_can_niso_supported(struct m_can_classdev *cdev) { - u32 cccr_reg, cccr_poll = 0; - int niso_timeout = -ETIMEDOUT; - int i; + bool niso_supported; - m_can_config_endisable(cdev, true); - cccr_reg = m_can_read(cdev, M_CAN_CCCR); - cccr_reg |= CCCR_NISO; - m_can_write(cdev, M_CAN_CCCR, cccr_reg); + /* First try to set the NISO bit (which requires the CCE bit too. */ + niso_supported = m_can_cccr_wait_bits(cdev, CCCR_NISO | CCCR_CCE, + CCCR_NISO | CCCR_CCE); - for (i = 0; i <= 10; i++) { - cccr_poll = m_can_read(cdev, M_CAN_CCCR); - if (cccr_poll == cccr_reg) { - niso_timeout = 0; - break; - } + /* Then clear the two bits again. */ + if (!m_can_cccr_wait_bits(cdev, CCCR_NISO | CCCR_CCE, 0)) + dev_err(cdev->dev, "failed to revert the NON-ISO bit in CCCR\n"); - usleep_range(1, 5); - } - - /* Clear NISO */ - cccr_reg &= ~(CCCR_NISO); - m_can_write(cdev, M_CAN_CCCR, cccr_reg); - - m_can_config_endisable(cdev, false); - - /* return false if time out (-ETIMEDOUT), else return true */ - return !niso_timeout; + return niso_supported; } static int m_can_dev_setup(struct m_can_classdev *cdev) @@ -1694,9 +1703,6 @@ static int m_can_dev_setup(struct m_can_classdev *cdev) return -EINVAL; } - if (cdev->ops->init) - cdev->ops->init(cdev); - return 0; } @@ -1708,7 +1714,8 @@ static void m_can_stop(struct net_device *dev) m_can_disable_all_interrupts(cdev); /* Set init mode to disengage from the network */ - m_can_config_endisable(cdev, true); + if (!m_can_cccr_wait_bits(cdev, CCCR_INIT, CCCR_INIT)) + netdev_err(dev, "failed to enter standby mode\n"); /* set the state as STOPPED */ cdev->can.state = CAN_STATE_STOPPED; diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c index a42600dac70d..c9937dc0d700 100644 --- a/drivers/net/can/m_can/tcan4x5x-core.c +++ b/drivers/net/can/m_can/tcan4x5x-core.c @@ -453,10 +453,18 @@ static int tcan4x5x_can_probe(struct spi_device *spi) goto out_power; } - ret = tcan4x5x_init(mcan_class); + tcan4x5x_check_wake(priv); + + ret = tcan4x5x_write_tcan_reg(mcan_class, TCAN4X5X_INT_EN, 0); if (ret) { - dev_err(&spi->dev, "tcan initialization failed %pe\n", - ERR_PTR(ret)); + dev_err(&spi->dev, "Disabling interrupts failed %pe\n", ERR_PTR(ret)); + goto out_power; + } + + ret = tcan4x5x_write_tcan_reg(mcan_class, TCAN4X5X_INT_FLAGS, + TCAN4X5X_CLEAR_ALL_INT); + if (ret) { + dev_err(&spi->dev, "Clearing interrupts failed %pe\n", ERR_PTR(ret)); goto out_power; } -- 2.44.0