ena_eth_com.h revision 361534
1296047Soshogbo/*-
2296047Soshogbo * BSD LICENSE
3296047Soshogbo *
4296047Soshogbo * Copyright (c) 2015-2020 Amazon.com, Inc. or its affiliates.
5296047Soshogbo * All rights reserved.
6296047Soshogbo *
7296047Soshogbo * Redistribution and use in source and binary forms, with or without
8296047Soshogbo * modification, are permitted provided that the following conditions
9296047Soshogbo * are met:
10296047Soshogbo *
11296047Soshogbo * * Redistributions of source code must retain the above copyright
12296047Soshogbo * notice, this list of conditions and the following disclaimer.
13296047Soshogbo * * Redistributions in binary form must reproduce the above copyright
14296047Soshogbo * notice, this list of conditions and the following disclaimer in
15296047Soshogbo * the documentation and/or other materials provided with the
16296047Soshogbo * distribution.
17296047Soshogbo * * Neither the name of copyright holder nor the names of its
18296047Soshogbo * contributors may be used to endorse or promote products derived
19296047Soshogbo * from this software without specific prior written permission.
20296047Soshogbo *
21296047Soshogbo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22296047Soshogbo * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23296047Soshogbo * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24296047Soshogbo * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25296047Soshogbo * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26296047Soshogbo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27296047Soshogbo * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28296047Soshogbo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29296047Soshogbo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30296047Soshogbo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31296047Soshogbo * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32296047Soshogbo */
33296047Soshogbo
34296047Soshogbo#ifndef ENA_ETH_COM_H_
35296047Soshogbo#define ENA_ETH_COM_H_
36296047Soshogbo
37296047Soshogbo#if defined(__cplusplus)
38296047Soshogboextern "C" {
39296047Soshogbo#endif
40296047Soshogbo#include "ena_com.h"
41296047Soshogbo
42296047Soshogbo/* head update threshold in units of (queue size / ENA_COMP_HEAD_THRESH) */
43296047Soshogbo#define ENA_COMP_HEAD_THRESH 4
44296047Soshogbo
45296047Soshogbostruct ena_com_tx_ctx {
46296047Soshogbo	struct ena_com_tx_meta ena_meta;
47296047Soshogbo	struct ena_com_buf *ena_bufs;
48296047Soshogbo	/* For LLQ, header buffer - pushed to the device mem space */
49296047Soshogbo	void *push_header;
50296047Soshogbo
51296047Soshogbo	enum ena_eth_io_l3_proto_index l3_proto;
52296047Soshogbo	enum ena_eth_io_l4_proto_index l4_proto;
53296047Soshogbo	u16 num_bufs;
54296047Soshogbo	u16 req_id;
55296047Soshogbo	/* For regular queue, indicate the size of the header
56296047Soshogbo	 * For LLQ, indicate the size of the pushed buffer
57296047Soshogbo	 */
58296047Soshogbo	u16 header_len;
59296047Soshogbo
60296047Soshogbo	u8 meta_valid;
61296047Soshogbo	u8 tso_enable;
62296047Soshogbo	u8 l3_csum_enable;
63296047Soshogbo	u8 l4_csum_enable;
64296047Soshogbo	u8 l4_csum_partial;
65296047Soshogbo	u8 df; /* Don't fragment */
66296047Soshogbo};
67296047Soshogbo
68296047Soshogbostruct ena_com_rx_ctx {
69296047Soshogbo	struct ena_com_rx_buf_info *ena_bufs;
70296047Soshogbo	enum ena_eth_io_l3_proto_index l3_proto;
71296047Soshogbo	enum ena_eth_io_l4_proto_index l4_proto;
72296047Soshogbo	bool l3_csum_err;
73296047Soshogbo	bool l4_csum_err;
74296047Soshogbo	u8 l4_csum_checked;
75296047Soshogbo	/* fragmented packet */
76296047Soshogbo	bool frag;
77296047Soshogbo	u32 hash;
78296047Soshogbo	u16 descs;
79296047Soshogbo	int max_bufs;
80296047Soshogbo	u8 pkt_offset;
81296047Soshogbo};
82296047Soshogbo
83296047Soshogboint ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
84296047Soshogbo		       struct ena_com_tx_ctx *ena_tx_ctx,
85296047Soshogbo		       int *nb_hw_desc);
86296047Soshogbo
87296047Soshogboint ena_com_rx_pkt(struct ena_com_io_cq *io_cq,
88296047Soshogbo		   struct ena_com_io_sq *io_sq,
89296047Soshogbo		   struct ena_com_rx_ctx *ena_rx_ctx);
90296047Soshogbo
91296047Soshogboint ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
92296047Soshogbo			       struct ena_com_buf *ena_buf,
93296047Soshogbo			       u16 req_id);
94296047Soshogbo
95296047Soshogbobool ena_com_cq_empty(struct ena_com_io_cq *io_cq);
96296047Soshogbo
97296047Soshogbostatic inline void ena_com_unmask_intr(struct ena_com_io_cq *io_cq,
98296047Soshogbo				       struct ena_eth_io_intr_reg *intr_reg)
99296047Soshogbo{
100296047Soshogbo	ENA_REG_WRITE32(io_cq->bus, intr_reg->intr_control, io_cq->unmask_reg);
101296047Soshogbo}
102296047Soshogbo
103296047Soshogbostatic inline int ena_com_free_q_entries(struct ena_com_io_sq *io_sq)
104296047Soshogbo{
105296047Soshogbo	u16 tail, next_to_comp, cnt;
106296047Soshogbo
107296047Soshogbo	next_to_comp = io_sq->next_to_comp;
108296047Soshogbo	tail = io_sq->tail;
109296047Soshogbo	cnt = tail - next_to_comp;
110296047Soshogbo
111296047Soshogbo	return io_sq->q_depth - 1 - cnt;
112296047Soshogbo}
113296047Soshogbo
114296047Soshogbo/* Check if the submission queue has enough space to hold required_buffers */
115296047Soshogbostatic inline bool ena_com_sq_have_enough_space(struct ena_com_io_sq *io_sq,
116296047Soshogbo						u16 required_buffers)
117296047Soshogbo{
118296047Soshogbo	int temp;
119296047Soshogbo
120296047Soshogbo	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
121296047Soshogbo		return ena_com_free_q_entries(io_sq) >= required_buffers;
122296047Soshogbo
123296047Soshogbo	/* This calculation doesn't need to be 100% accurate. So to reduce
124296047Soshogbo	 * the calculation overhead just Subtract 2 lines from the free descs
125296047Soshogbo	 * (one for the header line and one to compensate the devision
126296047Soshogbo	 * down calculation.
127296047Soshogbo	 */
128296047Soshogbo	temp = required_buffers / io_sq->llq_info.descs_per_entry + 2;
129296047Soshogbo
130296047Soshogbo	return ena_com_free_q_entries(io_sq) > temp;
131296047Soshogbo}
132296047Soshogbo
133296047Soshogbostatic inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq,
134296047Soshogbo					     struct ena_com_tx_ctx *ena_tx_ctx)
135296047Soshogbo{
136296047Soshogbo	if (!ena_tx_ctx->meta_valid)
137296047Soshogbo		return false;
138296047Soshogbo
139296047Soshogbo	return !!memcmp(&io_sq->cached_tx_meta,
140296047Soshogbo			&ena_tx_ctx->ena_meta,
141296047Soshogbo			sizeof(struct ena_com_tx_meta));
142296047Soshogbo}
143296047Soshogbo
144296047Soshogbostatic inline bool is_llq_max_tx_burst_exists(struct ena_com_io_sq *io_sq)
145296047Soshogbo{
146296047Soshogbo	return (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) &&
147296047Soshogbo	       io_sq->llq_info.max_entries_in_tx_burst > 0;
148296047Soshogbo}
149296047Soshogbo
150296047Soshogbostatic inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq,
151296047Soshogbo					      struct ena_com_tx_ctx *ena_tx_ctx)
152296047Soshogbo{
153296047Soshogbo	struct ena_com_llq_info *llq_info;
154296047Soshogbo	int descs_after_first_entry;
155296047Soshogbo	int num_entries_needed = 1;
156296047Soshogbo	u16 num_descs;
157296047Soshogbo
158296047Soshogbo	if (!is_llq_max_tx_burst_exists(io_sq))
159296047Soshogbo		return false;
160296047Soshogbo
161296047Soshogbo	llq_info = &io_sq->llq_info;
162296047Soshogbo	num_descs = ena_tx_ctx->num_bufs;
163296047Soshogbo
164296047Soshogbo	if (llq_info->disable_meta_caching ||
165296047Soshogbo	    unlikely(ena_com_meta_desc_changed(io_sq, ena_tx_ctx)))
166296047Soshogbo		++num_descs;
167296047Soshogbo
168296047Soshogbo	if (num_descs > llq_info->descs_num_before_header) {
169296047Soshogbo		descs_after_first_entry = num_descs - llq_info->descs_num_before_header;
170296047Soshogbo		num_entries_needed += DIV_ROUND_UP(descs_after_first_entry,
171296047Soshogbo						   llq_info->descs_per_entry);
172296047Soshogbo	}
173296047Soshogbo
174296047Soshogbo	ena_trc_dbg("queue: %d num_descs: %d num_entries_needed: %d\n",
175296047Soshogbo		    io_sq->qid, num_descs, num_entries_needed);
176296047Soshogbo
177296047Soshogbo	return num_entries_needed > io_sq->entries_in_tx_burst_left;
178296047Soshogbo}
179296047Soshogbo
180296047Soshogbostatic inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq)
181296047Soshogbo{
182296047Soshogbo	u16 max_entries_in_tx_burst = io_sq->llq_info.max_entries_in_tx_burst;
183296047Soshogbo	u16 tail = io_sq->tail;
184296047Soshogbo
185296047Soshogbo	ena_trc_dbg("write submission queue doorbell for queue: %d tail: %d\n",
186296047Soshogbo		    io_sq->qid, tail);
187296047Soshogbo
188296047Soshogbo	ENA_REG_WRITE32(io_sq->bus, tail, io_sq->db_addr);
189296047Soshogbo
190296047Soshogbo	if (is_llq_max_tx_burst_exists(io_sq)) {
191296047Soshogbo		ena_trc_dbg("reset available entries in tx burst for queue %d to %d\n",
192296047Soshogbo			     io_sq->qid, max_entries_in_tx_burst);
193296047Soshogbo		io_sq->entries_in_tx_burst_left = max_entries_in_tx_burst;
194296047Soshogbo	}
195296047Soshogbo
196296047Soshogbo	return 0;
197296047Soshogbo}
198296047Soshogbo
199296047Soshogbostatic inline int ena_com_update_dev_comp_head(struct ena_com_io_cq *io_cq)
200296047Soshogbo{
201296047Soshogbo	u16 unreported_comp, head;
202296047Soshogbo	bool need_update;
203296047Soshogbo
204296047Soshogbo	if (unlikely(io_cq->cq_head_db_reg)) {
205296047Soshogbo		head = io_cq->head;
206296047Soshogbo		unreported_comp = head - io_cq->last_head_update;
207296047Soshogbo		need_update = unreported_comp > (io_cq->q_depth / ENA_COMP_HEAD_THRESH);
208296047Soshogbo
209296047Soshogbo		if (unlikely(need_update)) {
210296047Soshogbo			ena_trc_dbg("Write completion queue doorbell for queue %d: head: %d\n",
211296047Soshogbo				    io_cq->qid, head);
212296047Soshogbo			ENA_REG_WRITE32(io_cq->bus, head, io_cq->cq_head_db_reg);
213296047Soshogbo			io_cq->last_head_update = head;
214296047Soshogbo		}
215296047Soshogbo	}
216296047Soshogbo
217296047Soshogbo	return 0;
218296047Soshogbo}
219296047Soshogbo
220296047Soshogbostatic inline void ena_com_update_numa_node(struct ena_com_io_cq *io_cq,
221296047Soshogbo					    u8 numa_node)
222296047Soshogbo{
223296047Soshogbo	struct ena_eth_io_numa_node_cfg_reg numa_cfg;
224296047Soshogbo
225296047Soshogbo	if (!io_cq->numa_node_cfg_reg)
226296047Soshogbo		return;
227296047Soshogbo
228296047Soshogbo	numa_cfg.numa_cfg = (numa_node & ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK)
229296047Soshogbo		| ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK;
230296047Soshogbo
231296047Soshogbo	ENA_REG_WRITE32(io_cq->bus, numa_cfg.numa_cfg, io_cq->numa_node_cfg_reg);
232296047Soshogbo}
233296047Soshogbo
234296047Soshogbostatic inline void ena_com_comp_ack(struct ena_com_io_sq *io_sq, u16 elem)
235296047Soshogbo{
236296047Soshogbo	io_sq->next_to_comp += elem;
237296047Soshogbo}
238296047Soshogbo
239296047Soshogbostatic inline void ena_com_cq_inc_head(struct ena_com_io_cq *io_cq)
240296047Soshogbo{
241296047Soshogbo	io_cq->head++;
242296047Soshogbo
243296047Soshogbo	/* Switch phase bit in case of wrap around */
244296047Soshogbo	if (unlikely((io_cq->head & (io_cq->q_depth - 1)) == 0))
245296047Soshogbo		io_cq->phase ^= 1;
246296047Soshogbo}
247296047Soshogbo
248296047Soshogbostatic inline int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq,
249296047Soshogbo					     u16 *req_id)
250296047Soshogbo{
251296047Soshogbo	u8 expected_phase, cdesc_phase;
252296047Soshogbo	struct ena_eth_io_tx_cdesc *cdesc;
253296047Soshogbo	u16 masked_head;
254296047Soshogbo
255296047Soshogbo	masked_head = io_cq->head & (io_cq->q_depth - 1);
256296047Soshogbo	expected_phase = io_cq->phase;
257296047Soshogbo
258296047Soshogbo	cdesc = (struct ena_eth_io_tx_cdesc *)
259296047Soshogbo		((uintptr_t)io_cq->cdesc_addr.virt_addr +
260296047Soshogbo		(masked_head * io_cq->cdesc_entry_size_in_bytes));
261296047Soshogbo
262296047Soshogbo	/* When the current completion descriptor phase isn't the same as the
263296047Soshogbo	 * expected, it mean that the device still didn't update
264296047Soshogbo	 * this completion.
265296047Soshogbo	 */
266296047Soshogbo	cdesc_phase = READ_ONCE16(cdesc->flags) & ENA_ETH_IO_TX_CDESC_PHASE_MASK;
267296047Soshogbo	if (cdesc_phase != expected_phase)
268296047Soshogbo		return ENA_COM_TRY_AGAIN;
269296047Soshogbo
270296047Soshogbo	dma_rmb();
271296047Soshogbo
272296047Soshogbo	*req_id = READ_ONCE16(cdesc->req_id);
273296047Soshogbo	if (unlikely(*req_id >= io_cq->q_depth)) {
274296047Soshogbo		ena_trc_err("Invalid req id %d\n", cdesc->req_id);
275296047Soshogbo		return ENA_COM_INVAL;
276296047Soshogbo	}
277296047Soshogbo
278296047Soshogbo	ena_com_cq_inc_head(io_cq);
279296047Soshogbo
280296047Soshogbo	return 0;
281296047Soshogbo}
282296047Soshogbo
283296047Soshogbo#if defined(__cplusplus)
284296047Soshogbo}
285296047Soshogbo#endif
286296047Soshogbo#endif /* ENA_ETH_COM_H_ */
287296047Soshogbo