Skip to content

Commit

Permalink
net: ethernet: adi: adin1110: Fix SPI transfers
Browse files Browse the repository at this point in the history
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: bc93e19 ("net: ethernet: adi: Add ADIN1110 support")
Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Alexandru Tachici authored and David S. Miller committed Oct 19, 2022
1 parent ac3208f commit a526a3c
Showing 1 changed file with 16 additions and 21 deletions.
37 changes: 16 additions & 21 deletions drivers/net/ethernet/adi/adin1110.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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) ||
Expand Down

0 comments on commit a526a3c

Please sign in to comment.