}
}
+/* STM32MP25xx (dwmac v5.3) states "Do not enable time-based scheduling for
+ * channels on which the TSO feature is enabled." If we have a skb for a
+ * channel which has TBS enabled, fall back to software GSO.
+ */
+static bool stmmac_tso_channel_permitted(struct stmmac_priv *priv,
+ unsigned int chan)
+{
+ /* TSO and TBS cannot co-exist */
+ return !(priv->dma_conf.tx_queue[chan].tbs & STMMAC_TBS_AVAIL);
+}
+
/**
* stmmac_hw_setup - setup mac in a usable state.
* @dev : pointer to the device structure.
/* Enable TSO */
if (priv->dma_cap.tsoen && priv->plat->flags & STMMAC_FLAG_TSO_EN) {
for (chan = 0; chan < tx_cnt; chan++) {
- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
-
- /* TSO and TBS cannot co-exist */
- if (tx_q->tbs & STMMAC_TBS_AVAIL)
+ if (!stmmac_tso_channel_permitted(priv, chan))
continue;
stmmac_enable_tso(priv, priv->ioaddr, 1, chan);
return NETDEV_TX_OK;
}
+static netdev_features_t stmmac_features_check(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
+{
+ u16 queue;
+
+ if (skb_is_gso(skb)) {
+ queue = skb_get_queue_mapping(skb);
+ if (!stmmac_tso_channel_permitted(netdev_priv(dev), queue))
+ features &= ~NETIF_F_GSO_MASK;
+ }
+
+ return vlan_features_check(skb, features);
+}
+
static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
{
struct vlan_ethhdr *veth = skb_vlan_eth_hdr(skb);
static const struct net_device_ops stmmac_netdev_ops = {
.ndo_open = stmmac_open,
.ndo_start_xmit = stmmac_xmit,
+ .ndo_features_check = stmmac_features_check,
.ndo_stop = stmmac_release,
.ndo_change_mtu = stmmac_change_mtu,
.ndo_fix_features = stmmac_fix_features,