Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: ethernet: adi: adin1110: Fix SPI transfers

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: bc93e19d088b ("net: ethernet: adi: Add ADIN1110 support")
Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Alexandru Tachici and committed by
David S. Miller
a526a3cc ac3208fb

+16 -21
+16 -21
drivers/net/ethernet/adi/adin1110.c
··· 196 196 { 197 197 u32 header_len = ADIN1110_RD_HEADER_LEN; 198 198 u32 read_len = ADIN1110_REG_LEN; 199 - struct spi_transfer t[2] = {0}; 199 + struct spi_transfer t = {0}; 200 200 int ret; 201 201 202 202 priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg); ··· 209 209 header_len++; 210 210 } 211 211 212 - t[0].tx_buf = &priv->data[0]; 213 - t[0].len = header_len; 214 - 215 212 if (priv->append_crc) 216 213 read_len++; 217 214 218 215 memset(&priv->data[header_len], 0, read_len); 219 - t[1].rx_buf = &priv->data[header_len]; 220 - t[1].len = read_len; 216 + t.tx_buf = &priv->data[0]; 217 + t.rx_buf = &priv->data[0]; 218 + t.len = read_len + header_len; 221 219 222 - ret = spi_sync_transfer(priv->spidev, t, 2); 220 + ret = spi_sync_transfer(priv->spidev, &t, 1); 223 221 if (ret) 224 222 return ret; 225 223 ··· 294 296 { 295 297 struct adin1110_priv *priv = port_priv->priv; 296 298 u32 header_len = ADIN1110_RD_HEADER_LEN; 297 - struct spi_transfer t[2] = {0}; 299 + struct spi_transfer t; 298 300 u32 frame_size_no_fcs; 299 301 struct sk_buff *rxb; 300 302 u32 frame_size; ··· 325 327 return ret; 326 328 327 329 frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN; 328 - 329 - rxb = netdev_alloc_skb(port_priv->netdev, round_len); 330 - if (!rxb) 331 - return -ENOMEM; 332 - 333 - memset(priv->data, 0, round_len + ADIN1110_RD_HEADER_LEN); 330 + memset(priv->data, 0, ADIN1110_RD_HEADER_LEN); 334 331 335 332 priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg); 336 333 priv->data[1] = FIELD_GET(GENMASK(7, 0), reg); ··· 335 342 header_len++; 336 343 } 337 344 338 - skb_put(rxb, frame_size_no_fcs + ADIN1110_FRAME_HEADER_LEN); 345 + rxb = netdev_alloc_skb(port_priv->netdev, round_len + header_len); 346 + if (!rxb) 347 + return -ENOMEM; 339 348 340 - t[0].tx_buf = &priv->data[0]; 341 - t[0].len = header_len; 349 + skb_put(rxb, frame_size_no_fcs + header_len + ADIN1110_FRAME_HEADER_LEN); 342 350 343 - t[1].rx_buf = &rxb->data[0]; 344 - t[1].len = round_len; 351 + t.tx_buf = &priv->data[0]; 352 + t.rx_buf = &rxb->data[0]; 353 + t.len = header_len + round_len; 345 354 346 - ret = spi_sync_transfer(priv->spidev, t, 2); 355 + ret = spi_sync_transfer(priv->spidev, &t, 1); 347 356 if (ret) { 348 357 kfree_skb(rxb); 349 358 return ret; 350 359 } 351 360 352 - skb_pull(rxb, ADIN1110_FRAME_HEADER_LEN); 361 + skb_pull(rxb, header_len + ADIN1110_FRAME_HEADER_LEN); 353 362 rxb->protocol = eth_type_trans(rxb, port_priv->netdev); 354 363 355 364 if ((port_priv->flags & IFF_ALLMULTI && rxb->pkt_type == PACKET_MULTICAST) ||