Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-stmmac-tso-fixes-cleanups'

Russell King says:

====================
net: stmmac: TSO fixes/cleanups

This is a more refined version of the previous patch series fixing
and cleaning up the TSO code.

I'm not sure whether "TSO" or "GSO" should be used to describe this
feature - although it primarily handles TCP, dwmac4 appears to also
be able to handle UDP.

In essence, this series adds a .ndo_features_check() method to handle
whether TSO/GSO can be used for a particular skbuff - checking which
queue the skbuff is destined for and whether that has TBS available
which precludes TSO being enabled on that channel.

I'm also adding a check that the header is smaller than 1024 bytes,
as documented in those sources which have TSO support - this is due
to the hardware buffering the header in "TSO memory" which I guess
is limited to 1KiB. I expect this test never to trigger, but if
the headers ever exceed that size, the hardware will likely fail.
While IPv4 headers are unlikely to be anywhere near this, there is
nothing in the protocol which prevents IPv6 headers up to 64KiB.

As we now have a .ndo_features_check() method, I'm moving the VLAN
insertion for TSO packets into core code by unpublishing the VLAN
insertion features when we use TSO. Another move is for checksumming,
which is required for TSO, but stmmac's requirements for offloading
checksums are more strict - and this seems to be a bug in the TSO
path.

I've changed the hardware initialisation to always enable TSO support
on the channels even if the user requests TSO/GSO to be disabled -
this fixes another issue as pointed out by Jakub in a previous review.

I'm moving the setup of the GSO features, cleaning those up, and
adding a warning if platform glue requests this to be enabled but the
hardware has no support. Hopefully this will never trigger if everyone
got the STMMAC_FLAG_TSO_EN flag correct. Also adding a check for TxPBL
value.

Finally, moving the "TSO supported" message to the new
stmmac_set_gso_features() function so keep all this TSO stuff together.
====================

Link: https://patch.msgid.link/aczHVF04LIGq_lYO@shell.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+150 -67
+2 -1
drivers/net/ethernet/stmicro/stmmac/stmmac.h
··· 265 265 u32 rx_coal_frames[MTL_MAX_RX_QUEUES]; 266 266 267 267 int hwts_tx_en; 268 + /* skb_shinfo(skb)->gso_type types that we handle */ 269 + unsigned int gso_enabled_types; 268 270 bool tx_path_in_lpi_mode; 269 - bool tso; 270 271 bool sph_active; 271 272 bool sph_capable; 272 273 u32 sarc_type;
+148 -66
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
··· 3619 3619 } 3620 3620 } 3621 3621 3622 + /* STM32MP25xx (dwmac v5.3) states "Do not enable time-based scheduling for 3623 + * channels on which the TSO feature is enabled." If we have a skb for a 3624 + * channel which has TBS enabled, fall back to software GSO. 3625 + */ 3626 + static bool stmmac_tso_channel_permitted(struct stmmac_priv *priv, 3627 + unsigned int chan) 3628 + { 3629 + /* TSO and TBS cannot co-exist */ 3630 + return !(priv->dma_conf.tx_queue[chan].tbs & STMMAC_TBS_AVAIL); 3631 + } 3632 + 3622 3633 /** 3623 3634 * stmmac_hw_setup - setup mac in a usable state. 3624 3635 * @dev : pointer to the device structure. ··· 3716 3705 stmmac_set_rings_length(priv); 3717 3706 3718 3707 /* Enable TSO */ 3719 - if (priv->tso) { 3708 + if (priv->dma_cap.tsoen && priv->plat->flags & STMMAC_FLAG_TSO_EN) { 3720 3709 for (chan = 0; chan < tx_cnt; chan++) { 3721 - struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; 3722 - 3723 - /* TSO and TBS cannot co-exist */ 3724 - if (tx_q->tbs & STMMAC_TBS_AVAIL) 3710 + if (!stmmac_tso_channel_permitted(priv, chan)) 3725 3711 continue; 3726 3712 3727 3713 stmmac_enable_tso(priv, priv->ioaddr, 1, chan); ··· 4373 4365 stmmac_set_queue_tx_tail_ptr(priv, tx_q, queue, tx_q->cur_tx); 4374 4366 } 4375 4367 4368 + static void stmmac_set_gso_types(struct stmmac_priv *priv, bool tso) 4369 + { 4370 + if (!tso) { 4371 + priv->gso_enabled_types = 0; 4372 + } else { 4373 + /* Manage oversized TCP frames for GMAC4 device */ 4374 + priv->gso_enabled_types = SKB_GSO_TCPV4 | SKB_GSO_TCPV6; 4375 + if (priv->plat->core_type == DWMAC_CORE_GMAC4) 4376 + priv->gso_enabled_types |= SKB_GSO_UDP_L4; 4377 + } 4378 + } 4379 + 4380 + static void stmmac_set_gso_features(struct net_device *ndev) 4381 + { 4382 + struct stmmac_priv *priv = netdev_priv(ndev); 4383 + const struct stmmac_dma_cfg *dma_cfg; 4384 + int txpbl; 4385 + 4386 + if (priv->dma_cap.tsoen) 4387 + dev_info(priv->device, "TSO supported\n"); 4388 + 4389 + if (!(priv->plat->flags & STMMAC_FLAG_TSO_EN)) 4390 + return; 4391 + 4392 + if (!priv->dma_cap.tsoen) { 4393 + dev_warn(priv->device, "platform requests unsupported TSO\n"); 4394 + return; 4395 + } 4396 + 4397 + /* FIXME: 4398 + * STM32MP151 (v4.2 userver v4.0) states that TxPBL must be >= 4. It 4399 + * is not clear whether PBLx8 (which multiplies the PBL value by 8) 4400 + * influences this. 4401 + */ 4402 + dma_cfg = priv->plat->dma_cfg; 4403 + txpbl = dma_cfg->txpbl ?: dma_cfg->pbl; 4404 + if (txpbl < 4) { 4405 + dev_warn(priv->device, "txpbl(%d) is too low for TSO\n", txpbl); 4406 + return; 4407 + } 4408 + 4409 + ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; 4410 + if (priv->plat->core_type == DWMAC_CORE_GMAC4) 4411 + ndev->hw_features |= NETIF_F_GSO_UDP_L4; 4412 + 4413 + stmmac_set_gso_types(priv, true); 4414 + 4415 + dev_info(priv->device, "TSO feature enabled\n"); 4416 + } 4417 + 4418 + static size_t stmmac_tso_header_size(struct sk_buff *skb) 4419 + { 4420 + size_t size; 4421 + 4422 + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 4423 + size = skb_transport_offset(skb) + sizeof(struct udphdr); 4424 + else 4425 + size = skb_tcp_all_headers(skb); 4426 + 4427 + return size; 4428 + } 4429 + 4430 + /* STM32MP151 (dwmac v4.2) and STM32MP25xx (dwmac v5.3) states for TDES2 normal 4431 + * (read format) descriptor that the maximum header length supported for the 4432 + * TSO feature is 1023 bytes. 4433 + * 4434 + * While IPv4 is limited to MAC+VLAN+IPv4+ext+TCP+ext = 138 bytes, the IPv6 4435 + * extension headers aren't similarly limited. 4436 + * 4437 + * Fall back to software GSO for these skbs. Also check that the MSS is >= 4438 + * the recommended 64 bytes (documented in ETH_DMACxCR register description), 4439 + * and that a the header plus MSS is not larger than 16383 (documented in 4440 + * "Building the Descriptor and the packet for the TSO feature"). 4441 + */ 4442 + static bool stmmac_tso_valid_packet(struct sk_buff *skb) 4443 + { 4444 + size_t header_len = stmmac_tso_header_size(skb); 4445 + unsigned int gso_size = skb_shinfo(skb)->gso_size; 4446 + 4447 + return header_len <= 1023 && gso_size >= 64 && 4448 + header_len + gso_size < 16383; 4449 + } 4450 + 4376 4451 /** 4377 4452 * stmmac_tso_xmit - Tx entry point of the driver for oversized frames (TSO) 4378 4453 * @skb : the socket buffer ··· 4506 4415 u8 proto_hdr_len, hdr; 4507 4416 dma_addr_t des; 4508 4417 4509 - /* Always insert VLAN tag to SKB payload for TSO frames. 4510 - * 4511 - * Never insert VLAN tag by HW, since segments split by 4512 - * TSO engine will be un-tagged by mistake. 4513 - */ 4514 - if (skb_vlan_tag_present(skb)) { 4515 - skb = __vlan_hwaccel_push_inside(skb); 4516 - if (unlikely(!skb)) { 4517 - priv->xstats.tx_dropped++; 4518 - return NETDEV_TX_OK; 4519 - } 4520 - } 4521 - 4522 4418 nfrags = skb_shinfo(skb)->nr_frags; 4523 4419 queue = skb_get_queue_mapping(skb); 4524 4420 ··· 4514 4436 first_tx = tx_q->cur_tx; 4515 4437 4516 4438 /* Compute header lengths */ 4517 - if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { 4518 - proto_hdr_len = skb_transport_offset(skb) + sizeof(struct udphdr); 4439 + proto_hdr_len = stmmac_tso_header_size(skb); 4440 + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 4519 4441 hdr = sizeof(struct udphdr); 4520 - } else { 4521 - proto_hdr_len = skb_tcp_all_headers(skb); 4442 + else 4522 4443 hdr = tcp_hdrlen(skb); 4523 - } 4524 4444 4525 4445 /* Desc availability based on threshold should be enough safe */ 4526 4446 if (unlikely(stmmac_tx_avail(priv, queue) < ··· 4756 4680 u32 queue = skb_get_queue_mapping(skb); 4757 4681 int nfrags = skb_shinfo(skb)->nr_frags; 4758 4682 unsigned int first_entry, tx_packets; 4759 - int gso = skb_shinfo(skb)->gso_type; 4760 4683 struct stmmac_txq_stats *txq_stats; 4761 4684 struct dma_desc *desc, *first_desc; 4762 4685 struct stmmac_tx_queue *tx_q; ··· 4767 4692 if (priv->tx_path_in_lpi_mode && priv->eee_sw_timer_en) 4768 4693 stmmac_stop_sw_lpi(priv); 4769 4694 4770 - /* Manage oversized TCP frames for GMAC4 device */ 4771 - if (skb_is_gso(skb) && priv->tso) { 4772 - if (gso & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) 4773 - return stmmac_tso_xmit(skb, dev); 4774 - if (priv->plat->core_type == DWMAC_CORE_GMAC4 && 4775 - (gso & SKB_GSO_UDP_L4)) 4776 - return stmmac_tso_xmit(skb, dev); 4777 - } 4695 + if (skb_is_gso(skb) && 4696 + skb_shinfo(skb)->gso_type & priv->gso_enabled_types) 4697 + return stmmac_tso_xmit(skb, dev); 4778 4698 4779 4699 if (priv->est && priv->est->enable && 4780 4700 priv->est->max_sdu[queue]) { ··· 4801 4731 /* Check if VLAN can be inserted by HW */ 4802 4732 has_vlan = stmmac_vlan_insert(priv, skb, tx_q); 4803 4733 4804 - csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); 4805 - /* DWMAC IPs can be synthesized to support tx coe only for a few tx 4806 - * queues. In that case, checksum offloading for those queues that don't 4807 - * support tx coe needs to fallback to software checksum calculation. 4808 - * 4809 - * Packets that won't trigger the COE e.g. most DSA-tagged packets will 4810 - * also have to be checksummed in software. 4811 - */ 4812 - if (csum_insertion && 4813 - (priv->plat->tx_queues_cfg[queue].coe_unsupported || 4814 - !stmmac_has_ip_ethertype(skb))) { 4815 - if (unlikely(skb_checksum_help(skb))) 4816 - goto dma_map_err; 4817 - csum_insertion = !csum_insertion; 4818 - } 4819 - 4820 4734 entry = tx_q->cur_tx; 4821 4735 first_entry = entry; 4822 4736 WARN_ON(tx_q->tx_skbuff[first_entry]); ··· 4815 4761 /* To program the descriptors according to the size of the frame */ 4816 4762 if (enh_desc) 4817 4763 is_jumbo = stmmac_is_jumbo_frm(priv, skb->len, enh_desc); 4764 + 4765 + csum_insertion = skb->ip_summed == CHECKSUM_PARTIAL; 4818 4766 4819 4767 if (unlikely(is_jumbo)) { 4820 4768 entry = stmmac_jumbo_frm(priv, tx_q, skb, csum_insertion); ··· 4973 4917 dev_kfree_skb(skb); 4974 4918 priv->xstats.tx_dropped++; 4975 4919 return NETDEV_TX_OK; 4920 + } 4921 + 4922 + static netdev_features_t stmmac_features_check(struct sk_buff *skb, 4923 + struct net_device *dev, 4924 + netdev_features_t features) 4925 + { 4926 + struct stmmac_priv *priv = netdev_priv(dev); 4927 + u16 queue = skb_get_queue_mapping(skb); 4928 + 4929 + /* DWMAC IPs can be synthesized to support tx coe only for a few tx 4930 + * queues. In that case, checksum offloading for those queues that don't 4931 + * support tx coe needs to fallback to software checksum calculation. 4932 + * 4933 + * Packets that won't trigger the COE e.g. most DSA-tagged packets will 4934 + * also have to be checksummed in software. 4935 + * 4936 + * Note that disabling hardware checksumming also disables TSO. See 4937 + * harmonize_features() in net/core/dev.c 4938 + */ 4939 + if (priv->plat->tx_queues_cfg[queue].coe_unsupported || 4940 + !stmmac_has_ip_ethertype(skb)) 4941 + features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); 4942 + 4943 + if (skb_is_gso(skb)) { 4944 + if (!stmmac_tso_channel_permitted(priv, queue) || 4945 + !stmmac_tso_valid_packet(skb)) 4946 + features &= ~NETIF_F_GSO_MASK; 4947 + 4948 + /* If we are going to be using hardware TSO, always insert 4949 + * VLAN tag to SKB payload for TSO frames. 4950 + * 4951 + * Never insert VLAN tag by HW, since segments split by 4952 + * TSO engine will be un-tagged by mistake. 4953 + */ 4954 + if (features & NETIF_F_GSO_MASK) 4955 + features &= ~(NETIF_F_HW_VLAN_STAG_TX | 4956 + NETIF_F_HW_VLAN_CTAG_TX); 4957 + } 4958 + 4959 + return vlan_features_check(skb, features); 4976 4960 } 4977 4961 4978 4962 static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb) ··· 6169 6073 if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN)) 6170 6074 features &= ~NETIF_F_CSUM_MASK; 6171 6075 6172 - /* Disable tso if asked by ethtool */ 6173 - if ((priv->plat->flags & STMMAC_FLAG_TSO_EN) && (priv->dma_cap.tsoen)) { 6174 - if (features & NETIF_F_TSO) 6175 - priv->tso = true; 6176 - else 6177 - priv->tso = false; 6178 - } 6179 - 6180 6076 return features; 6181 6077 } 6182 6078 ··· 6194 6106 for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++) 6195 6107 stmmac_enable_sph(priv, priv->ioaddr, sph_en, chan); 6196 6108 } 6109 + 6110 + stmmac_set_gso_types(priv, features & NETIF_F_TSO); 6197 6111 6198 6112 if (features & NETIF_F_HW_VLAN_CTAG_RX) 6199 6113 priv->hw->hw_vlan_en = true; ··· 7304 7214 static const struct net_device_ops stmmac_netdev_ops = { 7305 7215 .ndo_open = stmmac_open, 7306 7216 .ndo_start_xmit = stmmac_xmit, 7217 + .ndo_features_check = stmmac_features_check, 7307 7218 .ndo_stop = stmmac_release, 7308 7219 .ndo_change_mtu = stmmac_change_mtu, 7309 7220 .ndo_fix_features = stmmac_fix_features, ··· 7465 7374 device_set_wakeup_capable(priv->device, 1); 7466 7375 devm_pm_set_wake_irq(priv->device, priv->wol_irq); 7467 7376 } 7468 - 7469 - if (priv->dma_cap.tsoen) 7470 - dev_info(priv->device, "TSO supported\n"); 7471 7377 7472 7378 if (priv->dma_cap.number_rx_queues && 7473 7379 priv->plat->rx_queues_to_use > priv->dma_cap.number_rx_queues) { ··· 7917 7829 ndev->hw_features |= NETIF_F_HW_TC; 7918 7830 } 7919 7831 7920 - if ((priv->plat->flags & STMMAC_FLAG_TSO_EN) && (priv->dma_cap.tsoen)) { 7921 - ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; 7922 - if (priv->plat->core_type == DWMAC_CORE_GMAC4) 7923 - ndev->hw_features |= NETIF_F_GSO_UDP_L4; 7924 - priv->tso = true; 7925 - dev_info(priv->device, "TSO feature enabled\n"); 7926 - } 7832 + stmmac_set_gso_features(ndev); 7927 7833 7928 7834 if (priv->dma_cap.sphen && 7929 7835 !(priv->plat->flags & STMMAC_FLAG_SPH_DISABLE)) {