Skip to content

Commit

Permalink
net-next/hinic: add checksum offload and TSO support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Zhao Chen authored and davem330 committed Oct 18, 2018
1 parent 40b0655 commit cc18a75
Show file tree
Hide file tree
Showing 10 changed files with 571 additions and 60 deletions.
2 changes: 2 additions & 0 deletions drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ enum hinic_port_cmd {

HINIC_PORT_CMD_GET_GLOBAL_QPN = 102,

HINIC_PORT_CMD_SET_TSO = 112,

HINIC_PORT_CMD_GET_CAP = 170,
};

Expand Down
121 changes: 96 additions & 25 deletions drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@
#define SQ_MASKED_IDX(sq, idx) ((idx) & (sq)->wq->mask)
#define RQ_MASKED_IDX(rq, idx) ((idx) & (rq)->wq->mask)

#define TX_MAX_MSS_DEFAULT 0x3E00

enum sq_wqe_type {
SQ_NORMAL_WQE = 0,
};
Expand Down Expand Up @@ -494,33 +492,16 @@ static void sq_prepare_ctrl(struct hinic_sq_ctrl *ctrl, u16 prod_idx,
HINIC_SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT) |
HINIC_SQ_CTRL_SET(ctrl_size, LEN);

ctrl->queue_info = HINIC_SQ_CTRL_SET(TX_MAX_MSS_DEFAULT,
QUEUE_INFO_MSS);
ctrl->queue_info = HINIC_SQ_CTRL_SET(HINIC_MSS_DEFAULT,
QUEUE_INFO_MSS) |
HINIC_SQ_CTRL_SET(1, QUEUE_INFO_UC);
}

static void sq_prepare_task(struct hinic_sq_task *task)
{
task->pkt_info0 =
HINIC_SQ_TASK_INFO0_SET(0, L2HDR_LEN) |
HINIC_SQ_TASK_INFO0_SET(HINIC_L4_OFF_DISABLE, L4_OFFLOAD) |
HINIC_SQ_TASK_INFO0_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
INNER_L3TYPE) |
HINIC_SQ_TASK_INFO0_SET(HINIC_VLAN_OFF_DISABLE,
VLAN_OFFLOAD) |
HINIC_SQ_TASK_INFO0_SET(HINIC_PKT_NOT_PARSED, PARSE_FLAG);

task->pkt_info1 =
HINIC_SQ_TASK_INFO1_SET(HINIC_MEDIA_UNKNOWN, MEDIA_TYPE) |
HINIC_SQ_TASK_INFO1_SET(0, INNER_L4_LEN) |
HINIC_SQ_TASK_INFO1_SET(0, INNER_L3_LEN);

task->pkt_info2 =
HINIC_SQ_TASK_INFO2_SET(0, TUNNEL_L4_LEN) |
HINIC_SQ_TASK_INFO2_SET(0, OUTER_L3_LEN) |
HINIC_SQ_TASK_INFO2_SET(HINIC_TUNNEL_L4TYPE_UNKNOWN,
TUNNEL_L4TYPE) |
HINIC_SQ_TASK_INFO2_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
OUTER_L3TYPE);
task->pkt_info0 = 0;
task->pkt_info1 = 0;
task->pkt_info2 = 0;

task->ufo_v6_identify = 0;

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

void hinic_task_set_l2hdr(struct hinic_sq_task *task, u32 len)
{
task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(len, L2HDR_LEN);
}

void hinic_task_set_outter_l3(struct hinic_sq_task *task,
enum hinic_l3_offload_type l3_type,
u32 network_len)
{
task->pkt_info2 |= HINIC_SQ_TASK_INFO2_SET(l3_type, OUTER_L3TYPE) |
HINIC_SQ_TASK_INFO2_SET(network_len, OUTER_L3LEN);
}

void hinic_task_set_inner_l3(struct hinic_sq_task *task,
enum hinic_l3_offload_type l3_type,
u32 network_len)
{
task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l3_type, INNER_L3TYPE);
task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(network_len, INNER_L3LEN);
}

void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
enum hinic_l4_offload_type l4_type,
u32 tunnel_len)
{
task->pkt_info2 |= HINIC_SQ_TASK_INFO2_SET(l4_type, TUNNEL_L4TYPE) |
HINIC_SQ_TASK_INFO2_SET(tunnel_len, TUNNEL_L4LEN);
}

void hinic_set_cs_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
enum hinic_l4_offload_type l4_offload,
u32 l4_len, u32 offset)
{
u32 tcp_udp_cs = 0, sctp = 0;
u32 mss = HINIC_MSS_DEFAULT;

if (l4_offload == TCP_OFFLOAD_ENABLE ||
l4_offload == UDP_OFFLOAD_ENABLE)
tcp_udp_cs = 1;
else if (l4_offload == SCTP_OFFLOAD_ENABLE)
sctp = 1;

task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l4_offload, L4_OFFLOAD);
task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);

*queue_info |= HINIC_SQ_CTRL_SET(offset, QUEUE_INFO_PLDOFF) |
HINIC_SQ_CTRL_SET(tcp_udp_cs, QUEUE_INFO_TCPUDP_CS) |
HINIC_SQ_CTRL_SET(sctp, QUEUE_INFO_SCTP);

*queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
*queue_info |= HINIC_SQ_CTRL_SET(mss, QUEUE_INFO_MSS);
}

void hinic_set_tso_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
enum hinic_l4_offload_type l4_offload,
u32 l4_len, u32 offset, u32 ip_ident, u32 mss)
{
u32 tso = 0, ufo = 0;

if (l4_offload == TCP_OFFLOAD_ENABLE)
tso = 1;
else if (l4_offload == UDP_OFFLOAD_ENABLE)
ufo = 1;

task->ufo_v6_identify = ip_ident;

task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l4_offload, L4_OFFLOAD);
task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(tso || ufo, TSO_FLAG);
task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);

*queue_info |= HINIC_SQ_CTRL_SET(offset, QUEUE_INFO_PLDOFF) |
HINIC_SQ_CTRL_SET(tso, QUEUE_INFO_TSO) |
HINIC_SQ_CTRL_SET(ufo, QUEUE_INFO_UFO) |
HINIC_SQ_CTRL_SET(!!l4_offload, QUEUE_INFO_TCPUDP_CS);

/* set MSS value */
*queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
*queue_info |= HINIC_SQ_CTRL_SET(mss, QUEUE_INFO_MSS);
}

/**
* hinic_sq_prepare_wqe - prepare wqe before insert to the queue
* @sq: send queue
Expand Down Expand Up @@ -612,6 +673,16 @@ struct hinic_sq_wqe *hinic_sq_get_wqe(struct hinic_sq *sq,
return &hw_wqe->sq_wqe;
}

/**
* hinic_sq_return_wqe - return the wqe to the sq
* @sq: send queue
* @wqe_size: the size of the wqe
**/
void hinic_sq_return_wqe(struct hinic_sq *sq, unsigned int wqe_size)
{
hinic_return_wqe(sq->wq, wqe_size);
}

/**
* hinic_sq_write_wqe - write the wqe to the sq
* @sq: send queue
Expand Down
27 changes: 27 additions & 0 deletions drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,31 @@ int hinic_get_sq_free_wqebbs(struct hinic_sq *sq);

int hinic_get_rq_free_wqebbs(struct hinic_rq *rq);

void hinic_task_set_l2hdr(struct hinic_sq_task *task, u32 len);

void hinic_task_set_outter_l3(struct hinic_sq_task *task,
enum hinic_l3_offload_type l3_type,
u32 network_len);

void hinic_task_set_inner_l3(struct hinic_sq_task *task,
enum hinic_l3_offload_type l3_type,
u32 network_len);

void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
enum hinic_l4_offload_type l4_type,
u32 tunnel_len);

void hinic_set_cs_inner_l4(struct hinic_sq_task *task,
u32 *queue_info,
enum hinic_l4_offload_type l4_offload,
u32 l4_len, u32 offset);

void hinic_set_tso_inner_l4(struct hinic_sq_task *task,
u32 *queue_info,
enum hinic_l4_offload_type l4_offload,
u32 l4_len,
u32 offset, u32 ip_ident, u32 mss);

void hinic_sq_prepare_wqe(struct hinic_sq *sq, u16 prod_idx,
struct hinic_sq_wqe *wqe, struct hinic_sge *sges,
int nr_sges);
Expand All @@ -159,6 +184,8 @@ void hinic_sq_write_db(struct hinic_sq *sq, u16 prod_idx, unsigned int wqe_size,
struct hinic_sq_wqe *hinic_sq_get_wqe(struct hinic_sq *sq,
unsigned int wqe_size, u16 *prod_idx);

void hinic_sq_return_wqe(struct hinic_sq *sq, unsigned int wqe_size);

void hinic_sq_write_wqe(struct hinic_sq *sq, u16 prod_idx,
struct hinic_sq_wqe *wqe, struct sk_buff *skb,
unsigned int wqe_size);
Expand Down
14 changes: 14 additions & 0 deletions drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,20 @@ struct hinic_hw_wqe *hinic_get_wqe(struct hinic_wq *wq, unsigned int wqe_size,
return WQ_PAGE_ADDR(wq, *prod_idx) + WQE_PAGE_OFF(wq, *prod_idx);
}

/**
* hinic_return_wqe - return the wqe when transmit failed
* @wq: wq to return wqe
* @wqe_size: wqe size
**/
void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size)
{
int num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) / wq->wqebb_size;

atomic_sub(num_wqebbs, &wq->prod_idx);

atomic_add(num_wqebbs, &wq->delta);
}

/**
* hinic_put_wqe - return the wqe place to use for a new wqe
* @wq: wq to return wqe
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ void hinic_wq_free(struct hinic_wqs *wqs, struct hinic_wq *wq);
struct hinic_hw_wqe *hinic_get_wqe(struct hinic_wq *wq, unsigned int wqe_size,
u16 *prod_idx);

void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size);

void hinic_put_wqe(struct hinic_wq *wq, unsigned int wqe_size);

struct hinic_hw_wqe *hinic_read_wqe(struct hinic_wq *wq, unsigned int wqe_size,
Expand Down
97 changes: 69 additions & 28 deletions drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,33 @@
(((val) >> HINIC_CMDQ_WQE_HEADER_##member##_SHIFT) \
& HINIC_CMDQ_WQE_HEADER_##member##_MASK)

#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_SHIFT 0
#define HINIC_SQ_CTRL_TASKSECT_LEN_SHIFT 16
#define HINIC_SQ_CTRL_DATA_FORMAT_SHIFT 22
#define HINIC_SQ_CTRL_LEN_SHIFT 29

#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_MASK 0xFF
#define HINIC_SQ_CTRL_TASKSECT_LEN_MASK 0x1F
#define HINIC_SQ_CTRL_DATA_FORMAT_MASK 0x1
#define HINIC_SQ_CTRL_LEN_MASK 0x3

#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_SHIFT 13

#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_MASK 0x3FFF
#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_SHIFT 0
#define HINIC_SQ_CTRL_TASKSECT_LEN_SHIFT 16
#define HINIC_SQ_CTRL_DATA_FORMAT_SHIFT 22
#define HINIC_SQ_CTRL_LEN_SHIFT 29

#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_MASK 0xFF
#define HINIC_SQ_CTRL_TASKSECT_LEN_MASK 0x1F
#define HINIC_SQ_CTRL_DATA_FORMAT_MASK 0x1
#define HINIC_SQ_CTRL_LEN_MASK 0x3

#define HINIC_SQ_CTRL_QUEUE_INFO_PLDOFF_SHIFT 2
#define HINIC_SQ_CTRL_QUEUE_INFO_UFO_SHIFT 10
#define HINIC_SQ_CTRL_QUEUE_INFO_TSO_SHIFT 11
#define HINIC_SQ_CTRL_QUEUE_INFO_TCPUDP_CS_SHIFT 12
#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_SHIFT 13
#define HINIC_SQ_CTRL_QUEUE_INFO_SCTP_SHIFT 27
#define HINIC_SQ_CTRL_QUEUE_INFO_UC_SHIFT 28
#define HINIC_SQ_CTRL_QUEUE_INFO_PRI_SHIFT 29

#define HINIC_SQ_CTRL_QUEUE_INFO_PLDOFF_MASK 0xFF
#define HINIC_SQ_CTRL_QUEUE_INFO_UFO_MASK 0x1
#define HINIC_SQ_CTRL_QUEUE_INFO_TSO_MASK 0x1
#define HINIC_SQ_CTRL_QUEUE_INFO_TCPUDP_CS_MASK 0x1
#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_MASK 0x3FFF
#define HINIC_SQ_CTRL_QUEUE_INFO_SCTP_MASK 0x1
#define HINIC_SQ_CTRL_QUEUE_INFO_UC_MASK 0x1
#define HINIC_SQ_CTRL_QUEUE_INFO_PRI_MASK 0x7

#define HINIC_SQ_CTRL_SET(val, member) \
(((u32)(val) & HINIC_SQ_CTRL_##member##_MASK) \
Expand All @@ -84,6 +98,10 @@
(((val) >> HINIC_SQ_CTRL_##member##_SHIFT) \
& HINIC_SQ_CTRL_##member##_MASK)

#define HINIC_SQ_CTRL_CLEAR(val, member) \
((u32)(val) & (~(HINIC_SQ_CTRL_##member##_MASK \
<< HINIC_SQ_CTRL_##member##_SHIFT)))

#define HINIC_SQ_TASK_INFO0_L2HDR_LEN_SHIFT 0
#define HINIC_SQ_TASK_INFO0_L4_OFFLOAD_SHIFT 8
#define HINIC_SQ_TASK_INFO0_INNER_L3TYPE_SHIFT 10
Expand All @@ -108,28 +126,28 @@

/* 8 bits reserved */
#define HINIC_SQ_TASK_INFO1_MEDIA_TYPE_SHIFT 8
#define HINIC_SQ_TASK_INFO1_INNER_L4_LEN_SHIFT 16
#define HINIC_SQ_TASK_INFO1_INNER_L3_LEN_SHIFT 24
#define HINIC_SQ_TASK_INFO1_INNER_L4LEN_SHIFT 16
#define HINIC_SQ_TASK_INFO1_INNER_L3LEN_SHIFT 24

/* 8 bits reserved */
#define HINIC_SQ_TASK_INFO1_MEDIA_TYPE_MASK 0xFF
#define HINIC_SQ_TASK_INFO1_INNER_L4_LEN_MASK 0xFF
#define HINIC_SQ_TASK_INFO1_INNER_L3_LEN_MASK 0xFF
#define HINIC_SQ_TASK_INFO1_INNER_L4LEN_MASK 0xFF
#define HINIC_SQ_TASK_INFO1_INNER_L3LEN_MASK 0xFF

#define HINIC_SQ_TASK_INFO1_SET(val, member) \
(((u32)(val) & HINIC_SQ_TASK_INFO1_##member##_MASK) << \
HINIC_SQ_TASK_INFO1_##member##_SHIFT)

#define HINIC_SQ_TASK_INFO2_TUNNEL_L4_LEN_SHIFT 0
#define HINIC_SQ_TASK_INFO2_OUTER_L3_LEN_SHIFT 12
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_SHIFT 19
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4LEN_SHIFT 0
#define HINIC_SQ_TASK_INFO2_OUTER_L3LEN_SHIFT 8
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_SHIFT 16
/* 1 bit reserved */
#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_SHIFT 22
#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_SHIFT 24
/* 8 bits reserved */

#define HINIC_SQ_TASK_INFO2_TUNNEL_L4_LEN_MASK 0xFFF
#define HINIC_SQ_TASK_INFO2_OUTER_L3_LEN_MASK 0x7F
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_MASK 0x3
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4LEN_MASK 0xFF
#define HINIC_SQ_TASK_INFO2_OUTER_L3LEN_MASK 0xFF
#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_MASK 0x7
/* 1 bit reserved */
#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_MASK 0x3
/* 8 bits reserved */
Expand Down Expand Up @@ -187,12 +205,15 @@
sizeof(struct hinic_sq_task) + \
(nr_sges) * sizeof(struct hinic_sq_bufdesc))

#define HINIC_SCMD_DATA_LEN 16
#define HINIC_SCMD_DATA_LEN 16

#define HINIC_MAX_SQ_BUFDESCS 17

#define HINIC_MAX_SQ_BUFDESCS 17
#define HINIC_SQ_WQE_MAX_SIZE 320
#define HINIC_RQ_WQE_SIZE 32

#define HINIC_SQ_WQE_MAX_SIZE 320
#define HINIC_RQ_WQE_SIZE 32
#define HINIC_MSS_DEFAULT 0x3E00
#define HINIC_MSS_MIN 0x50

enum hinic_l4offload_type {
HINIC_L4_OFF_DISABLE = 0,
Expand All @@ -211,6 +232,26 @@ enum hinic_pkt_parsed {
HINIC_PKT_PARSED = 1,
};

enum hinic_l3_offload_type {
L3TYPE_UNKNOWN = 0,
IPV6_PKT = 1,
IPV4_PKT_NO_CHKSUM_OFFLOAD = 2,
IPV4_PKT_WITH_CHKSUM_OFFLOAD = 3,
};

enum hinic_l4_offload_type {
OFFLOAD_DISABLE = 0,
TCP_OFFLOAD_ENABLE = 1,
SCTP_OFFLOAD_ENABLE = 2,
UDP_OFFLOAD_ENABLE = 3,
};

enum hinic_l4_tunnel_type {
NOT_TUNNEL,
TUNNEL_UDP_NO_CSUM,
TUNNEL_UDP_CSUM,
};

enum hinic_outer_l3type {
HINIC_OUTER_L3TYPE_UNKNOWN = 0,
HINIC_OUTER_L3TYPE_IPV6 = 1,
Expand Down
Loading

0 comments on commit cc18a75

Please sign in to comment.