From: Christian Marangi <ansuelsmth@gmail.com>
To: "Russell King (Oracle)" <linux@armlinux.org.uk>
Cc: "Andrew Lunn" <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@google.com>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
"Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Heiner Kallweit" <hkallweit1@gmail.com>,
"Florian Fainelli" <florian.fainelli@broadcom.com>,
"Broadcom internal kernel review list"
<bcm-kernel-feedback-list@broadcom.com>,
"Marek Behún" <kabel@kernel.org>,
"Andrei Botila" <andrei.botila@oss.nxp.com>,
"Sabrina Dubroca" <sd@queasysnail.net>,
"Eric Woudstra" <ericwouds@gmail.com>,
"Daniel Golle" <daniel@makrotopia.org>,
netdev@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.or
Subject: Re: [net-next PATCH v7 5/6] net: phy: Add support for Aeonsemi AS21xxx PHYs
Date: Tue, 15 Apr 2025 13:24:16 +0200 [thread overview]
Message-ID: <67fe41e5.5d0a0220.1003f3.9737@mx.google.com> (raw)
In-Reply-To: <Z_4o7SBGxHBdjWFZ@shell.armlinux.org.uk>
On Tue, Apr 15, 2025 at 10:37:49AM +0100, Russell King (Oracle) wrote:
> On Thu, Apr 10, 2025 at 11:53:35AM +0200, Christian Marangi wrote:
> > +#define VEND1_IPC_DATA0 0x5808
> > +#define VEND1_IPC_DATA1 0x5809
> > +#define VEND1_IPC_DATA2 0x580a
> > +#define VEND1_IPC_DATA3 0x580b
> > +#define VEND1_IPC_DATA4 0x580c
> > +#define VEND1_IPC_DATA5 0x580d
> > +#define VEND1_IPC_DATA6 0x580e
> > +#define VEND1_IPC_DATA7 0x580f
>
> Do you use any of these other than the first? If not, please remove
> them, maybe adding a comment before the first stating that there are
> 8 registers.
>
No since the macro is used. Also from Andrew request I will declare the
max number of IPC data register so yes I can drop.
> > +static int aeon_ipcs_wait_cmd(struct phy_device *phydev, bool parity_status)
> > +{
> > + u16 val;
> > +
> > + /* Exit condition logic:
> > + * - Wait for parity bit equal
> > + * - Wait for status success, error OR ready
> > + */
> > + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS, val,
> > + FIELD_GET(AEON_IPC_STS_PARITY, val) == parity_status &&
> > + (val & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_RCVD &&
> > + (val & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_PROCESS &&
> > + (val & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_BUSY,
> > + AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false);
>
> Hmm. I'm wondering whether:
>
> static bool aeon_ipc_ready(u16 val, bool parity_status)
> {
> u16 status;
>
> if (FIELD_GET(AEON_IPC_STS_PARITY, val) != parity_status)
> return false;
>
> status = val & AEON_IPC_STS_STATUS;
>
> return status != AEON_IPC_STS_STATUS_RCVD &&
> status != AEON_IPC_STS_STATUS_PROCESS &&
> status != AEON_IPC_STS_STATUS_BUSY;
> }
>
> would be better, and then maybe you can fit the code into less than 80
> columns. I'm not a fan of FIELD_PREP_CONST() when it causes differing
> usage patterns like the above (FIELD_GET(AEON_IPC_STS_STATUS, val)
> would match the coding style, and probably makes no difference to the
> code emitted.)
>
You are suggesting to use a generic readx function or use a while +
sleep to use the suggested _ready function?
> > +}
> > +
> > +static int aeon_ipc_send_cmd(struct phy_device *phydev,
> > + struct as21xxx_priv *priv,
> > + u16 cmd, u16 *ret_sts)
> > +{
> > + bool curr_parity;
> > + int ret;
> > +
> > + /* The IPC sync by using a single parity bit.
> > + * Each CMD have alternately this bit set or clear
> > + * to understand correct flow and packet order.
> > + */
> > + curr_parity = priv->parity_status;
> > + if (priv->parity_status)
> > + cmd |= AEON_IPC_CMD_PARITY;
> > +
> > + /* Always update parity for next packet */
> > + priv->parity_status = !priv->parity_status;
> > +
> > + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_CMD, cmd);
> > + if (ret)
> > + return ret;
> > +
> > + /* Wait for packet to be processed */
> > + usleep_range(AEON_IPC_DELAY, AEON_IPC_DELAY + 5000);
> > +
> > + /* With no ret_sts, ignore waiting for packet completion
> > + * (ipc parity bit sync)
> > + */
> > + if (!ret_sts)
> > + return 0;
> > +
> > + ret = aeon_ipcs_wait_cmd(phydev, curr_parity);
> > + if (ret)
> > + return ret;
> > +
> > + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS);
> > + if (ret < 0)
> > + return ret;
> > +
> > + *ret_sts = ret;
> > + if ((*ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_SUCCESS)
> > + return -EINVAL;
> > +
> > + return 0;
> > +}
> > +
> > +static int aeon_ipc_send_msg(struct phy_device *phydev,
> > + u16 opcode, u16 *data, unsigned int data_len,
> > + u16 *ret_sts)
> > +{
> > + struct as21xxx_priv *priv = phydev->priv;
> > + u16 cmd;
> > + int ret;
> > + int i;
> > +
> > + /* IPC have a max of 8 register to transfer data,
> > + * make sure we never exceed this.
> > + */
> > + if (data_len > AEON_IPC_DATA_MAX)
> > + return -EINVAL;
> > +
> > + mutex_lock(&priv->ipc_lock);
> > +
> > + for (i = 0; i < data_len / sizeof(u16); i++)
> > + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i),
> > + data[i]);
> > +
> > + cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, data_len) |
> > + FIELD_PREP(AEON_IPC_CMD_OPCODE, opcode);
> > + ret = aeon_ipc_send_cmd(phydev, priv, cmd, ret_sts);
> > + if (ret)
> > + phydev_err(phydev, "failed to send ipc msg for %x: %d\n",
> > + opcode, ret);
> > +
> > + mutex_unlock(&priv->ipc_lock);
> > +
> > + return ret;
> > +}
> > +
> > +static int aeon_ipc_rcv_msg(struct phy_device *phydev,
> > + u16 ret_sts, u16 *data)
> > +{
> > + struct as21xxx_priv *priv = phydev->priv;
> > + unsigned int size;
> > + int ret;
> > + int i;
> > +
> > + if ((ret_sts & AEON_IPC_STS_STATUS) == AEON_IPC_STS_STATUS_ERROR)
> > + return -EINVAL;
> > +
> > + /* Prevent IPC from stack smashing the kernel */
> > + size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts);
> > + if (size > AEON_IPC_DATA_MAX)
> > + return -EINVAL;
> > +
> > + mutex_lock(&priv->ipc_lock);
> > +
> > + for (i = 0; i < DIV_ROUND_UP(size, sizeof(u16)); i++) {
> > + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i));
> > + if (ret < 0) {
> > + size = ret;
> > + goto out;
> > + }
> > +
> > + data[i] = ret;
> > + }
> > +
> > +out:
> > + mutex_unlock(&priv->ipc_lock);
>
> I think the locking here is suspicious.
>
> aeon_ipc_send_msg() takes the lock, writes the registers, and waits for
> the success signal, returning the status, and then drops the lock.
>
> Time passes.
>
> aeon_ipc_rcv_msg() is then called, which extracts the number of bytes to
> be read from the returned status, takes the lock, reads the registers,
> and then drops the lock.
>
> So, what can happen is:
>
> Thread 1 Thread 2
> aeon_ipc_send_msg()
> aeon_ipc_send_msg()
> aeon_ipc_rcv_msg()
> aeon_ipc_rcv_msg()
>
> Which means thread 1 reads the reply from thread 2's message.
>
> So, this lock does nothing to really protect against the IPC mechanism
> against races.
>
> I think you need to combine both into a single function that takes the
> lock once and releases it once.
>
Mhhh I think I will have to create __ function for locked and non-locked
variant. I think I woulkd just handle the lock in the function using
send and rcv and maybe add some smatch tag to make sure the lock is
taken when entering those functions.
--
Ansuel
next prev parent reply other threads:[~2025-04-15 11:24 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-10 9:53 [net-next PATCH v7 0/6] net: phy: Add support for new Aeonsemi PHYs Christian Marangi
2025-04-10 9:53 ` [net-next PATCH v7 1/6] net: phy: pass PHY driver to .match_phy_device OP Christian Marangi
2025-04-10 9:53 ` [net-next PATCH v7 2/6] net: phy: bcm87xx: simplify " Christian Marangi
2025-04-10 9:53 ` [net-next PATCH v7 3/6] net: phy: nxp-c45-tja11xx: " Christian Marangi
2025-04-15 10:56 ` Andrei Botila
2025-04-10 9:53 ` [net-next PATCH v7 4/6] net: phy: introduce genphy_match_phy_device() Christian Marangi
2025-04-10 9:53 ` [net-next PATCH v7 5/6] net: phy: Add support for Aeonsemi AS21xxx PHYs Christian Marangi
2025-04-14 23:36 ` Jakub Kicinski
2025-04-15 1:14 ` Andrew Lunn
2025-04-15 11:19 ` Christian Marangi
2025-04-15 9:37 ` Russell King (Oracle)
2025-04-15 11:24 ` Christian Marangi [this message]
2025-04-15 12:33 ` Andrew Lunn
2025-04-15 12:55 ` Russell King (Oracle)
2025-04-15 13:04 ` Christian Marangi
2025-04-10 9:53 ` [net-next PATCH v7 6/6] dt-bindings: net: Document support for Aeonsemi PHYs Christian Marangi
2025-04-15 9:56 ` [net-next PATCH v7 0/6] net: phy: Add support for new " Russell King (Oracle)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=67fe41e5.5d0a0220.1003f3.9737@mx.google.com \
--to=ansuelsmth@gmail.com \
--cc=andrei.botila@oss.nxp.com \
--cc=andrew+netdev@lunn.ch \
--cc=bcm-kernel-feedback-list@broadcom.com \
--cc=conor+dt@kernel.org \
--cc=daniel@makrotopia.org \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@google.com \
--cc=ericwouds@gmail.com \
--cc=florian.fainelli@broadcom.com \
--cc=hkallweit1@gmail.com \
--cc=kabel@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.or \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=robh@kernel.org \
--cc=sd@queasysnail.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).