Skip to content

Commit 1a2a14f

Browse files
chelsiocudbgJakub Kicinski
authored andcommitted
cxgb4: add UDP segmentation offload support
Implement and export UDP segmentation offload (USO) support for both NIC and MQPRIO QoS offload Tx path. Update appropriate logic in Tx to parse GSO info in skb and configure FW_ETH_TX_EO_WR request needed to perform USO. v2: - Remove inline keyword from write_eo_udp_wr() in sge.c. Let the compiler decide. Signed-off-by: Rahul Lakkireddy <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 0ed96b4 commit 1a2a14f

File tree

6 files changed

+139
-50
lines changed

6 files changed

+139
-50
lines changed

drivers/net/ethernet/chelsio/cxgb4/cxgb4.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,7 @@ struct sge_eth_txq { /* state for an SGE Ethernet Tx queue */
772772
u8 dbqt; /* SGE Doorbell Queue Timer in use */
773773
unsigned int dbqtimerix; /* SGE Doorbell Queue Timer Index */
774774
unsigned long tso; /* # of TSO requests */
775+
unsigned long uso; /* # of USO requests */
775776
unsigned long tx_cso; /* # of Tx checksum offloads */
776777
unsigned long vlan_ins; /* # of Tx VLAN insertions */
777778
unsigned long mapping_err; /* # of I/O MMU packet mapping errors */

drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,6 +2748,7 @@ do { \
27482748
RL("RxDrops:", stats.rx_drops);
27492749
RL("RxBadPkts:", stats.bad_rx_pkts);
27502750
TL("TSO:", tso);
2751+
TL("USO:", uso);
27512752
TL("TxCSO:", tx_cso);
27522753
TL("VLANins:", vlan_ins);
27532754
TL("TxQFull:", q.stops);

drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ static const char stats_strings[][ETH_GSTRING_LEN] = {
9191
"rx_bg3_frames_trunc ",
9292

9393
"tso ",
94+
"uso ",
9495
"tx_csum_offload ",
9596
"rx_csum_good ",
9697
"vlan_extractions ",
@@ -220,6 +221,7 @@ static void get_strings(struct net_device *dev, u32 stringset, u8 *data)
220221
*/
221222
struct queue_port_stats {
222223
u64 tso;
224+
u64 uso;
223225
u64 tx_csum;
224226
u64 rx_csum;
225227
u64 vlan_ex;
@@ -247,6 +249,7 @@ static void collect_sge_port_stats(const struct adapter *adap,
247249
memset(s, 0, sizeof(*s));
248250
for (i = 0; i < p->nqsets; i++, rx++, tx++) {
249251
s->tso += tx->tso;
252+
s->uso += tx->uso;
250253
s->tx_csum += tx->tx_cso;
251254
s->rx_csum += rx->stats.rx_cso;
252255
s->vlan_ex += rx->stats.vlan_ex;

drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,11 +1136,17 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb,
11361136

11371137
if (dev->num_tc) {
11381138
struct port_info *pi = netdev2pinfo(dev);
1139+
u8 ver, proto;
1140+
1141+
ver = ip_hdr(skb)->version;
1142+
proto = (ver == 6) ? ipv6_hdr(skb)->nexthdr :
1143+
ip_hdr(skb)->protocol;
11391144

11401145
/* Send unsupported traffic pattern to normal NIC queues. */
11411146
txq = netdev_pick_tx(dev, skb, sb_dev);
11421147
if (xfrm_offload(skb) || is_ptp_enabled(skb, dev) ||
1143-
ip_hdr(skb)->protocol != IPPROTO_TCP)
1148+
skb->encapsulation ||
1149+
(proto != IPPROTO_TCP && proto != IPPROTO_UDP))
11441150
txq = txq % pi->nqsets;
11451151

11461152
return txq;
@@ -5838,7 +5844,8 @@ static void free_some_resources(struct adapter *adapter)
58385844
t4_fw_bye(adapter, adapter->pf);
58395845
}
58405846

5841-
#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
5847+
#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | \
5848+
NETIF_F_GSO_UDP_L4)
58425849
#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \
58435850
NETIF_F_GRO | NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
58445851
#define SEGMENT_SIZE 128

drivers/net/ethernet/chelsio/cxgb4/sge.c

Lines changed: 112 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,8 @@ static inline int is_eth_imm(const struct sk_buff *skb, unsigned int chip_ver)
734734
chip_ver > CHELSIO_T5) {
735735
hdrlen = sizeof(struct cpl_tx_tnl_lso);
736736
hdrlen += sizeof(struct cpl_tx_pkt_core);
737+
} else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) {
738+
return 0;
737739
} else {
738740
hdrlen = skb_shinfo(skb)->gso_size ?
739741
sizeof(struct cpl_tx_pkt_lso_core) : 0;
@@ -775,12 +777,20 @@ static inline unsigned int calc_tx_flits(const struct sk_buff *skb,
775777
*/
776778
flits = sgl_len(skb_shinfo(skb)->nr_frags + 1);
777779
if (skb_shinfo(skb)->gso_size) {
778-
if (skb->encapsulation && chip_ver > CHELSIO_T5)
780+
if (skb->encapsulation && chip_ver > CHELSIO_T5) {
779781
hdrlen = sizeof(struct fw_eth_tx_pkt_wr) +
780782
sizeof(struct cpl_tx_tnl_lso);
781-
else
783+
} else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) {
784+
u32 pkt_hdrlen;
785+
786+
pkt_hdrlen = eth_get_headlen(skb->dev, skb->data,
787+
skb_headlen(skb));
788+
hdrlen = sizeof(struct fw_eth_tx_eo_wr) +
789+
round_up(pkt_hdrlen, 16);
790+
} else {
782791
hdrlen = sizeof(struct fw_eth_tx_pkt_wr) +
783792
sizeof(struct cpl_tx_pkt_lso_core);
793+
}
784794

785795
hdrlen += sizeof(struct cpl_tx_pkt_core);
786796
flits += (hdrlen / sizeof(__be64));
@@ -1345,6 +1355,25 @@ static inline int cxgb4_validate_skb(struct sk_buff *skb,
13451355
return 0;
13461356
}
13471357

1358+
static void *write_eo_udp_wr(struct sk_buff *skb, struct fw_eth_tx_eo_wr *wr,
1359+
u32 hdr_len)
1360+
{
1361+
wr->u.udpseg.type = FW_ETH_TX_EO_TYPE_UDPSEG;
1362+
wr->u.udpseg.ethlen = skb_network_offset(skb);
1363+
wr->u.udpseg.iplen = cpu_to_be16(skb_network_header_len(skb));
1364+
wr->u.udpseg.udplen = sizeof(struct udphdr);
1365+
wr->u.udpseg.rtplen = 0;
1366+
wr->u.udpseg.r4 = 0;
1367+
if (skb_shinfo(skb)->gso_size)
1368+
wr->u.udpseg.mss = cpu_to_be16(skb_shinfo(skb)->gso_size);
1369+
else
1370+
wr->u.udpseg.mss = cpu_to_be16(skb->len - hdr_len);
1371+
wr->u.udpseg.schedpktsize = wr->u.udpseg.mss;
1372+
wr->u.udpseg.plen = cpu_to_be32(skb->len - hdr_len);
1373+
1374+
return (void *)(wr + 1);
1375+
}
1376+
13481377
/**
13491378
* cxgb4_eth_xmit - add a packet to an Ethernet Tx queue
13501379
* @skb: the packet
@@ -1357,14 +1386,15 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
13571386
enum cpl_tx_tnl_lso_type tnl_type = TX_TNL_TYPE_OPAQUE;
13581387
bool ptp_enabled = is_ptp_enabled(skb, dev);
13591388
unsigned int last_desc, flits, ndesc;
1389+
u32 wr_mid, ctrl0, op, sgl_off = 0;
13601390
const struct skb_shared_info *ssi;
1391+
int len, qidx, credits, ret, left;
13611392
struct tx_sw_desc *sgl_sdesc;
1393+
struct fw_eth_tx_eo_wr *eowr;
13621394
struct fw_eth_tx_pkt_wr *wr;
13631395
struct cpl_tx_pkt_core *cpl;
1364-
int len, qidx, credits, ret;
13651396
const struct port_info *pi;
13661397
bool immediate = false;
1367-
u32 wr_mid, ctrl0, op;
13681398
u64 cntrl, *end, *sgl;
13691399
struct sge_eth_txq *q;
13701400
unsigned int chip_ver;
@@ -1469,13 +1499,17 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
14691499
}
14701500

14711501
wr = (void *)&q->q.desc[q->q.pidx];
1502+
eowr = (void *)&q->q.desc[q->q.pidx];
14721503
wr->equiq_to_len16 = htonl(wr_mid);
14731504
wr->r3 = cpu_to_be64(0);
1474-
end = (u64 *)wr + flits;
1505+
if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
1506+
end = (u64 *)eowr + flits;
1507+
else
1508+
end = (u64 *)wr + flits;
14751509

14761510
len = immediate ? skb->len : 0;
14771511
len += sizeof(*cpl);
1478-
if (ssi->gso_size) {
1512+
if (ssi->gso_size && !(ssi->gso_type & SKB_GSO_UDP_L4)) {
14791513
struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1);
14801514
struct cpl_tx_tnl_lso *tnl_lso = (void *)(wr + 1);
14811515

@@ -1507,20 +1541,29 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
15071541
cntrl = hwcsum(adap->params.chip, skb);
15081542
}
15091543
sgl = (u64 *)(cpl + 1); /* sgl start here */
1510-
if (unlikely((u8 *)sgl >= (u8 *)q->q.stat)) {
1511-
/* If current position is already at the end of the
1512-
* txq, reset the current to point to start of the queue
1513-
* and update the end ptr as well.
1514-
*/
1515-
if (sgl == (u64 *)q->q.stat) {
1516-
int left = (u8 *)end - (u8 *)q->q.stat;
1517-
1518-
end = (void *)q->q.desc + left;
1519-
sgl = (void *)q->q.desc;
1520-
}
1521-
}
15221544
q->tso++;
15231545
q->tx_cso += ssi->gso_segs;
1546+
} else if (ssi->gso_size) {
1547+
u64 *start;
1548+
u32 hdrlen;
1549+
1550+
hdrlen = eth_get_headlen(dev, skb->data, skb_headlen(skb));
1551+
len += hdrlen;
1552+
wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_EO_WR) |
1553+
FW_ETH_TX_EO_WR_IMMDLEN_V(len));
1554+
cpl = write_eo_udp_wr(skb, eowr, hdrlen);
1555+
cntrl = hwcsum(adap->params.chip, skb);
1556+
1557+
start = (u64 *)(cpl + 1);
1558+
sgl = (u64 *)inline_tx_skb_header(skb, &q->q, (void *)start,
1559+
hdrlen);
1560+
if (unlikely(start > sgl)) {
1561+
left = (u8 *)end - (u8 *)q->q.stat;
1562+
end = (void *)q->q.desc + left;
1563+
}
1564+
sgl_off = hdrlen;
1565+
q->uso++;
1566+
q->tx_cso += ssi->gso_segs;
15241567
} else {
15251568
if (ptp_enabled)
15261569
op = FW_PTP_TX_PKT_WR;
@@ -1537,6 +1580,16 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
15371580
}
15381581
}
15391582

1583+
if (unlikely((u8 *)sgl >= (u8 *)q->q.stat)) {
1584+
/* If current position is already at the end of the
1585+
* txq, reset the current to point to start of the queue
1586+
* and update the end ptr as well.
1587+
*/
1588+
left = (u8 *)end - (u8 *)q->q.stat;
1589+
end = (void *)q->q.desc + left;
1590+
sgl = (void *)q->q.desc;
1591+
}
1592+
15401593
if (skb_vlan_tag_present(skb)) {
15411594
q->vlan_ins++;
15421595
cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb));
@@ -1566,7 +1619,7 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
15661619
cxgb4_inline_tx_skb(skb, &q->q, sgl);
15671620
dev_consume_skb_any(skb);
15681621
} else {
1569-
cxgb4_write_sgl(skb, &q->q, (void *)sgl, end, 0,
1622+
cxgb4_write_sgl(skb, &q->q, (void *)sgl, end, sgl_off,
15701623
sgl_sdesc->addr);
15711624
skb_orphan(skb);
15721625
sgl_sdesc->skb = skb;
@@ -2024,18 +2077,23 @@ static inline u8 ethofld_calc_tx_flits(struct adapter *adap,
20242077
u32 wrlen;
20252078

20262079
wrlen = sizeof(struct fw_eth_tx_eo_wr) + sizeof(struct cpl_tx_pkt_core);
2027-
if (skb_shinfo(skb)->gso_size)
2080+
if (skb_shinfo(skb)->gso_size &&
2081+
!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4))
20282082
wrlen += sizeof(struct cpl_tx_pkt_lso_core);
20292083

20302084
wrlen += roundup(hdr_len, 16);
20312085

20322086
/* Packet headers + WR + CPLs */
20332087
flits = DIV_ROUND_UP(wrlen, 8);
20342088

2035-
if (skb_shinfo(skb)->nr_frags > 0)
2036-
nsgl = sgl_len(skb_shinfo(skb)->nr_frags);
2037-
else if (skb->len - hdr_len)
2089+
if (skb_shinfo(skb)->nr_frags > 0) {
2090+
if (skb_headlen(skb) - hdr_len)
2091+
nsgl = sgl_len(skb_shinfo(skb)->nr_frags + 1);
2092+
else
2093+
nsgl = sgl_len(skb_shinfo(skb)->nr_frags);
2094+
} else if (skb->len - hdr_len) {
20382095
nsgl = sgl_len(1);
2096+
}
20392097

20402098
return flits + nsgl;
20412099
}
@@ -2049,16 +2107,16 @@ static inline void *write_eo_wr(struct adapter *adap,
20492107
struct cpl_tx_pkt_core *cpl;
20502108
u32 immd_len, wrlen16;
20512109
bool compl = false;
2110+
u8 ver, proto;
2111+
2112+
ver = ip_hdr(skb)->version;
2113+
proto = (ver == 6) ? ipv6_hdr(skb)->nexthdr : ip_hdr(skb)->protocol;
20522114

20532115
wrlen16 = DIV_ROUND_UP(wrlen, 16);
20542116
immd_len = sizeof(struct cpl_tx_pkt_core);
2055-
if (skb_shinfo(skb)->gso_size) {
2056-
if (skb->encapsulation &&
2057-
CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5)
2058-
immd_len += sizeof(struct cpl_tx_tnl_lso);
2059-
else
2060-
immd_len += sizeof(struct cpl_tx_pkt_lso_core);
2061-
}
2117+
if (skb_shinfo(skb)->gso_size &&
2118+
!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4))
2119+
immd_len += sizeof(struct cpl_tx_pkt_lso_core);
20622120
immd_len += hdr_len;
20632121

20642122
if (!eosw_txq->ncompl ||
@@ -2074,23 +2132,27 @@ static inline void *write_eo_wr(struct adapter *adap,
20742132
wr->equiq_to_len16 = cpu_to_be32(FW_WR_LEN16_V(wrlen16) |
20752133
FW_WR_FLOWID_V(eosw_txq->hwtid));
20762134
wr->r3 = 0;
2077-
wr->u.tcpseg.type = FW_ETH_TX_EO_TYPE_TCPSEG;
2078-
wr->u.tcpseg.ethlen = skb_network_offset(skb);
2079-
wr->u.tcpseg.iplen = cpu_to_be16(skb_network_header_len(skb));
2080-
wr->u.tcpseg.tcplen = tcp_hdrlen(skb);
2081-
wr->u.tcpseg.tsclk_tsoff = 0;
2082-
wr->u.tcpseg.r4 = 0;
2083-
wr->u.tcpseg.r5 = 0;
2084-
wr->u.tcpseg.plen = cpu_to_be32(skb->len - hdr_len);
2085-
2086-
if (ssi->gso_size) {
2087-
struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1);
2088-
2089-
wr->u.tcpseg.mss = cpu_to_be16(ssi->gso_size);
2090-
cpl = write_tso_wr(adap, skb, lso);
2135+
if (proto == IPPROTO_UDP) {
2136+
cpl = write_eo_udp_wr(skb, wr, hdr_len);
20912137
} else {
2092-
wr->u.tcpseg.mss = cpu_to_be16(0xffff);
2093-
cpl = (void *)(wr + 1);
2138+
wr->u.tcpseg.type = FW_ETH_TX_EO_TYPE_TCPSEG;
2139+
wr->u.tcpseg.ethlen = skb_network_offset(skb);
2140+
wr->u.tcpseg.iplen = cpu_to_be16(skb_network_header_len(skb));
2141+
wr->u.tcpseg.tcplen = tcp_hdrlen(skb);
2142+
wr->u.tcpseg.tsclk_tsoff = 0;
2143+
wr->u.tcpseg.r4 = 0;
2144+
wr->u.tcpseg.r5 = 0;
2145+
wr->u.tcpseg.plen = cpu_to_be32(skb->len - hdr_len);
2146+
2147+
if (ssi->gso_size) {
2148+
struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1);
2149+
2150+
wr->u.tcpseg.mss = cpu_to_be16(ssi->gso_size);
2151+
cpl = write_tso_wr(adap, skb, lso);
2152+
} else {
2153+
wr->u.tcpseg.mss = cpu_to_be16(0xffff);
2154+
cpl = (void *)(wr + 1);
2155+
}
20942156
}
20952157

20962158
eosw_txq->cred -= wrlen16;
@@ -4312,7 +4374,10 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
43124374
txq->q.q_type = CXGB4_TXQ_ETH;
43134375
init_txq(adap, &txq->q, FW_EQ_ETH_CMD_EQID_G(ntohl(c.eqid_pkd)));
43144376
txq->txq = netdevq;
4315-
txq->tso = txq->tx_cso = txq->vlan_ins = 0;
4377+
txq->tso = 0;
4378+
txq->uso = 0;
4379+
txq->tx_cso = 0;
4380+
txq->vlan_ins = 0;
43164381
txq->mapping_err = 0;
43174382
txq->dbqt = dbqt;
43184383

drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,14 +536,26 @@ struct fw_eth_tx_pkt_wr {
536536
};
537537

538538
enum fw_eth_tx_eo_type {
539-
FW_ETH_TX_EO_TYPE_TCPSEG = 1,
539+
FW_ETH_TX_EO_TYPE_UDPSEG = 0,
540+
FW_ETH_TX_EO_TYPE_TCPSEG,
540541
};
541542

542543
struct fw_eth_tx_eo_wr {
543544
__be32 op_immdlen;
544545
__be32 equiq_to_len16;
545546
__be64 r3;
546547
union fw_eth_tx_eo {
548+
struct fw_eth_tx_eo_udpseg {
549+
__u8 type;
550+
__u8 ethlen;
551+
__be16 iplen;
552+
__u8 udplen;
553+
__u8 rtplen;
554+
__be16 r4;
555+
__be16 mss;
556+
__be16 schedpktsize;
557+
__be32 plen;
558+
} udpseg;
547559
struct fw_eth_tx_eo_tcpseg {
548560
__u8 type;
549561
__u8 ethlen;

0 commit comments

Comments
 (0)