summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-06-18 22:56:30 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-10-17 14:35:18 +0100
commit55993c83effcef1d4d3ebcee4ee01151547699b0 (patch)
tree02115901b24df1f458d5376785c57f0633084831
parent12d03c5f1759e2298e3017d701a668fff7da7757 (diff)
net: fec: adjust ring threshold according to SG setting
When SG is enabled, we must ensure that there are up to 1+MAX_SKB_FRAGS free entries in the ring. When SG is disabled, this can be reduced to one, and we can allow smaller rings. Adjust this setting according to the state of SG. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/net/ethernet/freescale/fec.h1
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c44
2 files changed, 43 insertions, 2 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 17ab4849802d..19210acabcaa 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -298,6 +298,7 @@ struct fec_enet_private {
/* The next free ring entry */
unsigned short tx_next;
unsigned short tx_dirty;
+ unsigned short tx_min;
unsigned short rx_next;
unsigned short tx_ring_size;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b0f218797630..59e1d15c4d02 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -197,6 +197,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#endif
#endif /* CONFIG_M5272 */
+/* Minimum TX ring size when using NETIF_F_SG */
+#define TX_RING_SIZE_MIN_SG (2 * (MAX_SKB_FRAGS + 1))
+
/* Interrupt events/masks. */
#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
@@ -476,7 +479,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
unsigned int index;
int ret;
- if (fec_enet_get_free_txdesc_num(fep) < MAX_SKB_FRAGS + 1) {
+ if (fec_enet_get_free_txdesc_num(fep) < fep->tx_min) {
dev_kfree_skb_any(skb);
if (net_ratelimit())
netdev_err(ndev, "NOT enough BD for SG!\n");
@@ -2471,7 +2474,22 @@ static void fec_poll_controller(struct net_device *dev)
}
#endif
-#define FEATURES_NEED_QUIESCE NETIF_F_RXCSUM
+static netdev_features_t fec_fix_features(struct net_device *ndev,
+ netdev_features_t features)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ /*
+ * NETIF_F_SG requires a minimum transmit ring size. If we
+ * have less than this size, we can't support this feature.
+ */
+ if (fep->tx_ring_size < TX_RING_SIZE_MIN_SG)
+ features &= ~NETIF_F_SG;
+
+ return features;
+}
+
+#define FEATURES_NEED_QUIESCE (NETIF_F_RXCSUM | NETIF_F_SG)
static int fec_set_features(struct net_device *netdev,
netdev_features_t features)
@@ -2496,6 +2514,17 @@ static int fec_set_features(struct net_device *netdev,
fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED;
}
+ /* Set the appropriate minimum transmit ring free threshold */
+ if (features & NETIF_F_SG) {
+ fep->tx_min = MAX_SKB_FRAGS + 1;
+ fep->tx_stop_threshold = FEC_MAX_SKB_DESCS;
+ fep->tx_wake_threshold = (fep->tx_ring_size - fep->tx_stop_threshold) / 2;
+ } else {
+ fep->tx_min = 1;
+ fep->tx_stop_threshold = 1;
+ fep->tx_wake_threshold = 1;
+ }
+
/* Resume the device after updates */
if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
fec_restart(netdev);
@@ -2520,6 +2549,7 @@ static const struct net_device_ops fec_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = fec_poll_controller,
#endif
+ .ndo_fix_features = fec_fix_features,
.ndo_set_features = fec_set_features,
};
@@ -2606,6 +2636,16 @@ static int fec_enet_init(struct net_device *ndev)
fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
}
+ if (ndev->features & NETIF_F_SG) {
+ fep->tx_min = MAX_SKB_FRAGS + 1;
+ fep->tx_stop_threshold = FEC_MAX_SKB_DESCS;
+ fep->tx_wake_threshold = (fep->tx_ring_size - fep->tx_stop_threshold) / 2;
+ } else {
+ fep->tx_min = 1;
+ fep->tx_stop_threshold = 1;
+ fep->tx_wake_threshold = 1;
+ }
+
ndev->hw_features = ndev->features;
fec_restart(ndev);