summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/freescale/fec_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c44
1 files changed, 42 insertions, 2 deletions
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);