diff options
-rw-r--r-- | drivers/net/ethernet/freescale/fec.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 44 |
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); |