Browse Source

rmnet_core: segment ULSO skbs on LL channel

ULSO is not supported on the LL endpoint. If such skbs are received by the
rmnet driver, they must be segmented in software before transmitting them.

Change-Id: I0103d06c6bfa8eb96cfbde85f68b1b45034a93e5
Signed-off-by: Sean Tranchetti <[email protected]>
Sean Tranchetti 4 năm trước cách đây
mục cha
commit
42e9497010
2 tập tin đã thay đổi với 26 bổ sung1 xóa
  1. 2 0
      core/rmnet_config.h
  2. 24 1
      core/rmnet_vnd.c

+ 2 - 0
core/rmnet_config.h

@@ -188,6 +188,8 @@ struct rmnet_priv_stats {
 	u64 ul_prio;
 	u64 tso_pkts;
 	u64 tso_arriv_errs;
+	u64 ll_tso_segs;
+	u64 ll_tso_errs;
 };
 
 struct rmnet_priv {

+ 24 - 1
core/rmnet_vnd.c

@@ -89,7 +89,30 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,
 			rmnet_perf_tether_egress(skb);
 		}
 		low_latency = qmi_rmnet_flow_is_low_latency(dev, skb);
-		rmnet_egress_handler(skb, low_latency);
+		if (low_latency && skb_is_gso(skb)) {
+			netdev_features_t features;
+			struct sk_buff *segs, *tmp;
+
+			features = dev->features & ~NETIF_F_GSO_MASK;
+			segs = skb_gso_segment(skb, features);
+			if (IS_ERR_OR_NULL(segs)) {
+				this_cpu_add(priv->pcpu_stats->stats.tx_drops,
+					     skb_shinfo(skb)->gso_segs);
+				priv->stats.ll_tso_errs++;
+				kfree_skb(skb);
+				return NETDEV_TX_OK;
+			}
+
+			consume_skb(skb);
+			for (skb = segs; skb; skb = tmp) {
+				tmp = skb->next;
+				skb->dev = dev;
+				priv->stats.ll_tso_segs++;
+				rmnet_egress_handler(skb, low_latency);
+			}
+		} else {
+			rmnet_egress_handler(skb, low_latency);
+		}
 		qmi_rmnet_burst_fc_check(dev, ip_type, mark, len);
 		qmi_rmnet_work_maybe_restart(rmnet_get_rmnet_port(dev));
 	} else {