From nobody Sun Jun 28 01:53:23 2026 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 DE9EFC433FE for ; Wed, 16 Feb 2022 16:03:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235934AbiBPQDu (ORCPT ); Wed, 16 Feb 2022 11:03:50 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:49522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233934AbiBPQDq (ORCPT ); Wed, 16 Feb 2022 11:03:46 -0500 Received: from mail-ed1-x52a.google.com (mail-ed1-x52a.google.com [IPv6:2a00:1450:4864:20::52a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B1BA02A8D14 for ; Wed, 16 Feb 2022 08:03:33 -0800 (PST) Received: by mail-ed1-x52a.google.com with SMTP id q17so4728796edd.4 for ; Wed, 16 Feb 2022 08:03:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pqrs.dk; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CgwwwRe7DVOH/1dsBc3Z4xB3KrKc56bjTH+52806yM0=; b=LzzwC1b1yXUAENqm/50FckyEAdxE50WQO+Rb56jagPFwh/PDFNvGbXlLS48qdcS8hK mOquVl6ZrQlSHIrIaREZr1hdqmcrZ1DhXZQXMt1pgVyPH1VcKYguZ/SRmTCEtvkJAP3b 5c83Q4v143IVlfHw+7EWjcUUPT6Uv17e/+F7Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CgwwwRe7DVOH/1dsBc3Z4xB3KrKc56bjTH+52806yM0=; b=1tXCLGQf2hV8aCtu6cnfx+grvUsihDHTMKsXQlkOIg5jo59IbOOo/ybRjuBw+9sFKE jFN6M5N8xG/dC0GhGi77+O+j6tHC+IwU6g5xvMXMNHUjVZ8U8BEIwrZeX3KXxV6J0c/g ogKFKDToveBw//L8hjPkQrT6SkfNCWrMVv1UwLOfVM2OBJEBu8uzcqGi62afYHOatTut ht211Yy08CbTPfoHwT9WNcSX52kE5u3B/+XBA1DlJ4MDXgewZ6Jeyfb6nRJE2XOA5BOv DXEcwHqPwlOuRD2sZyfbdXpXHFVgzytO3LjaSxwAQgosCy2ziIJPKADf+t6o6VhdmHkd Kcmw== X-Gm-Message-State: AOAM531+2gMBv5OfbqCPEEOh3lIDemWHKzIicHD0Dc5hpXyCRX6gnHk+ +p1ndLn/zrVW3dabcsQ7zwxg2Q== X-Google-Smtp-Source: ABdhPJw4owliV0xvwuYMJxIJK2lCHFwl8dDLixoAHNVsFeXtWmFRFqobpt+tY85Zr09HRdRILOcCSw== X-Received: by 2002:aa7:c983:0:b0:410:d314:6451 with SMTP id c3-20020aa7c983000000b00410d3146451mr3679668edt.56.1645027412302; Wed, 16 Feb 2022 08:03:32 -0800 (PST) Received: from capella.. ([193.89.194.60]) by smtp.gmail.com with ESMTPSA id j19sm48365ejm.111.2022.02.16.08.03.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 08:03:31 -0800 (PST) From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= To: Linus Walleij , Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , =?UTF-8?q?Alvin=20=C5=A0ipraga?= Cc: Luiz Angelo Daros de Luca , =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= , Michael Rasmussen , netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net-next 1/2] net: dsa: realtek: allow subdrivers to externally lock regmap Date: Wed, 16 Feb 2022 17:04:59 +0100 Message-Id: <20220216160500.2341255-2-alvin@pqrs.dk> X-Mailer: git-send-email 2.35.0 In-Reply-To: <20220216160500.2341255-1-alvin@pqrs.dk> References: <20220216160500.2341255-1-alvin@pqrs.dk> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Alvin =C5=A0ipraga Currently there is no way for Realtek DSA subdrivers to serialize consecutive regmap accesses. In preparation for a bugfix relating to indirect PHY register access - which involves a series of regmap reads and writes - add a facility for subdrivers to serialize their regmap access. Specifically, a mutex is added to the driver private data structure and the standard regmap is initialized with custom lock/unlock ops which use this mutex. Then, a "nolock" variant of the regmap is added, which is functionally equivalent to the existing regmap except that regmap locking is disabled. Functions that wish to serialize a sequence of regmap accesses may then lock the newly introduced driver-owned mutex before using the nolock regmap. Doing things this way means that subdriver code that doesn't care about serialized register access - i.e. the vast majority of code - needn't worry about synchronizing register access with an external lock: it can just continue to use the original regmap. Another advantage of this design is that, while regmaps with locking disabled do not expose a debugfs interface for obvious reasons, there still exists the original regmap which does expose this interface. This interface remains safe to use even combined with driver codepaths that use the nolock regmap, because said codepaths will use the same mutex to synchronize access. With respect to disadvantages, it can be argued that having near-duplicate regmaps is confusing. However, the naming is rather explicit, and examples will abound. Finally, while we are at it, rename realtek_smi_mdio_regmap_config to realtek_smi_regmap_config. This makes it consistent with the naming realtek_mdio_regmap_config in realtek-mdio.c. Signed-off-by: Alvin =C5=A0ipraga --- drivers/net/dsa/realtek/realtek-mdio.c | 46 ++++++++++++++++++++++-- drivers/net/dsa/realtek/realtek-smi.c | 48 ++++++++++++++++++++++++-- drivers/net/dsa/realtek/realtek.h | 2 ++ 3 files changed, 91 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realt= ek/realtek-mdio.c index 0308be95d00a..31e1f100e48e 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -98,6 +98,20 @@ static int realtek_mdio_read(void *ctx, u32 reg, u32 *va= l) return ret; } =20 +static void realtek_mdio_lock(void *ctx) +{ + struct realtek_priv *priv =3D ctx; + + mutex_lock(&priv->map_lock); +} + +static void realtek_mdio_unlock(void *ctx) +{ + struct realtek_priv *priv =3D ctx; + + mutex_unlock(&priv->map_lock); +} + static const struct regmap_config realtek_mdio_regmap_config =3D { .reg_bits =3D 10, /* A4..A0 R4..R0 */ .val_bits =3D 16, @@ -108,6 +122,21 @@ static const struct regmap_config realtek_mdio_regmap_= config =3D { .reg_read =3D realtek_mdio_read, .reg_write =3D realtek_mdio_write, .cache_type =3D REGCACHE_NONE, + .lock =3D realtek_mdio_lock, + .unlock =3D realtek_mdio_unlock, +}; + +static const struct regmap_config realtek_mdio_nolock_regmap_config =3D { + .reg_bits =3D 10, /* A4..A0 R4..R0 */ + .val_bits =3D 16, + .reg_stride =3D 1, + /* PHY regs are at 0x8000 */ + .max_register =3D 0xffff, + .reg_format_endian =3D REGMAP_ENDIAN_BIG, + .reg_read =3D realtek_mdio_read, + .reg_write =3D realtek_mdio_write, + .cache_type =3D REGCACHE_NONE, + .disable_locking =3D true, }; =20 static int realtek_mdio_probe(struct mdio_device *mdiodev) @@ -115,8 +144,9 @@ static int realtek_mdio_probe(struct mdio_device *mdiod= ev) struct realtek_priv *priv; struct device *dev =3D &mdiodev->dev; const struct realtek_variant *var; - int ret; + struct regmap_config rc; struct device_node *np; + int ret; =20 var =3D of_device_get_match_data(dev); if (!var) @@ -126,13 +156,25 @@ static int realtek_mdio_probe(struct mdio_device *mdi= odev) if (!priv) return -ENOMEM; =20 - priv->map =3D devm_regmap_init(dev, NULL, priv, &realtek_mdio_regmap_conf= ig); + mutex_init(&priv->map_lock); + + rc =3D realtek_mdio_regmap_config; + rc.lock_arg =3D priv; + priv->map =3D devm_regmap_init(dev, NULL, priv, &rc); if (IS_ERR(priv->map)) { ret =3D PTR_ERR(priv->map); dev_err(dev, "regmap init failed: %d\n", ret); return ret; } =20 + rc =3D realtek_mdio_nolock_regmap_config; + priv->map_nolock =3D devm_regmap_init(dev, NULL, priv, &rc); + if (IS_ERR(priv->map_nolock)) { + ret =3D PTR_ERR(priv->map_nolock); + dev_err(dev, "regmap init failed: %d\n", ret); + return ret; + } + priv->mdio_addr =3D mdiodev->addr; priv->bus =3D mdiodev->bus; priv->dev =3D &mdiodev->dev; diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realte= k/realtek-smi.c index 8806b74bd7a8..2243d3da55b2 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -311,7 +311,21 @@ static int realtek_smi_read(void *ctx, u32 reg, u32 *v= al) return realtek_smi_read_reg(priv, reg, val); } =20 -static const struct regmap_config realtek_smi_mdio_regmap_config =3D { +static void realtek_smi_lock(void *ctx) +{ + struct realtek_priv *priv =3D ctx; + + mutex_lock(&priv->map_lock); +} + +static void realtek_smi_unlock(void *ctx) +{ + struct realtek_priv *priv =3D ctx; + + mutex_unlock(&priv->map_lock); +} + +static const struct regmap_config realtek_smi_regmap_config =3D { .reg_bits =3D 10, /* A4..A0 R4..R0 */ .val_bits =3D 16, .reg_stride =3D 1, @@ -321,6 +335,21 @@ static const struct regmap_config realtek_smi_mdio_reg= map_config =3D { .reg_read =3D realtek_smi_read, .reg_write =3D realtek_smi_write, .cache_type =3D REGCACHE_NONE, + .lock =3D realtek_smi_lock, + .unlock =3D realtek_smi_unlock, +}; + +static const struct regmap_config realtek_smi_nolock_regmap_config =3D { + .reg_bits =3D 10, /* A4..A0 R4..R0 */ + .val_bits =3D 16, + .reg_stride =3D 1, + /* PHY regs are at 0x8000 */ + .max_register =3D 0xffff, + .reg_format_endian =3D REGMAP_ENDIAN_BIG, + .reg_read =3D realtek_smi_read, + .reg_write =3D realtek_smi_write, + .cache_type =3D REGCACHE_NONE, + .disable_locking =3D true, }; =20 static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) @@ -385,6 +414,7 @@ static int realtek_smi_probe(struct platform_device *pd= ev) const struct realtek_variant *var; struct device *dev =3D &pdev->dev; struct realtek_priv *priv; + struct regmap_config rc; struct device_node *np; int ret; =20 @@ -395,14 +425,26 @@ static int realtek_smi_probe(struct platform_device *= pdev) if (!priv) return -ENOMEM; priv->chip_data =3D (void *)priv + sizeof(*priv); - priv->map =3D devm_regmap_init(dev, NULL, priv, - &realtek_smi_mdio_regmap_config); + + mutex_init(&priv->map_lock); + + rc =3D realtek_smi_regmap_config; + rc.lock_arg =3D priv; + priv->map =3D devm_regmap_init(dev, NULL, priv, &rc); if (IS_ERR(priv->map)) { ret =3D PTR_ERR(priv->map); dev_err(dev, "regmap init failed: %d\n", ret); return ret; } =20 + rc =3D realtek_smi_nolock_regmap_config; + priv->map_nolock =3D devm_regmap_init(dev, NULL, priv, &rc); + if (IS_ERR(priv->map_nolock)) { + ret =3D PTR_ERR(priv->map_nolock); + dev_err(dev, "regmap init failed: %d\n", ret); + return ret; + } + /* Link forward and backward */ priv->dev =3D dev; priv->clk_delay =3D var->clk_delay; diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/re= altek.h index e7d3e1bcf8b8..4fa7c6ba874a 100644 --- a/drivers/net/dsa/realtek/realtek.h +++ b/drivers/net/dsa/realtek/realtek.h @@ -52,6 +52,8 @@ struct realtek_priv { struct gpio_desc *mdc; struct gpio_desc *mdio; struct regmap *map; + struct regmap *map_nolock; + struct mutex map_lock; struct mii_bus *slave_mii_bus; struct mii_bus *bus; int mdio_addr; --=20 2.35.0 From nobody Sun Jun 28 01:53:23 2026 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 39FCCC433FE for ; Wed, 16 Feb 2022 16:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235939AbiBPQD6 (ORCPT ); Wed, 16 Feb 2022 11:03:58 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:49694 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235922AbiBPQDs (ORCPT ); Wed, 16 Feb 2022 11:03:48 -0500 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EAE542A8D0C for ; Wed, 16 Feb 2022 08:03:35 -0800 (PST) Received: by mail-ed1-x52d.google.com with SMTP id c6so1977801edk.12 for ; Wed, 16 Feb 2022 08:03:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pqrs.dk; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=151KIZ20IIFNSQmdYRUVjHa4bOA5A5/XYS9O5JQklAI=; b=lh3mDuwouCECAY9+enH6p3rPY0ru9wMKGNyO9MqYiWkYyUbQ9w1kGH+czehn+i5fyi nMUpg2Cl+SpQ4itc4p9VCE3jt5w1fz3F83kS37Rzej4zVEDAPEGDcxplSVqP06mpY3gX y6ptlLagUW86rybf2y0knm/Kz8YhnQdbqIvzs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=151KIZ20IIFNSQmdYRUVjHa4bOA5A5/XYS9O5JQklAI=; b=ErI3Sbkqx7Ix22zJil0t9LxT+KYg1BG6JFFjaYp8HivZLGu9X7g3KPwXMLIqlsUzWW FK+coIhKofjW0F0fAukNkUUXUm3PWjY7d8iqnpTE88/HjLbfwQ0x8A68e9iaT5/Fu1JI uYc3uIvUxmSQHc+cVGNTpnwXk1c7DqGkrOlyBkTJTFWNOJLqxlQQFaNfl5YfZM4dqi7r d9n+tCszwuc3jhIS0TimM27r5nglcEwGA0mNBJVqyYCu0c868APkgtqjrwJ30QoQdq6g zZML0L3up2AiupNvCoxfnwXe4BNdej5pVqahx2gdTi0vU6tGnMTco4BxXGQ8L/TRSfpX Urwg== X-Gm-Message-State: AOAM5301WQ1VTLYmttWmaUofHU6bviNuVkMIwxdxFX+ZDIo1VdoPOOW1 BHqCJZR0Rzf7DENp0Fxhx2kwNQ== X-Google-Smtp-Source: ABdhPJyEaJ8Ox8sISNJO00yJxKPFNXb76QhHKp48G3ttPeQQuAQlcpLs2UxuAMz7MbXgKfHBoFQdfw== X-Received: by 2002:a05:6402:190:b0:407:27da:4def with SMTP id r16-20020a056402019000b0040727da4defmr3756454edv.345.1645027414469; Wed, 16 Feb 2022 08:03:34 -0800 (PST) Received: from capella.. ([193.89.194.60]) by smtp.gmail.com with ESMTPSA id j19sm48365ejm.111.2022.02.16.08.03.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 08:03:33 -0800 (PST) From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= To: Linus Walleij , Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , =?UTF-8?q?Alvin=20=C5=A0ipraga?= Cc: Luiz Angelo Daros de Luca , =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= , Michael Rasmussen , netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net-next 2/2] net: dsa: realtek: rtl8365mb: serialize indirect PHY register access Date: Wed, 16 Feb 2022 17:05:00 +0100 Message-Id: <20220216160500.2341255-3-alvin@pqrs.dk> X-Mailer: git-send-email 2.35.0 In-Reply-To: <20220216160500.2341255-1-alvin@pqrs.dk> References: <20220216160500.2341255-1-alvin@pqrs.dk> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Alvin =C5=A0ipraga Realtek switches in the rtl8365mb family can access the PHY registers of the internal PHYs via the switch registers. This method is called indirect access. At a high level, the indirect PHY register access method involves reading and writing some special switch registers in a particular sequence. This works for both SMI and MDIO connected switches. Currently the rtl8365mb driver does not take any care to serialize the aforementioned access to the switch registers. In particular, it is permitted for other driver code to access other switch registers while the indirect PHY register access is ongoing. Locking is only done at the regmap level. This, however, is a bug: concurrent register access, even to unrelated switch registers, risks corrupting the PHY register value read back via the indirect access method described above. Ar=C4=B1n=C3=A7 reported that the switch sometimes returns nonsense data wh= en reading the PHY registers. In particular, a value of 0 causes the kernel's PHY subsystem to think that the link is down, but since most reads return correct data, the link then flip-flops between up and down over a period of time. The aforementioned bug can be readily observed by: 1. Enabling ftrace events for regmap and mdio 2. Polling BSMR PHY register for a connected port; it should always read the same (e.g. 0x79ed) 3. Wait for step 2 to give a different value Example command for step 2: while true; do phytool read swp2/2/0x01; done On my i.MX8MM, the above steps will yield a bogus value for the BSMR PHY register within a matter of seconds. The interleaved register access it then evident in the trace log: kworker/3:4-70 [003] ....... 1927.139849: regmap_reg_write: ethernet= -switch reg=3D1004 val=3Dbd phytool-16816 [002] ....... 1927.139979: regmap_reg_read: ethernet-= switch reg=3D1f01 val=3D0 kworker/3:4-70 [003] ....... 1927.140381: regmap_reg_read: ethernet-= switch reg=3D1005 val=3D0 phytool-16816 [002] ....... 1927.140468: regmap_reg_read: ethernet-= switch reg=3D1d15 val=3Da69 kworker/3:4-70 [003] ....... 1927.140864: regmap_reg_read: ethernet-= switch reg=3D1003 val=3D0 phytool-16816 [002] ....... 1927.140955: regmap_reg_write: ethernet= -switch reg=3D1f02 val=3D2041 kworker/3:4-70 [003] ....... 1927.141390: regmap_reg_read: ethernet-= switch reg=3D1002 val=3D0 phytool-16816 [002] ....... 1927.141479: regmap_reg_write: ethernet= -switch reg=3D1f00 val=3D1 kworker/3:4-70 [003] ....... 1927.142311: regmap_reg_write: ethernet= -switch reg=3D1004 val=3Dbe phytool-16816 [002] ....... 1927.142410: regmap_reg_read: ethernet-= switch reg=3D1f01 val=3D0 kworker/3:4-70 [003] ....... 1927.142534: regmap_reg_read: ethernet-= switch reg=3D1005 val=3D0 phytool-16816 [002] ....... 1927.142618: regmap_reg_read: ethernet-= switch reg=3D1f04 val=3D0 phytool-16816 [002] ....... 1927.142641: mdio_access: SMI-0 read p= hy:0x02 reg:0x01 val:0x0000 <- ?! kworker/3:4-70 [003] ....... 1927.143037: regmap_reg_read: ethernet-= switch reg=3D1001 val=3D0 kworker/3:4-70 [003] ....... 1927.143133: regmap_reg_read: ethernet-= switch reg=3D1000 val=3D2d89 kworker/3:4-70 [003] ....... 1927.143213: regmap_reg_write: ethernet= -switch reg=3D1004 val=3Dbe kworker/3:4-70 [003] ....... 1927.143291: regmap_reg_read: ethernet-= switch reg=3D1005 val=3D0 kworker/3:4-70 [003] ....... 1927.143368: regmap_reg_read: ethernet-= switch reg=3D1003 val=3D0 kworker/3:4-70 [003] ....... 1927.143443: regmap_reg_read: ethernet-= switch reg=3D1002 val=3D6 The kworker here is polling MIB counters for stats, as evidenced by the register 0x1004 that we are writing to (RTL8365MB_MIB_ADDRESS_REG). This polling is performed every 3 seconds, but is just one example of such unsynchronized access. Further investigation reveals the underlying problem: if we read from an arbitrary register A and this read coincides with the indirect access method in rtl8365mb_phy_ocp_read, then the final read from RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG will always return the value in register A. The value read back can be readily poisoned by repeatedly reading back the value of another register A via debugfs in a busy loop via the dd utility or similar. This issue appears to be unique to the indirect PHY register access pattern. In particular, it does not seem to impact similar sequential register operations such MIB counter access. To fix this problem, one must guard against exactly the scenario seen in the above trace. In particular, other parts of the driver using the regmap API must not be permitted to access the switch registers until the PHY register access is complete. Fix this by using the newly introduced "nolock" regmap in all PHY-related functions, and by aquiring the regmap mutex at the top level of the PHY register access callbacks. Although no issue has been observed with PHY register _writes_, this change also serializes the indirect access method there. This is done purely as a matter of convenience. Fixes: 4af2950c50c8 ("net: dsa: realtek-smi: add rtl8365mb subdriver for RT= L8365MB-VC") Link: https://lore.kernel.org/netdev/CAJq09z5FCgG-+jVT7uxh1a-0CiiFsoKoHYsAW= JtiKwv7LXKofQ@mail.gmail.com/ Reported-by: Ar=C4=B1n=C3=A7 =C3=9CNAL Reported-by: Luiz Angelo Daros de Luca Signed-off-by: Alvin =C5=A0ipraga --- drivers/net/dsa/realtek/rtl8365mb.c | 54 ++++++++++++++++++----------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/= rtl8365mb.c index 2ed592147c20..c39d6b744597 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -590,7 +590,7 @@ static int rtl8365mb_phy_poll_busy(struct realtek_priv = *priv) { u32 val; =20 - return regmap_read_poll_timeout(priv->map, + return regmap_read_poll_timeout(priv->map_nolock, RTL8365MB_INDIRECT_ACCESS_STATUS_REG, val, !val, 10, 100); } @@ -604,7 +604,7 @@ static int rtl8365mb_phy_ocp_prepare(struct realtek_pri= v *priv, int phy, /* Set OCP prefix */ val =3D FIELD_GET(RTL8365MB_PHY_OCP_ADDR_PREFIX_MASK, ocp_addr); ret =3D regmap_update_bits( - priv->map, RTL8365MB_GPHY_OCP_MSB_0_REG, + priv->map_nolock, RTL8365MB_GPHY_OCP_MSB_0_REG, RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK, FIELD_PREP(RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK, val)); if (ret) @@ -617,8 +617,8 @@ static int rtl8365mb_phy_ocp_prepare(struct realtek_pri= v *priv, int phy, ocp_addr >> 1); val |=3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_9_6_MASK, ocp_addr >> 6); - ret =3D regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG, - val); + ret =3D regmap_write(priv->map_nolock, + RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG, val); if (ret) return ret; =20 @@ -631,36 +631,42 @@ static int rtl8365mb_phy_ocp_read(struct realtek_priv= *priv, int phy, u32 val; int ret; =20 + mutex_lock(&priv->map_lock); + ret =3D rtl8365mb_phy_poll_busy(priv); if (ret) - return ret; + goto out; =20 ret =3D rtl8365mb_phy_ocp_prepare(priv, phy, ocp_addr); if (ret) - return ret; + goto out; =20 /* Execute read operation */ val =3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK, RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) | FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK, RTL8365MB_INDIRECT_ACCESS_CTRL_RW_READ); - ret =3D regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val); + ret =3D regmap_write(priv->map_nolock, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, + val); if (ret) - return ret; + goto out; =20 ret =3D rtl8365mb_phy_poll_busy(priv); if (ret) - return ret; + goto out; =20 /* Get PHY register data */ - ret =3D regmap_read(priv->map, RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG, - &val); + ret =3D regmap_read(priv->map_nolock, + RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG, &val); if (ret) - return ret; + goto out; =20 *data =3D val & 0xFFFF; =20 - return 0; +out: + mutex_unlock(&priv->map_lock); + + return ret; } =20 static int rtl8365mb_phy_ocp_write(struct realtek_priv *priv, int phy, @@ -669,32 +675,38 @@ static int rtl8365mb_phy_ocp_write(struct realtek_pri= v *priv, int phy, u32 val; int ret; =20 + mutex_lock(&priv->map_lock); + ret =3D rtl8365mb_phy_poll_busy(priv); if (ret) - return ret; + goto out; =20 ret =3D rtl8365mb_phy_ocp_prepare(priv, phy, ocp_addr); if (ret) - return ret; + goto out; =20 /* Set PHY register data */ - ret =3D regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG, - data); + ret =3D regmap_write(priv->map_nolock, + RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG, data); if (ret) - return ret; + goto out; =20 /* Execute write operation */ val =3D FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK, RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) | FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK, RTL8365MB_INDIRECT_ACCESS_CTRL_RW_WRITE); - ret =3D regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val); + ret =3D regmap_write(priv->map_nolock, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, + val); if (ret) - return ret; + goto out; =20 ret =3D rtl8365mb_phy_poll_busy(priv); if (ret) - return ret; + goto out; + +out: + mutex_unlock(&priv->map_lock); =20 return 0; } --=20 2.35.0