net: ethernet: adi: adin1110: Fix SPI transfers

[ Upstream commit a526a3cc9c ]

No need to use more than one SPI transfer for reads.
Use only one from now as ADIN1110/2111 does not tolerate
CS changes during reads.

The BCM2711/2708 SPI controllers worked fine, but the NXP
IMX8MM could not keep CS lowered during SPI bursts.

This change aims to make the ADIN1110/2111 driver compatible
with both SPI controllers, without any loss of bandwidth/other
capabilities.

Fixes: bc93e19d08 ("net: ethernet: adi: Add ADIN1110 support")
Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Alexandru Tachici 2022-10-17 19:37:03 +03:00 committed by Greg Kroah-Hartman
parent 1c65f8f981
commit 22d569b3d1

View file

@ -196,7 +196,7 @@ static int adin1110_read_reg(struct adin1110_priv *priv, u16 reg, u32 *val)
{
u32 header_len = ADIN1110_RD_HEADER_LEN;
u32 read_len = ADIN1110_REG_LEN;
struct spi_transfer t[2] = {0};
struct spi_transfer t = {0};
int ret;
priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg);
@ -209,17 +209,15 @@ static int adin1110_read_reg(struct adin1110_priv *priv, u16 reg, u32 *val)
header_len++;
}
t[0].tx_buf = &priv->data[0];
t[0].len = header_len;
if (priv->append_crc)
read_len++;
memset(&priv->data[header_len], 0, read_len);
t[1].rx_buf = &priv->data[header_len];
t[1].len = read_len;
t.tx_buf = &priv->data[0];
t.rx_buf = &priv->data[0];
t.len = read_len + header_len;
ret = spi_sync_transfer(priv->spidev, t, 2);
ret = spi_sync_transfer(priv->spidev, &t, 1);
if (ret)
return ret;
@ -296,7 +294,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv)
{
struct adin1110_priv *priv = port_priv->priv;
u32 header_len = ADIN1110_RD_HEADER_LEN;
struct spi_transfer t[2] = {0};
struct spi_transfer t;
u32 frame_size_no_fcs;
struct sk_buff *rxb;
u32 frame_size;
@ -327,12 +325,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv)
return ret;
frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN;
rxb = netdev_alloc_skb(port_priv->netdev, round_len);
if (!rxb)
return -ENOMEM;
memset(priv->data, 0, round_len + ADIN1110_RD_HEADER_LEN);
memset(priv->data, 0, ADIN1110_RD_HEADER_LEN);
priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg);
priv->data[1] = FIELD_GET(GENMASK(7, 0), reg);
@ -342,21 +335,23 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv)
header_len++;
}
skb_put(rxb, frame_size_no_fcs + ADIN1110_FRAME_HEADER_LEN);
rxb = netdev_alloc_skb(port_priv->netdev, round_len + header_len);
if (!rxb)
return -ENOMEM;
t[0].tx_buf = &priv->data[0];
t[0].len = header_len;
skb_put(rxb, frame_size_no_fcs + header_len + ADIN1110_FRAME_HEADER_LEN);
t[1].rx_buf = &rxb->data[0];
t[1].len = round_len;
t.tx_buf = &priv->data[0];
t.rx_buf = &rxb->data[0];
t.len = header_len + round_len;
ret = spi_sync_transfer(priv->spidev, t, 2);
ret = spi_sync_transfer(priv->spidev, &t, 1);
if (ret) {
kfree_skb(rxb);
return ret;
}
skb_pull(rxb, ADIN1110_FRAME_HEADER_LEN);
skb_pull(rxb, header_len + ADIN1110_FRAME_HEADER_LEN);
rxb->protocol = eth_type_trans(rxb, port_priv->netdev);
if ((port_priv->flags & IFF_ALLMULTI && rxb->pkt_type == PACKET_MULTICAST) ||