Skip to content

Commit

Permalink
stmmac: do not perform zero-copy for rx frames
Browse files Browse the repository at this point in the history
This patch is to allow this driver to copy tiny frames during the reception
process. This is giving more stability while stressing the driver on STi
embedded systems.

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: Alexandre TORGUE <alexandre.torgue@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Giuseppe Cavallaro authored and David S. Miller committed Mar 2, 2016
1 parent 8ecd80a commit 22ad383
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 15 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/stmicro/stmmac/stmmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ struct stmmac_priv {
unsigned int cur_rx;
unsigned int dirty_rx;
unsigned int dma_buf_sz;
unsigned int rx_copybreak;
u32 rx_riwt;
int hwts_rx_en;
dma_addr_t *rx_skbuff_dma;
Expand Down
39 changes: 39 additions & 0 deletions drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,43 @@ static int stmmac_get_ts_info(struct net_device *dev,
return ethtool_op_get_ts_info(dev, info);
}

static int stmmac_get_tunable(struct net_device *dev,
const struct ethtool_tunable *tuna, void *data)
{
struct stmmac_priv *priv = netdev_priv(dev);
int ret = 0;

switch (tuna->id) {
case ETHTOOL_RX_COPYBREAK:
*(u32 *)data = priv->rx_copybreak;
break;
default:
ret = -EINVAL;
break;
}

return ret;
}

static int stmmac_set_tunable(struct net_device *dev,
const struct ethtool_tunable *tuna,
const void *data)
{
struct stmmac_priv *priv = netdev_priv(dev);
int ret = 0;

switch (tuna->id) {
case ETHTOOL_RX_COPYBREAK:
priv->rx_copybreak = *(u32 *)data;
break;
default:
ret = -EINVAL;
break;
}

return ret;
}

static const struct ethtool_ops stmmac_ethtool_ops = {
.begin = stmmac_check_if_running,
.get_drvinfo = stmmac_ethtool_getdrvinfo,
Expand All @@ -803,6 +840,8 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
.get_ts_info = stmmac_get_ts_info,
.get_coalesce = stmmac_get_coalesce,
.set_coalesce = stmmac_set_coalesce,
.get_tunable = stmmac_get_tunable,
.set_tunable = stmmac_set_tunable,
};

void stmmac_set_ethtool_ops(struct net_device *netdev)
Expand Down
61 changes: 46 additions & 15 deletions drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ static int buf_sz = DEFAULT_BUFSIZE;
module_param(buf_sz, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(buf_sz, "DMA buffer size");

#define STMMAC_RX_COPYBREAK 256

static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_IFUP |
NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
Expand Down Expand Up @@ -1808,6 +1810,7 @@ static int stmmac_open(struct net_device *dev)
priv->xstats.threshold = tc;

priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
priv->rx_copybreak = STMMAC_RX_COPYBREAK;

ret = alloc_dma_desc_resources(priv);
if (ret < 0) {
Expand Down Expand Up @@ -2159,8 +2162,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
struct sk_buff *skb;

skb = netdev_alloc_skb_ip_align(priv->dev, bfsize);

if (unlikely(skb == NULL))
if (unlikely(!skb))
break;

priv->rx_skbuff[entry] = skb;
Expand Down Expand Up @@ -2282,23 +2284,52 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
pr_debug("\tframe size %d, COE: %d\n",
frame_len, status);
}
skb = priv->rx_skbuff[entry];
if (unlikely(!skb)) {
pr_err("%s: Inconsistent Rx descriptor chain\n",
priv->dev->name);
priv->dev->stats.rx_dropped++;
break;

if (unlikely(frame_len < priv->rx_copybreak)) {
skb = netdev_alloc_skb_ip_align(priv->dev,
frame_len);
if (unlikely(!skb)) {
if (net_ratelimit())
dev_warn(priv->device,
"packet dropped\n");
priv->dev->stats.rx_dropped++;
break;
}

dma_sync_single_for_cpu(priv->device,
priv->rx_skbuff_dma
[entry], frame_len,
DMA_FROM_DEVICE);
skb_copy_to_linear_data(skb,
priv->
rx_skbuff[entry]->data,
frame_len);

skb_put(skb, frame_len);
dma_sync_single_for_device(priv->device,
priv->rx_skbuff_dma
[entry], frame_len,
DMA_FROM_DEVICE);
} else {
skb = priv->rx_skbuff[entry];
if (unlikely(!skb)) {
pr_err("%s: Inconsistent Rx chain\n",
priv->dev->name);
priv->dev->stats.rx_dropped++;
break;
}
prefetch(skb->data - NET_IP_ALIGN);
priv->rx_skbuff[entry] = NULL;

skb_put(skb, frame_len);
dma_unmap_single(priv->device,
priv->rx_skbuff_dma[entry],
priv->dma_buf_sz,
DMA_FROM_DEVICE);
}
prefetch(skb->data - NET_IP_ALIGN);
priv->rx_skbuff[entry] = NULL;

stmmac_get_rx_hwtstamp(priv, entry, skb);

skb_put(skb, frame_len);
dma_unmap_single(priv->device,
priv->rx_skbuff_dma[entry],
priv->dma_buf_sz, DMA_FROM_DEVICE);

if (netif_msg_pktdata(priv)) {
pr_debug("frame received (%dbytes)", frame_len);
print_pkt(skb->data, frame_len);
Expand Down

0 comments on commit 22ad383

Please sign in to comment.