/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
 * Copyright(c) 2017 Huawei Technologies Co., Ltd
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 */

#ifndef HINIC_QP_H
#define HINIC_QP_H

#include "hinic_qe_def.h"
#include "hinic_port_cmd.h"

/* frags and linner */
#define HINIC_MAX_SQ_BUFDESCS			(MAX_SKB_FRAGS + 1)
#define HINIC_MAX_SQ_SGE			17
#define HINIC_MAX_SKB_NR_FRAGE			(HINIC_MAX_SQ_SGE - 1)
#define HINIC_GSO_MAX_SIZE			65536

struct hinic_sq_ctrl {
	u32	ctrl_fmt;
	u32	queue_info;
};

struct hinic_sq_task {
	u32	pkt_info0;
	u32	pkt_info1;
	u32	pkt_info2;
	u32	ufo_v6_identify;
	u32	pkt_info4;
	u32	rsvd5;
};

struct hinic_sq_bufdesc {
	u32	hi_addr;
	u32	lo_addr;
	u32	len;
	u32	rsvd;
};

struct hinic_sq_wqe {
	struct hinic_sq_ctrl		ctrl;
	struct hinic_sq_task		task;
	struct hinic_sq_bufdesc		buf_descs[HINIC_MAX_SQ_BUFDESCS];
};

struct hinic_rq_ctrl {
	u32	ctrl_fmt;
};

struct hinic_rq_cqe {
	u32	status;
	u32	vlan_len;

	u32	offload_type;
	u32	hash_val;
	u32	rsvd4;
	u32	rsvd5;
	u32	rsvd6;
	u32	pkt_info;
};

struct hinic_rq_cqe_sect {
	struct hinic_sge	sge;
	u32			rsvd;
};

struct hinic_rq_bufdesc {
	u32	addr_high;
	u32	addr_low;
};

struct hinic_rq_wqe {
	struct hinic_rq_ctrl		ctrl;
	u32				rsvd;
	struct hinic_rq_cqe_sect	cqe_sect;
	struct hinic_rq_bufdesc		buf_desc;
};

void hinic_prepare_sq_ctrl(struct hinic_sq_ctrl *ctrl, u32 queue_info,
			   int nr_descs, u8 owner);

u32 hinic_get_pkt_len(struct hinic_rq_cqe *cqe);

int hinic_get_super_cqe_en(struct hinic_rq_cqe *cqe);

u32 hinic_get_pkt_len_for_super_cqe(struct hinic_rq_cqe *cqe, bool last);

u32 hinic_get_pkt_num(struct hinic_rq_cqe *cqe);

int hinic_get_rx_done(struct hinic_rq_cqe *cqe);

void hinic_clear_rx_done(struct hinic_rq_cqe *cqe, u32 status_old);

void hinic_prepare_rq_wqe(void *wqe, u16 pi, dma_addr_t buf_addr,
			  dma_addr_t cqe_dma);

static inline void hinic_task_set_outter_l3(struct hinic_sq_task *task,
					    enum sq_l3_type l3_type,
					    u32 network_len)
{
	task->pkt_info2 |= SQ_TASK_INFO2_SET(l3_type, OUTER_L3TYPE) |
			SQ_TASK_INFO2_SET(network_len, OUTER_L3LEN);
}

static inline void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
					    enum sq_tunnel_l4_type l4_type,
					    u32 tunnel_len)
{
	task->pkt_info2 |= SQ_TASK_INFO2_SET(l4_type, TUNNEL_L4TYPE) |
			SQ_TASK_INFO2_SET(tunnel_len, TUNNEL_L4LEN);
}

static inline void hinic_task_set_inner_l3(struct hinic_sq_task *task,
					   enum sq_l3_type l3_type,
					   u32 network_len)
{
	task->pkt_info0 |= SQ_TASK_INFO0_SET(l3_type, INNER_L3TYPE);
	task->pkt_info1 |= SQ_TASK_INFO1_SET(network_len, INNER_L3LEN);
}

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

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

void hinic_set_vlan_tx_offload(struct hinic_sq_task *task, u32 *queue_info,
			       u16 vlan_tag, u16 vlan_pri);

void hinic_task_set_tx_offload_valid(struct hinic_sq_task *task, u32 l2hdr_len);

#endif
