Commit f7b4e71c authored by David S. Miller's avatar David S. Miller

Merge branch 'mvneta'

Ezequiel Garcia says:

====================
ethernet: marvell: After-TSO fixes

This patchset consists of different fixes and improvements in the mvneta
and mv643xx_eth drivers. The most important change is the one that allows
to support small MSS values (see patches 2 and 6).

This is done following the Solarflare driver (see commit 7e6d06f0).

While doing this some other fixes were spotted and so they are included.

Finally, notice that the TSO support introduced a wrong DMA unmapping
of the TSO header buffers, so patches 4 and 8 provide a couple patches to
fix that in the drivers.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 688cea83 b926260c
......@@ -185,6 +185,13 @@ static char mv643xx_eth_driver_version[] = "1.4";
#define TSO_HEADER_SIZE 128
/* Max number of allowed TCP segments for software TSO */
#define MV643XX_MAX_TSO_SEGS 100
#define MV643XX_MAX_SKB_DESCS (MV643XX_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS)
#define IS_TSO_HEADER(txq, addr) \
((addr >= txq->tso_hdrs_dma) && \
(addr < txq->tso_hdrs_dma + txq->tx_ring_size * TSO_HEADER_SIZE))
/*
* RX/TX descriptors.
*/
......@@ -348,6 +355,9 @@ struct tx_queue {
int tx_curr_desc;
int tx_used_desc;
int tx_stop_threshold;
int tx_wake_threshold;
char *tso_hdrs;
dma_addr_t tso_hdrs_dma;
......@@ -497,7 +507,7 @@ static void txq_maybe_wake(struct tx_queue *txq)
if (netif_tx_queue_stopped(nq)) {
__netif_tx_lock(nq, smp_processor_id());
if (txq->tx_ring_size - txq->tx_desc_count >= MAX_SKB_FRAGS + 1)
if (txq->tx_desc_count <= txq->tx_wake_threshold)
netif_tx_wake_queue(nq);
__netif_tx_unlock(nq);
}
......@@ -897,7 +907,8 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb)
}
}
static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb)
static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb,
struct net_device *dev)
{
struct mv643xx_eth_private *mp = txq_to_mp(txq);
int nr_frags = skb_shinfo(skb)->nr_frags;
......@@ -910,11 +921,15 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb)
cmd_sts = 0;
l4i_chk = 0;
if (txq->tx_ring_size - txq->tx_desc_count < MAX_SKB_FRAGS + 1) {
if (net_ratelimit())
netdev_err(dev, "tx queue full?!\n");
return -EBUSY;
}
ret = skb_tx_csum(mp, skb, &l4i_chk, &cmd_sts, skb->len);
if (ret) {
dev_kfree_skb_any(skb);
if (ret)
return ret;
}
cmd_sts |= TX_FIRST_DESC | GEN_CRC | BUFFER_OWNED_BY_DMA;
tx_index = txq->tx_curr_desc++;
......@@ -967,36 +982,26 @@ static netdev_tx_t mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev)
nq = netdev_get_tx_queue(dev, queue);
if (has_tiny_unaligned_frags(skb) && __skb_linearize(skb)) {
txq->tx_dropped++;
netdev_printk(KERN_DEBUG, dev,
"failed to linearize skb with tiny unaligned fragment\n");
return NETDEV_TX_BUSY;
}
if (txq->tx_ring_size - txq->tx_desc_count < MAX_SKB_FRAGS + 1) {
if (net_ratelimit())
netdev_err(dev, "tx queue full?!\n");
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
length = skb->len;
if (skb_is_gso(skb))
ret = txq_submit_tso(txq, skb, dev);
else
ret = txq_submit_skb(txq, skb);
ret = txq_submit_skb(txq, skb, dev);
if (!ret) {
int entries_left;
txq->tx_bytes += length;
txq->tx_packets++;
entries_left = txq->tx_ring_size - txq->tx_desc_count;
if (entries_left < MAX_SKB_FRAGS + 1)
if (txq->tx_desc_count >= txq->tx_stop_threshold)
netif_tx_stop_queue(nq);
} else if (ret == -EBUSY) {
return NETDEV_TX_BUSY;
} else {
txq->tx_dropped++;
dev_kfree_skb_any(skb);
}
return NETDEV_TX_OK;
......@@ -1070,8 +1075,9 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
mp->dev->stats.tx_errors++;
}
dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr,
desc->byte_cnt, DMA_TO_DEVICE);
if (!IS_TSO_HEADER(txq, desc->buf_ptr))
dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr,
desc->byte_cnt, DMA_TO_DEVICE);
dev_kfree_skb(skb);
}
......@@ -1614,7 +1620,11 @@ mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er)
return -EINVAL;
mp->rx_ring_size = er->rx_pending < 4096 ? er->rx_pending : 4096;
mp->tx_ring_size = er->tx_pending < 4096 ? er->tx_pending : 4096;
mp->tx_ring_size = clamp_t(unsigned int, er->tx_pending,
MV643XX_MAX_SKB_DESCS * 2, 4096);
if (mp->tx_ring_size != er->tx_pending)
netdev_warn(dev, "TX queue size set to %u (requested %u)\n",
mp->tx_ring_size, er->tx_pending);
if (netif_running(dev)) {
mv643xx_eth_stop(dev);
......@@ -1990,6 +2000,13 @@ static int txq_init(struct mv643xx_eth_private *mp, int index)
txq->tx_ring_size = mp->tx_ring_size;
/* A queue must always have room for at least one skb.
* Therefore, stop the queue when the free entries reaches
* the maximum number of descriptors per skb.
*/
txq->tx_stop_threshold = txq->tx_ring_size - MV643XX_MAX_SKB_DESCS;
txq->tx_wake_threshold = txq->tx_stop_threshold / 2;
txq->tx_desc_count = 0;
txq->tx_curr_desc = 0;
txq->tx_used_desc = 0;
......@@ -2849,6 +2866,7 @@ static void set_params(struct mv643xx_eth_private *mp,
struct mv643xx_eth_platform_data *pd)
{
struct net_device *dev = mp->dev;
unsigned int tx_ring_size;
if (is_valid_ether_addr(pd->mac_addr))
memcpy(dev->dev_addr, pd->mac_addr, ETH_ALEN);
......@@ -2863,9 +2881,16 @@ static void set_params(struct mv643xx_eth_private *mp,
mp->rxq_count = pd->rx_queue_count ? : 1;
mp->tx_ring_size = DEFAULT_TX_QUEUE_SIZE;
tx_ring_size = DEFAULT_TX_QUEUE_SIZE;
if (pd->tx_queue_size)
mp->tx_ring_size = pd->tx_queue_size;
tx_ring_size = pd->tx_queue_size;
mp->tx_ring_size = clamp_t(unsigned int, tx_ring_size,
MV643XX_MAX_SKB_DESCS * 2, 4096);
if (mp->tx_ring_size != tx_ring_size)
netdev_warn(dev, "TX queue size set to %u (requested %u)\n",
mp->tx_ring_size, tx_ring_size);
mp->tx_desc_sram_addr = pd->tx_sram_addr;
mp->tx_desc_sram_size = pd->tx_sram_size;
......@@ -3092,6 +3117,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
dev->hw_features = dev->features;
dev->priv_flags |= IFF_UNICAST_FLT;
dev->gso_max_segs = MV643XX_MAX_TSO_SEGS;
SET_NETDEV_DEV(dev, &pdev->dev);
......
......@@ -219,9 +219,6 @@
#define MVNETA_RX_COAL_PKTS 32
#define MVNETA_RX_COAL_USEC 100
/* Napi polling weight */
#define MVNETA_RX_POLL_WEIGHT 64
/* The two bytes Marvell header. Either contains a special value used
* by Marvell switches when a specific hardware mode is enabled (not
* supported by this driver) or is filled automatically by zeroes on
......@@ -254,6 +251,11 @@
/* Max number of Tx descriptors */
#define MVNETA_MAX_TXD 532
/* Max number of allowed TCP segments for software TSO */
#define MVNETA_MAX_TSO_SEGS 100
#define MVNETA_MAX_SKB_DESCS (MVNETA_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS)
/* descriptor aligned size */
#define MVNETA_DESC_ALIGNED_SIZE 32
......@@ -262,6 +264,10 @@
ETH_HLEN + ETH_FCS_LEN, \
MVNETA_CPU_D_CACHE_LINE_SIZE)
#define IS_TSO_HEADER(txq, addr) \
((addr >= txq->tso_hdrs_phys) && \
(addr < txq->tso_hdrs_phys + txq->size * TSO_HEADER_SIZE))
#define MVNETA_RX_BUF_SIZE(pkt_size) ((pkt_size) + NET_SKB_PAD)
struct mvneta_pcpu_stats {
......@@ -391,6 +397,8 @@ struct mvneta_tx_queue {
* descriptor ring
*/
int count;
int tx_stop_threshold;
int tx_wake_threshold;
/* Array of transmitted skb */
struct sk_buff **tx_skb;
......@@ -1287,11 +1295,12 @@ static void mvneta_txq_bufs_free(struct mvneta_port *pp,
mvneta_txq_inc_get(txq);
if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr))
dma_unmap_single(pp->dev->dev.parent,
tx_desc->buf_phys_addr,
tx_desc->data_size, DMA_TO_DEVICE);
if (!skb)
continue;
dma_unmap_single(pp->dev->dev.parent, tx_desc->buf_phys_addr,
tx_desc->data_size, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
}
}
......@@ -1312,7 +1321,7 @@ static void mvneta_txq_done(struct mvneta_port *pp,
txq->count -= tx_done;
if (netif_tx_queue_stopped(nq)) {
if (txq->size - txq->count >= MAX_SKB_FRAGS + 1)
if (txq->count <= txq->tx_wake_threshold)
netif_tx_wake_queue(nq);
}
}
......@@ -1639,7 +1648,7 @@ static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev,
*/
for (i = desc_count - 1; i >= 0; i--) {
struct mvneta_tx_desc *tx_desc = txq->descs + i;
if (!(tx_desc->command & MVNETA_TXD_F_DESC))
if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr))
dma_unmap_single(pp->dev->dev.parent,
tx_desc->buf_phys_addr,
tx_desc->data_size,
......@@ -1772,7 +1781,7 @@ static int mvneta_tx(struct sk_buff *skb, struct net_device *dev)
txq->count += frags;
mvneta_txq_pend_desc_add(pp, txq, frags);
if (txq->size - txq->count < MAX_SKB_FRAGS + 1)
if (txq->count >= txq->tx_stop_threshold)
netif_tx_stop_queue(nq);
u64_stats_update_begin(&stats->syncp);
......@@ -2211,6 +2220,14 @@ static int mvneta_txq_init(struct mvneta_port *pp,
{
txq->size = pp->tx_ring_size;
/* A queue must always have room for at least one skb.
* Therefore, stop the queue when the free entries reaches
* the maximum number of descriptors per skb.
*/
txq->tx_stop_threshold = txq->size - MVNETA_MAX_SKB_DESCS;
txq->tx_wake_threshold = txq->tx_stop_threshold / 2;
/* Allocate memory for TX descriptors */
txq->descs = dma_alloc_coherent(pp->dev->dev.parent,
txq->size * MVNETA_DESC_ALIGNED_SIZE,
......@@ -2745,8 +2762,12 @@ static int mvneta_ethtool_set_ringparam(struct net_device *dev,
return -EINVAL;
pp->rx_ring_size = ring->rx_pending < MVNETA_MAX_RXD ?
ring->rx_pending : MVNETA_MAX_RXD;
pp->tx_ring_size = ring->tx_pending < MVNETA_MAX_TXD ?
ring->tx_pending : MVNETA_MAX_TXD;
pp->tx_ring_size = clamp_t(u16, ring->tx_pending,
MVNETA_MAX_SKB_DESCS * 2, MVNETA_MAX_TXD);
if (pp->tx_ring_size != ring->tx_pending)
netdev_warn(dev, "TX queue size set to %u (requested %u)\n",
pp->tx_ring_size, ring->tx_pending);
if (netif_running(dev)) {
mvneta_stop(dev);
......@@ -3025,12 +3046,13 @@ static int mvneta_probe(struct platform_device *pdev)
if (dram_target_info)
mvneta_conf_mbus_windows(pp, dram_target_info);
netif_napi_add(dev, &pp->napi, mvneta_poll, MVNETA_RX_POLL_WEIGHT);
netif_napi_add(dev, &pp->napi, mvneta_poll, NAPI_POLL_WEIGHT);
dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
dev->hw_features |= dev->features;
dev->vlan_features |= dev->features;
dev->priv_flags |= IFF_UNICAST_FLT;
dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
err = register_netdev(dev);
if (err < 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment