Skip to content

Commit

Permalink
net: lantiq_xrx200: increase buffer reservation
Browse files Browse the repository at this point in the history
If the user sets a lower mtu on the CPU port than on the switch,
then DMA inserts a few more bytes into the buffer than expected.
In the worst case, it may exceed the size of the buffer. The
experiments showed that the buffer should be a multiple of the
burst length value. This patch rounds the length of the rx buffer
upwards and fixes this bug. The reservation of FCS space in the
buffer has been removed as PMAC strips the FCS.

Fixes: 998ac35 ("net: lantiq: add support for jumbo frames")
Reported-by: Thomas Nixon <[email protected]>
Signed-off-by: Aleksander Jan Bajkowski <[email protected]>
Signed-off-by: Jakub Kicinski <[email protected]>
  • Loading branch information
abajk authored and kuba-moo committed Dec 18, 2021
1 parent 14193d5 commit 1488fc2
Showing 1 changed file with 24 additions and 10 deletions.
34 changes: 24 additions & 10 deletions drivers/net/ethernet/lantiq_xrx200.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ struct xrx200_priv {
struct xrx200_chan chan_tx;
struct xrx200_chan chan_rx;

u16 rx_buf_size;

struct net_device *net_dev;
struct device *dev;

Expand All @@ -97,6 +99,16 @@ static void xrx200_pmac_mask(struct xrx200_priv *priv, u32 clear, u32 set,
xrx200_pmac_w32(priv, val, offset);
}

static int xrx200_max_frame_len(int mtu)
{
return VLAN_ETH_HLEN + mtu;
}

static int xrx200_buffer_size(int mtu)
{
return round_up(xrx200_max_frame_len(mtu), 4 * XRX200_DMA_BURST_LEN);
}

/* drop all the packets from the DMA ring */
static void xrx200_flush_dma(struct xrx200_chan *ch)
{
Expand All @@ -109,8 +121,7 @@ static void xrx200_flush_dma(struct xrx200_chan *ch)
break;

desc->ctl = LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
(ch->priv->net_dev->mtu + VLAN_ETH_HLEN +
ETH_FCS_LEN);
ch->priv->rx_buf_size;
ch->dma.desc++;
ch->dma.desc %= LTQ_DESC_NUM;
}
Expand Down Expand Up @@ -158,21 +169,21 @@ static int xrx200_close(struct net_device *net_dev)

static int xrx200_alloc_skb(struct xrx200_chan *ch)
{
int len = ch->priv->net_dev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
struct sk_buff *skb = ch->skb[ch->dma.desc];
struct xrx200_priv *priv = ch->priv;
dma_addr_t mapping;
int ret = 0;

ch->skb[ch->dma.desc] = netdev_alloc_skb_ip_align(ch->priv->net_dev,
len);
ch->skb[ch->dma.desc] = netdev_alloc_skb_ip_align(priv->net_dev,
priv->rx_buf_size);
if (!ch->skb[ch->dma.desc]) {
ret = -ENOMEM;
goto skip;
}

mapping = dma_map_single(ch->priv->dev, ch->skb[ch->dma.desc]->data,
len, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(ch->priv->dev, mapping))) {
mapping = dma_map_single(priv->dev, ch->skb[ch->dma.desc]->data,
priv->rx_buf_size, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(priv->dev, mapping))) {
dev_kfree_skb_any(ch->skb[ch->dma.desc]);
ch->skb[ch->dma.desc] = skb;
ret = -ENOMEM;
Expand All @@ -184,7 +195,7 @@ static int xrx200_alloc_skb(struct xrx200_chan *ch)
wmb();
skip:
ch->dma.desc_base[ch->dma.desc].ctl =
LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | len;
LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | priv->rx_buf_size;

return ret;
}
Expand Down Expand Up @@ -356,6 +367,7 @@ xrx200_change_mtu(struct net_device *net_dev, int new_mtu)
int ret = 0;

net_dev->mtu = new_mtu;
priv->rx_buf_size = xrx200_buffer_size(new_mtu);

if (new_mtu <= old_mtu)
return ret;
Expand All @@ -375,6 +387,7 @@ xrx200_change_mtu(struct net_device *net_dev, int new_mtu)
ret = xrx200_alloc_skb(ch_rx);
if (ret) {
net_dev->mtu = old_mtu;
priv->rx_buf_size = xrx200_buffer_size(old_mtu);
break;
}
dev_kfree_skb_any(skb);
Expand Down Expand Up @@ -505,7 +518,8 @@ static int xrx200_probe(struct platform_device *pdev)
net_dev->netdev_ops = &xrx200_netdev_ops;
SET_NETDEV_DEV(net_dev, dev);
net_dev->min_mtu = ETH_ZLEN;
net_dev->max_mtu = XRX200_DMA_DATA_LEN - VLAN_ETH_HLEN - ETH_FCS_LEN;
net_dev->max_mtu = XRX200_DMA_DATA_LEN - xrx200_max_frame_len(0);
priv->rx_buf_size = xrx200_buffer_size(ETH_DATA_LEN);

/* load the memory ranges */
priv->pmac_reg = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
Expand Down

0 comments on commit 1488fc2

Please sign in to comment.