Skip to content

Commit cc18a75

Browse files
Zhao Chendavem330
authored andcommitted
net-next/hinic: add checksum offload and TSO support
This patch adds checksum offload and TSO support for the HiNIC driver. Perfomance test (Iperf) shows more than 100% improvement in TCP streams. Signed-off-by: Zhao Chen <zhaochen6@huawei.com> Signed-off-by: Xue Chaojing <xuechaojing@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 40b0655 commit cc18a75

File tree

10 files changed

+571
-60
lines changed

10 files changed

+571
-60
lines changed

drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ enum hinic_port_cmd {
5858

5959
HINIC_PORT_CMD_GET_GLOBAL_QPN = 102,
6060

61+
HINIC_PORT_CMD_SET_TSO = 112,
62+
6163
HINIC_PORT_CMD_GET_CAP = 170,
6264
};
6365

drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c

Lines changed: 96 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@
7070
#define SQ_MASKED_IDX(sq, idx) ((idx) & (sq)->wq->mask)
7171
#define RQ_MASKED_IDX(rq, idx) ((idx) & (rq)->wq->mask)
7272

73-
#define TX_MAX_MSS_DEFAULT 0x3E00
74-
7573
enum sq_wqe_type {
7674
SQ_NORMAL_WQE = 0,
7775
};
@@ -494,33 +492,16 @@ static void sq_prepare_ctrl(struct hinic_sq_ctrl *ctrl, u16 prod_idx,
494492
HINIC_SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT) |
495493
HINIC_SQ_CTRL_SET(ctrl_size, LEN);
496494

497-
ctrl->queue_info = HINIC_SQ_CTRL_SET(TX_MAX_MSS_DEFAULT,
498-
QUEUE_INFO_MSS);
495+
ctrl->queue_info = HINIC_SQ_CTRL_SET(HINIC_MSS_DEFAULT,
496+
QUEUE_INFO_MSS) |
497+
HINIC_SQ_CTRL_SET(1, QUEUE_INFO_UC);
499498
}
500499

501500
static void sq_prepare_task(struct hinic_sq_task *task)
502501
{
503-
task->pkt_info0 =
504-
HINIC_SQ_TASK_INFO0_SET(0, L2HDR_LEN) |
505-
HINIC_SQ_TASK_INFO0_SET(HINIC_L4_OFF_DISABLE, L4_OFFLOAD) |
506-
HINIC_SQ_TASK_INFO0_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
507-
INNER_L3TYPE) |
508-
HINIC_SQ_TASK_INFO0_SET(HINIC_VLAN_OFF_DISABLE,
509-
VLAN_OFFLOAD) |
510-
HINIC_SQ_TASK_INFO0_SET(HINIC_PKT_NOT_PARSED, PARSE_FLAG);
511-
512-
task->pkt_info1 =
513-
HINIC_SQ_TASK_INFO1_SET(HINIC_MEDIA_UNKNOWN, MEDIA_TYPE) |
514-
HINIC_SQ_TASK_INFO1_SET(0, INNER_L4_LEN) |
515-
HINIC_SQ_TASK_INFO1_SET(0, INNER_L3_LEN);
516-
517-
task->pkt_info2 =
518-
HINIC_SQ_TASK_INFO2_SET(0, TUNNEL_L4_LEN) |
519-
HINIC_SQ_TASK_INFO2_SET(0, OUTER_L3_LEN) |
520-
HINIC_SQ_TASK_INFO2_SET(HINIC_TUNNEL_L4TYPE_UNKNOWN,
521-
TUNNEL_L4TYPE) |
522-
HINIC_SQ_TASK_INFO2_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
523-
OUTER_L3TYPE);
502+
task->pkt_info0 = 0;
503+
task->pkt_info1 = 0;
504+
task->pkt_info2 = 0;
524505

525506
task->ufo_v6_identify = 0;
526507

@@ -529,6 +510,86 @@ static void sq_prepare_task(struct hinic_sq_task *task)
529510
task->zero_pad = 0;
530511
}
531512

513+
void hinic_task_set_l2hdr(struct hinic_sq_task *task, u32 len)
514+
{
515+
task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(len, L2HDR_LEN);
516+
}
517+
518+
void hinic_task_set_outter_l3(struct hinic_sq_task *task,
519+
enum hinic_l3_offload_type l3_type,
520+
u32 network_len)
521+
{
522+
task->pkt_info2 |= HINIC_SQ_TASK_INFO2_SET(l3_type, OUTER_L3TYPE) |
523+
HINIC_SQ_TASK_INFO2_SET(network_len, OUTER_L3LEN);
524+
}
525+
526+
void hinic_task_set_inner_l3(struct hinic_sq_task *task,
527+
enum hinic_l3_offload_type l3_type,
528+
u32 network_len)
529+
{
530+
task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l3_type, INNER_L3TYPE);
531+
task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(network_len, INNER_L3LEN);
532+
}
533+
534+
void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
535+
enum hinic_l4_offload_type l4_type,
536+
u32 tunnel_len)
537+
{
538+
task->pkt_info2 |= HINIC_SQ_TASK_INFO2_SET(l4_type, TUNNEL_L4TYPE) |
539+
HINIC_SQ_TASK_INFO2_SET(tunnel_len, TUNNEL_L4LEN);
540+
}
541+
542+
void hinic_set_cs_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
543+
enum hinic_l4_offload_type l4_offload,
544+
u32 l4_len, u32 offset)
545+
{
546+
u32 tcp_udp_cs = 0, sctp = 0;
547+
u32 mss = HINIC_MSS_DEFAULT;
548+
549+
if (l4_offload == TCP_OFFLOAD_ENABLE ||
550+
l4_offload == UDP_OFFLOAD_ENABLE)
551+
tcp_udp_cs = 1;
552+
else if (l4_offload == SCTP_OFFLOAD_ENABLE)
553+
sctp = 1;
554+
555+
task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l4_offload, L4_OFFLOAD);
556+
task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);
557+
558+
*queue_info |= HINIC_SQ_CTRL_SET(offset, QUEUE_INFO_PLDOFF) |
559+
HINIC_SQ_CTRL_SET(tcp_udp_cs, QUEUE_INFO_TCPUDP_CS) |
560+
HINIC_SQ_CTRL_SET(sctp, QUEUE_INFO_SCTP);
561+
562+
*queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
563+
*queue_info |= HINIC_SQ_CTRL_SET(mss, QUEUE_INFO_MSS);
564+
}
565+
566+
void hinic_set_tso_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
567+
enum hinic_l4_offload_type l4_offload,
568+
u32 l4_len, u32 offset, u32 ip_ident, u32 mss)
569+
{
570+
u32 tso = 0, ufo = 0;
571+
572+
if (l4_offload == TCP_OFFLOAD_ENABLE)
573+
tso = 1;
574+
else if (l4_offload == UDP_OFFLOAD_ENABLE)
575+
ufo = 1;
576+
577+
task->ufo_v6_identify = ip_ident;
578+
579+
task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l4_offload, L4_OFFLOAD);
580+
task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(tso || ufo, TSO_FLAG);
581+
task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);
582+
583+
*queue_info |= HINIC_SQ_CTRL_SET(offset, QUEUE_INFO_PLDOFF) |
584+
HINIC_SQ_CTRL_SET(tso, QUEUE_INFO_TSO) |
585+
HINIC_SQ_CTRL_SET(ufo, QUEUE_INFO_UFO) |
586+
HINIC_SQ_CTRL_SET(!!l4_offload, QUEUE_INFO_TCPUDP_CS);
587+
588+
/* set MSS value */
589+
*queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
590+
*queue_info |= HINIC_SQ_CTRL_SET(mss, QUEUE_INFO_MSS);
591+
}
592+
532593
/**
533594
* hinic_sq_prepare_wqe - prepare wqe before insert to the queue
534595
* @sq: send queue
@@ -612,6 +673,16 @@ struct hinic_sq_wqe *hinic_sq_get_wqe(struct hinic_sq *sq,
612673
return &hw_wqe->sq_wqe;
613674
}
614675

676+
/**
677+
* hinic_sq_return_wqe - return the wqe to the sq
678+
* @sq: send queue
679+
* @wqe_size: the size of the wqe
680+
**/
681+
void hinic_sq_return_wqe(struct hinic_sq *sq, unsigned int wqe_size)
682+
{
683+
hinic_return_wqe(sq->wq, wqe_size);
684+
}
685+
615686
/**
616687
* hinic_sq_write_wqe - write the wqe to the sq
617688
* @sq: send queue

drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,31 @@ int hinic_get_sq_free_wqebbs(struct hinic_sq *sq);
149149

150150
int hinic_get_rq_free_wqebbs(struct hinic_rq *rq);
151151

152+
void hinic_task_set_l2hdr(struct hinic_sq_task *task, u32 len);
153+
154+
void hinic_task_set_outter_l3(struct hinic_sq_task *task,
155+
enum hinic_l3_offload_type l3_type,
156+
u32 network_len);
157+
158+
void hinic_task_set_inner_l3(struct hinic_sq_task *task,
159+
enum hinic_l3_offload_type l3_type,
160+
u32 network_len);
161+
162+
void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
163+
enum hinic_l4_offload_type l4_type,
164+
u32 tunnel_len);
165+
166+
void hinic_set_cs_inner_l4(struct hinic_sq_task *task,
167+
u32 *queue_info,
168+
enum hinic_l4_offload_type l4_offload,
169+
u32 l4_len, u32 offset);
170+
171+
void hinic_set_tso_inner_l4(struct hinic_sq_task *task,
172+
u32 *queue_info,
173+
enum hinic_l4_offload_type l4_offload,
174+
u32 l4_len,
175+
u32 offset, u32 ip_ident, u32 mss);
176+
152177
void hinic_sq_prepare_wqe(struct hinic_sq *sq, u16 prod_idx,
153178
struct hinic_sq_wqe *wqe, struct hinic_sge *sges,
154179
int nr_sges);
@@ -159,6 +184,8 @@ void hinic_sq_write_db(struct hinic_sq *sq, u16 prod_idx, unsigned int wqe_size,
159184
struct hinic_sq_wqe *hinic_sq_get_wqe(struct hinic_sq *sq,
160185
unsigned int wqe_size, u16 *prod_idx);
161186

187+
void hinic_sq_return_wqe(struct hinic_sq *sq, unsigned int wqe_size);
188+
162189
void hinic_sq_write_wqe(struct hinic_sq *sq, u16 prod_idx,
163190
struct hinic_sq_wqe *wqe, struct sk_buff *skb,
164191
unsigned int wqe_size);

drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,20 @@ struct hinic_hw_wqe *hinic_get_wqe(struct hinic_wq *wq, unsigned int wqe_size,
774774
return WQ_PAGE_ADDR(wq, *prod_idx) + WQE_PAGE_OFF(wq, *prod_idx);
775775
}
776776

777+
/**
778+
* hinic_return_wqe - return the wqe when transmit failed
779+
* @wq: wq to return wqe
780+
* @wqe_size: wqe size
781+
**/
782+
void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size)
783+
{
784+
int num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) / wq->wqebb_size;
785+
786+
atomic_sub(num_wqebbs, &wq->prod_idx);
787+
788+
atomic_add(num_wqebbs, &wq->delta);
789+
}
790+
777791
/**
778792
* hinic_put_wqe - return the wqe place to use for a new wqe
779793
* @wq: wq to return wqe

drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ void hinic_wq_free(struct hinic_wqs *wqs, struct hinic_wq *wq);
104104
struct hinic_hw_wqe *hinic_get_wqe(struct hinic_wq *wq, unsigned int wqe_size,
105105
u16 *prod_idx);
106106

107+
void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size);
108+
107109
void hinic_put_wqe(struct hinic_wq *wq, unsigned int wqe_size);
108110

109111
struct hinic_hw_wqe *hinic_read_wqe(struct hinic_wq *wq, unsigned int wqe_size,

drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,33 @@
6262
(((val) >> HINIC_CMDQ_WQE_HEADER_##member##_SHIFT) \
6363
& HINIC_CMDQ_WQE_HEADER_##member##_MASK)
6464

65-
#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_SHIFT 0
66-
#define HINIC_SQ_CTRL_TASKSECT_LEN_SHIFT 16
67-
#define HINIC_SQ_CTRL_DATA_FORMAT_SHIFT 22
68-
#define HINIC_SQ_CTRL_LEN_SHIFT 29
69-
70-
#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_MASK 0xFF
71-
#define HINIC_SQ_CTRL_TASKSECT_LEN_MASK 0x1F
72-
#define HINIC_SQ_CTRL_DATA_FORMAT_MASK 0x1
73-
#define HINIC_SQ_CTRL_LEN_MASK 0x3
74-
75-
#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_SHIFT 13
76-
77-
#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_MASK 0x3FFF
65+
#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_SHIFT 0
66+
#define HINIC_SQ_CTRL_TASKSECT_LEN_SHIFT 16
67+
#define HINIC_SQ_CTRL_DATA_FORMAT_SHIFT 22
68+
#define HINIC_SQ_CTRL_LEN_SHIFT 29
69+
70+
#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_MASK 0xFF
71+
#define HINIC_SQ_CTRL_TASKSECT_LEN_MASK 0x1F
72+
#define HINIC_SQ_CTRL_DATA_FORMAT_MASK 0x1
73+
#define HINIC_SQ_CTRL_LEN_MASK 0x3
74+
75+
#define HINIC_SQ_CTRL_QUEUE_INFO_PLDOFF_SHIFT 2
76+
#define HINIC_SQ_CTRL_QUEUE_INFO_UFO_SHIFT 10
77+
#define HINIC_SQ_CTRL_QUEUE_INFO_TSO_SHIFT 11
78+
#define HINIC_SQ_CTRL_QUEUE_INFO_TCPUDP_CS_SHIFT 12
79+
#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_SHIFT 13
80+
#define HINIC_SQ_CTRL_QUEUE_INFO_SCTP_SHIFT 27
81+
#define HINIC_SQ_CTRL_QUEUE_INFO_UC_SHIFT 28
82+
#define HINIC_SQ_CTRL_QUEUE_INFO_PRI_SHIFT 29
83+
84+
#define HINIC_SQ_CTRL_QUEUE_INFO_PLDOFF_MASK 0xFF
85+
#define HINIC_SQ_CTRL_QUEUE_INFO_UFO_MASK 0x1
86+
#define HINIC_SQ_CTRL_QUEUE_INFO_TSO_MASK 0x1
87+
#define HINIC_SQ_CTRL_QUEUE_INFO_TCPUDP_CS_MASK 0x1
88+
#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_MASK 0x3FFF
89+
#define HINIC_SQ_CTRL_QUEUE_INFO_SCTP_MASK 0x1
90+
#define HINIC_SQ_CTRL_QUEUE_INFO_UC_MASK 0x1
91+
#define HINIC_SQ_CTRL_QUEUE_INFO_PRI_MASK 0x7
7892

7993
#define HINIC_SQ_CTRL_SET(val, member) \
8094
(((u32)(val) & HINIC_SQ_CTRL_##member##_MASK) \
@@ -84,6 +98,10 @@
8498
(((val) >> HINIC_SQ_CTRL_##member##_SHIFT) \
8599
& HINIC_SQ_CTRL_##member##_MASK)
86100

101+
#define HINIC_SQ_CTRL_CLEAR(val, member) \
102+
((u32)(val) & (~(HINIC_SQ_CTRL_##member##_MASK \
103+
<< HINIC_SQ_CTRL_##member##_SHIFT)))
104+
87105
#define HINIC_SQ_TASK_INFO0_L2HDR_LEN_SHIFT 0
88106
#define HINIC_SQ_TASK_INFO0_L4_OFFLOAD_SHIFT 8
89107
#define HINIC_SQ_TASK_INFO0_INNER_L3TYPE_SHIFT 10
@@ -108,28 +126,28 @@
108126

109127
/* 8 bits reserved */
110128
#define HINIC_SQ_TASK_INFO1_MEDIA_TYPE_SHIFT 8
111-
#define HINIC_SQ_TASK_INFO1_INNER_L4_LEN_SHIFT 16
112-
#define HINIC_SQ_TASK_INFO1_INNER_L3_LEN_SHIFT 24
129+
#define HINIC_SQ_TASK_INFO1_INNER_L4LEN_SHIFT 16
130+
#define HINIC_SQ_TASK_INFO1_INNER_L3LEN_SHIFT 24
113131

114132
/* 8 bits reserved */
115133
#define HINIC_SQ_TASK_INFO1_MEDIA_TYPE_MASK 0xFF
116-
#define HINIC_SQ_TASK_INFO1_INNER_L4_LEN_MASK 0xFF
117-
#define HINIC_SQ_TASK_INFO1_INNER_L3_LEN_MASK 0xFF
134+
#define HINIC_SQ_TASK_INFO1_INNER_L4LEN_MASK 0xFF
135+
#define HINIC_SQ_TASK_INFO1_INNER_L3LEN_MASK 0xFF
118136

119137
#define HINIC_SQ_TASK_INFO1_SET(val, member) \
120138
(((u32)(val) & HINIC_SQ_TASK_INFO1_##member##_MASK) << \
121139
HINIC_SQ_TASK_INFO1_##member##_SHIFT)
122140

123-
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4_LEN_SHIFT 0
124-
#define HINIC_SQ_TASK_INFO2_OUTER_L3_LEN_SHIFT 12
125-
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_SHIFT 19
141+
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4LEN_SHIFT 0
142+
#define HINIC_SQ_TASK_INFO2_OUTER_L3LEN_SHIFT 8
143+
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_SHIFT 16
126144
/* 1 bit reserved */
127-
#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_SHIFT 22
145+
#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_SHIFT 24
128146
/* 8 bits reserved */
129147

130-
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4_LEN_MASK 0xFFF
131-
#define HINIC_SQ_TASK_INFO2_OUTER_L3_LEN_MASK 0x7F
132-
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_MASK 0x3
148+
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4LEN_MASK 0xFF
149+
#define HINIC_SQ_TASK_INFO2_OUTER_L3LEN_MASK 0xFF
150+
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_MASK 0x7
133151
/* 1 bit reserved */
134152
#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_MASK 0x3
135153
/* 8 bits reserved */
@@ -187,12 +205,15 @@
187205
sizeof(struct hinic_sq_task) + \
188206
(nr_sges) * sizeof(struct hinic_sq_bufdesc))
189207

190-
#define HINIC_SCMD_DATA_LEN 16
208+
#define HINIC_SCMD_DATA_LEN 16
209+
210+
#define HINIC_MAX_SQ_BUFDESCS 17
191211

192-
#define HINIC_MAX_SQ_BUFDESCS 17
212+
#define HINIC_SQ_WQE_MAX_SIZE 320
213+
#define HINIC_RQ_WQE_SIZE 32
193214

194-
#define HINIC_SQ_WQE_MAX_SIZE 320
195-
#define HINIC_RQ_WQE_SIZE 32
215+
#define HINIC_MSS_DEFAULT 0x3E00
216+
#define HINIC_MSS_MIN 0x50
196217

197218
enum hinic_l4offload_type {
198219
HINIC_L4_OFF_DISABLE = 0,
@@ -211,6 +232,26 @@ enum hinic_pkt_parsed {
211232
HINIC_PKT_PARSED = 1,
212233
};
213234

235+
enum hinic_l3_offload_type {
236+
L3TYPE_UNKNOWN = 0,
237+
IPV6_PKT = 1,
238+
IPV4_PKT_NO_CHKSUM_OFFLOAD = 2,
239+
IPV4_PKT_WITH_CHKSUM_OFFLOAD = 3,
240+
};
241+
242+
enum hinic_l4_offload_type {
243+
OFFLOAD_DISABLE = 0,
244+
TCP_OFFLOAD_ENABLE = 1,
245+
SCTP_OFFLOAD_ENABLE = 2,
246+
UDP_OFFLOAD_ENABLE = 3,
247+
};
248+
249+
enum hinic_l4_tunnel_type {
250+
NOT_TUNNEL,
251+
TUNNEL_UDP_NO_CSUM,
252+
TUNNEL_UDP_CSUM,
253+
};
254+
214255
enum hinic_outer_l3type {
215256
HINIC_OUTER_L3TYPE_UNKNOWN = 0,
216257
HINIC_OUTER_L3TYPE_IPV6 = 1,

0 commit comments

Comments
 (0)