Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2017 Huawei Technologies Co., Ltd
3 : : */
4 : :
5 : : #include "hinic_compat.h"
6 : : #include "hinic_pmd_hwdev.h"
7 : : #include "hinic_pmd_hwif.h"
8 : : #include "hinic_pmd_wq.h"
9 : : #include "hinic_pmd_mgmt.h"
10 : : #include "hinic_pmd_mbox.h"
11 : : #include "hinic_pmd_cmdq.h"
12 : :
13 : : #define CMDQ_CMD_TIMEOUT 5000 /* millisecond */
14 : :
15 : : #define UPPER_8_BITS(data) (((data) >> 8) & 0xFF)
16 : : #define LOWER_8_BITS(data) ((data) & 0xFF)
17 : :
18 : : #define CMDQ_DB_INFO_HI_PROD_IDX_SHIFT 0
19 : : #define CMDQ_DB_INFO_QUEUE_TYPE_SHIFT 23
20 : : #define CMDQ_DB_INFO_CMDQ_TYPE_SHIFT 24
21 : : #define CMDQ_DB_INFO_SRC_TYPE_SHIFT 27
22 : :
23 : : #define CMDQ_DB_INFO_HI_PROD_IDX_MASK 0xFFU
24 : : #define CMDQ_DB_INFO_QUEUE_TYPE_MASK 0x1U
25 : : #define CMDQ_DB_INFO_CMDQ_TYPE_MASK 0x7U
26 : : #define CMDQ_DB_INFO_SRC_TYPE_MASK 0x1FU
27 : :
28 : : #define CMDQ_DB_INFO_SET(val, member) \
29 : : (((val) & CMDQ_DB_INFO_##member##_MASK) << \
30 : : CMDQ_DB_INFO_##member##_SHIFT)
31 : :
32 : : #define CMDQ_CTRL_PI_SHIFT 0
33 : : #define CMDQ_CTRL_CMD_SHIFT 16
34 : : #define CMDQ_CTRL_MOD_SHIFT 24
35 : : #define CMDQ_CTRL_ACK_TYPE_SHIFT 29
36 : : #define CMDQ_CTRL_HW_BUSY_BIT_SHIFT 31
37 : :
38 : : #define CMDQ_CTRL_PI_MASK 0xFFFFU
39 : : #define CMDQ_CTRL_CMD_MASK 0xFFU
40 : : #define CMDQ_CTRL_MOD_MASK 0x1FU
41 : : #define CMDQ_CTRL_ACK_TYPE_MASK 0x3U
42 : : #define CMDQ_CTRL_HW_BUSY_BIT_MASK 0x1U
43 : :
44 : : #define CMDQ_CTRL_SET(val, member) \
45 : : (((val) & CMDQ_CTRL_##member##_MASK) << CMDQ_CTRL_##member##_SHIFT)
46 : :
47 : : #define CMDQ_CTRL_GET(val, member) \
48 : : (((val) >> CMDQ_CTRL_##member##_SHIFT) & CMDQ_CTRL_##member##_MASK)
49 : :
50 : : #define CMDQ_WQE_HEADER_BUFDESC_LEN_SHIFT 0
51 : : #define CMDQ_WQE_HEADER_COMPLETE_FMT_SHIFT 15
52 : : #define CMDQ_WQE_HEADER_DATA_FMT_SHIFT 22
53 : : #define CMDQ_WQE_HEADER_COMPLETE_REQ_SHIFT 23
54 : : #define CMDQ_WQE_HEADER_COMPLETE_SECT_LEN_SHIFT 27
55 : : #define CMDQ_WQE_HEADER_CTRL_LEN_SHIFT 29
56 : : #define CMDQ_WQE_HEADER_HW_BUSY_BIT_SHIFT 31
57 : :
58 : : #define CMDQ_WQE_HEADER_BUFDESC_LEN_MASK 0xFFU
59 : : #define CMDQ_WQE_HEADER_COMPLETE_FMT_MASK 0x1U
60 : : #define CMDQ_WQE_HEADER_DATA_FMT_MASK 0x1U
61 : : #define CMDQ_WQE_HEADER_COMPLETE_REQ_MASK 0x1U
62 : : #define CMDQ_WQE_HEADER_COMPLETE_SECT_LEN_MASK 0x3U
63 : : #define CMDQ_WQE_HEADER_CTRL_LEN_MASK 0x3U
64 : : #define CMDQ_WQE_HEADER_HW_BUSY_BIT_MASK 0x1U
65 : :
66 : : #define CMDQ_WQE_HEADER_SET(val, member) \
67 : : (((val) & CMDQ_WQE_HEADER_##member##_MASK) << \
68 : : CMDQ_WQE_HEADER_##member##_SHIFT)
69 : :
70 : : #define CMDQ_WQE_HEADER_GET(val, member) \
71 : : (((val) >> CMDQ_WQE_HEADER_##member##_SHIFT) & \
72 : : CMDQ_WQE_HEADER_##member##_MASK)
73 : :
74 : : #define CMDQ_CTXT_CURR_WQE_PAGE_PFN_SHIFT 0
75 : : #define CMDQ_CTXT_EQ_ID_SHIFT 56
76 : : #define CMDQ_CTXT_CEQ_ARM_SHIFT 61
77 : : #define CMDQ_CTXT_CEQ_EN_SHIFT 62
78 : : #define CMDQ_CTXT_HW_BUSY_BIT_SHIFT 63
79 : :
80 : : #define CMDQ_CTXT_CURR_WQE_PAGE_PFN_MASK 0xFFFFFFFFFFFFF
81 : : #define CMDQ_CTXT_EQ_ID_MASK 0x1F
82 : : #define CMDQ_CTXT_CEQ_ARM_MASK 0x1
83 : : #define CMDQ_CTXT_CEQ_EN_MASK 0x1
84 : : #define CMDQ_CTXT_HW_BUSY_BIT_MASK 0x1
85 : :
86 : : #define CMDQ_CTXT_PAGE_INFO_SET(val, member) \
87 : : (((u64)(val) & CMDQ_CTXT_##member##_MASK) << CMDQ_CTXT_##member##_SHIFT)
88 : :
89 : : #define CMDQ_CTXT_PAGE_INFO_CLEAR(val, member) \
90 : : ((val) & (~((u64)CMDQ_CTXT_##member##_MASK << \
91 : : CMDQ_CTXT_##member##_SHIFT)))
92 : :
93 : : #define CMDQ_CTXT_WQ_BLOCK_PFN_SHIFT 0
94 : : #define CMDQ_CTXT_CI_SHIFT 52
95 : :
96 : : #define CMDQ_CTXT_WQ_BLOCK_PFN_MASK 0xFFFFFFFFFFFFF
97 : : #define CMDQ_CTXT_CI_MASK 0xFFF
98 : :
99 : : #define CMDQ_CTXT_BLOCK_INFO_SET(val, member) \
100 : : (((u64)(val) & CMDQ_CTXT_##member##_MASK) << CMDQ_CTXT_##member##_SHIFT)
101 : :
102 : : #define SAVED_DATA_ARM_SHIFT 31
103 : :
104 : : #define SAVED_DATA_ARM_MASK 0x1U
105 : :
106 : : #define SAVED_DATA_SET(val, member) \
107 : : (((val) & SAVED_DATA_##member##_MASK) << SAVED_DATA_##member##_SHIFT)
108 : :
109 : : #define SAVED_DATA_CLEAR(val, member) \
110 : : ((val) & (~(SAVED_DATA_##member##_MASK << SAVED_DATA_##member##_SHIFT)))
111 : :
112 : : #define WQE_ERRCODE_VAL_SHIFT 20
113 : :
114 : : #define WQE_ERRCODE_VAL_MASK 0xF
115 : :
116 : : #define WQE_ERRCODE_GET(val, member) \
117 : : (((val) >> WQE_ERRCODE_##member##_SHIFT) & WQE_ERRCODE_##member##_MASK)
118 : :
119 : : #define WQE_COMPLETED(ctrl_info) CMDQ_CTRL_GET(ctrl_info, HW_BUSY_BIT)
120 : :
121 : : #define WQE_HEADER(wqe) ((struct hinic_cmdq_header *)(wqe))
122 : :
123 : : #define CMDQ_DB_PI_OFF(pi) (((u16)LOWER_8_BITS(pi)) << 3)
124 : :
125 : : #define CMDQ_DB_ADDR(db_base, pi) \
126 : : (((u8 *)(db_base) + HINIC_DB_OFF) + CMDQ_DB_PI_OFF(pi))
127 : :
128 : : #define CMDQ_PFN(addr, page_size) ((addr) >> (ilog2(page_size)))
129 : :
130 : : #define FIRST_DATA_TO_WRITE_LAST sizeof(u64)
131 : :
132 : : #define WQE_LCMD_SIZE 64
133 : : #define WQE_SCMD_SIZE 64
134 : :
135 : : #define COMPLETE_LEN 3
136 : :
137 : : #define CMDQ_WQEBB_SIZE 64
138 : : #define CMDQ_WQEBB_SHIFT 6
139 : :
140 : : #define CMDQ_WQE_SIZE 64
141 : :
142 : : #define HINIC_CMDQ_WQ_BUF_SIZE 4096
143 : :
144 : : #define WQE_NUM_WQEBBS(wqe_size, wq) \
145 : : ((u16)(ALIGN((u32)(wqe_size), (wq)->wqebb_size) / (wq)->wqebb_size))
146 : :
147 : : #define cmdq_to_cmdqs(cmdq) container_of((cmdq) - (cmdq)->cmdq_type, \
148 : : struct hinic_cmdqs, cmdq[0])
149 : :
150 : : #define WAIT_CMDQ_ENABLE_TIMEOUT 300
151 : :
152 : :
153 : : static void cmdq_init_queue_ctxt(struct hinic_cmdq *cmdq,
154 : : struct hinic_cmdq_ctxt *cmdq_ctxt);
155 : : static void hinic_cmdqs_free(struct hinic_hwdev *hwdev);
156 : :
157 : 0 : bool hinic_cmdq_idle(struct hinic_cmdq *cmdq)
158 : : {
159 : 0 : struct hinic_wq *wq = cmdq->wq;
160 : :
161 : 0 : return ((wq->delta) == wq->q_depth ? true : false);
162 : : }
163 : :
164 : 0 : struct hinic_cmd_buf *hinic_alloc_cmd_buf(void *hwdev)
165 : : {
166 : 0 : struct hinic_cmdqs *cmdqs = ((struct hinic_hwdev *)hwdev)->cmdqs;
167 : : struct hinic_cmd_buf *cmd_buf;
168 : :
169 : 0 : cmd_buf = kzalloc(sizeof(*cmd_buf), GFP_KERNEL);
170 [ # # ]: 0 : if (!cmd_buf) {
171 : 0 : PMD_DRV_LOG(ERR, "Allocate cmd buffer failed");
172 : 0 : return NULL;
173 : : }
174 : :
175 : 0 : cmd_buf->buf = pci_pool_alloc(cmdqs->cmd_buf_pool, &cmd_buf->dma_addr);
176 [ # # ]: 0 : if (!cmd_buf->buf) {
177 : 0 : PMD_DRV_LOG(ERR, "Allocate cmd from the pool failed");
178 : 0 : goto alloc_pci_buf_err;
179 : : }
180 : :
181 : : return cmd_buf;
182 : :
183 : : alloc_pci_buf_err:
184 : 0 : kfree(cmd_buf);
185 : 0 : return NULL;
186 : : }
187 : :
188 : 0 : void hinic_free_cmd_buf(void *hwdev, struct hinic_cmd_buf *cmd_buf)
189 : : {
190 : 0 : struct hinic_cmdqs *cmdqs = ((struct hinic_hwdev *)hwdev)->cmdqs;
191 : :
192 : 0 : pci_pool_free(cmdqs->cmd_buf_pool, cmd_buf->buf, cmd_buf->dma_addr);
193 : 0 : kfree(cmd_buf);
194 : 0 : }
195 : :
196 : : static u32 cmdq_wqe_size(enum cmdq_wqe_type wqe_type)
197 : : {
198 : : u32 wqe_size = 0;
199 : :
200 : : switch (wqe_type) {
201 : : case WQE_LCMD_TYPE:
202 : : wqe_size = WQE_LCMD_SIZE;
203 : : break;
204 : : case WQE_SCMD_TYPE:
205 : : wqe_size = WQE_SCMD_SIZE;
206 : : break;
207 : : }
208 : :
209 : : return wqe_size;
210 : : }
211 : :
212 : : static int cmdq_get_wqe_size(enum bufdesc_len len)
213 : : {
214 : : int wqe_size = 0;
215 : :
216 : 0 : switch (len) {
217 : : case BUFDESC_LCMD_LEN:
218 : : wqe_size = WQE_LCMD_SIZE;
219 : : break;
220 : : case BUFDESC_SCMD_LEN:
221 : : wqe_size = WQE_SCMD_SIZE;
222 : : break;
223 : : }
224 : :
225 : : return wqe_size;
226 : : }
227 : :
228 : : static void cmdq_set_completion(struct hinic_cmdq_completion *complete,
229 : : struct hinic_cmd_buf *buf_out)
230 : : {
231 : : struct hinic_sge_resp *sge_resp = &complete->sge_resp;
232 : :
233 : 0 : hinic_set_sge(&sge_resp->sge, buf_out->dma_addr,
234 : : HINIC_CMDQ_BUF_SIZE);
235 : 0 : }
236 : :
237 : : static void cmdq_set_lcmd_bufdesc(struct hinic_cmdq_wqe_lcmd *wqe,
238 : : struct hinic_cmd_buf *buf_in)
239 : : {
240 : 0 : hinic_set_sge(&wqe->buf_desc.sge, buf_in->dma_addr, buf_in->size);
241 : : }
242 : :
243 : : static void cmdq_fill_db(struct hinic_cmdq_db *db,
244 : : enum hinic_cmdq_type cmdq_type, u16 prod_idx)
245 : : {
246 : 0 : db->db_info = CMDQ_DB_INFO_SET(UPPER_8_BITS(prod_idx), HI_PROD_IDX) |
247 : 0 : CMDQ_DB_INFO_SET(HINIC_DB_CMDQ_TYPE, QUEUE_TYPE) |
248 : 0 : CMDQ_DB_INFO_SET(cmdq_type, CMDQ_TYPE) |
249 : : CMDQ_DB_INFO_SET(HINIC_DB_SRC_CMDQ_TYPE, SRC_TYPE);
250 : : }
251 : :
252 : 0 : static void cmdq_set_db(struct hinic_cmdq *cmdq,
253 : : enum hinic_cmdq_type cmdq_type, u16 prod_idx)
254 : : {
255 : : struct hinic_cmdq_db db;
256 : :
257 : 0 : cmdq_fill_db(&db, cmdq_type, prod_idx);
258 : :
259 : : /* The data that is written to HW should be in Big Endian Format */
260 [ # # ]: 0 : db.db_info = cpu_to_be32(db.db_info);
261 : :
262 : : rte_wmb(); /* write all before the doorbell */
263 : :
264 : 0 : writel(db.db_info, CMDQ_DB_ADDR(cmdq->db_base, prod_idx));
265 : 0 : }
266 : :
267 : : static void cmdq_wqe_fill(void *dst, void *src)
268 : : {
269 : 0 : memcpy((u8 *)dst + FIRST_DATA_TO_WRITE_LAST,
270 : : (u8 *)src + FIRST_DATA_TO_WRITE_LAST,
271 : : CMDQ_WQE_SIZE - FIRST_DATA_TO_WRITE_LAST);
272 : :
273 : : rte_wmb();/* The first 8 bytes should be written last */
274 : :
275 : 0 : *(u64 *)dst = *(u64 *)src;
276 : : }
277 : :
278 : 0 : static void cmdq_prepare_wqe_ctrl(struct hinic_cmdq_wqe *wqe, int wrapped,
279 : : enum hinic_ack_type ack_type,
280 : : enum hinic_mod_type mod, u8 cmd, u16 prod_idx,
281 : : enum completion_format complete_format,
282 : : enum data_format local_data_format,
283 : : enum bufdesc_len buf_len)
284 : : {
285 : : struct hinic_ctrl *ctrl;
286 : : enum ctrl_sect_len ctrl_len;
287 : : struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
288 : : struct hinic_cmdq_wqe_scmd *wqe_scmd;
289 : 0 : u32 saved_data = WQE_HEADER(wqe)->saved_data;
290 : :
291 [ # # ]: 0 : if (local_data_format == DATA_SGE) {
292 : : wqe_lcmd = &wqe->wqe_lcmd;
293 : :
294 : 0 : wqe_lcmd->status.status_info = 0;
295 : 0 : ctrl = &wqe_lcmd->ctrl;
296 : : ctrl_len = CTRL_SECT_LEN;
297 : : } else {
298 : : wqe_scmd = &wqe->inline_wqe.wqe_scmd;
299 : :
300 : 0 : wqe_scmd->status.status_info = 0;
301 : 0 : ctrl = &wqe_scmd->ctrl;
302 : : ctrl_len = CTRL_DIRECT_SECT_LEN;
303 : : }
304 : :
305 : 0 : ctrl->ctrl_info = CMDQ_CTRL_SET(prod_idx, PI) |
306 : 0 : CMDQ_CTRL_SET(cmd, CMD) |
307 : 0 : CMDQ_CTRL_SET(mod, MOD) |
308 : 0 : CMDQ_CTRL_SET(ack_type, ACK_TYPE);
309 : :
310 : 0 : WQE_HEADER(wqe)->header_info =
311 : 0 : CMDQ_WQE_HEADER_SET(buf_len, BUFDESC_LEN) |
312 : 0 : CMDQ_WQE_HEADER_SET(complete_format, COMPLETE_FMT) |
313 : 0 : CMDQ_WQE_HEADER_SET(local_data_format, DATA_FMT) |
314 : : CMDQ_WQE_HEADER_SET(CEQ_SET, COMPLETE_REQ) |
315 : 0 : CMDQ_WQE_HEADER_SET(COMPLETE_LEN, COMPLETE_SECT_LEN) |
316 : 0 : CMDQ_WQE_HEADER_SET(ctrl_len, CTRL_LEN) |
317 : 0 : CMDQ_WQE_HEADER_SET((u32)wrapped, HW_BUSY_BIT);
318 : :
319 [ # # ]: 0 : if (cmd == CMDQ_SET_ARM_CMD && mod == HINIC_MOD_COMM) {
320 : 0 : saved_data &= SAVED_DATA_CLEAR(saved_data, ARM);
321 : 0 : WQE_HEADER(wqe)->saved_data = saved_data |
322 : : SAVED_DATA_SET(1, ARM);
323 : : } else {
324 : 0 : saved_data &= SAVED_DATA_CLEAR(saved_data, ARM);
325 : 0 : WQE_HEADER(wqe)->saved_data = saved_data;
326 : : }
327 : 0 : }
328 : :
329 : 0 : static void cmdq_set_lcmd_wqe(struct hinic_cmdq_wqe *wqe,
330 : : enum cmdq_cmd_type cmd_type,
331 : : struct hinic_cmd_buf *buf_in,
332 : : struct hinic_cmd_buf *buf_out, int wrapped,
333 : : enum hinic_ack_type ack_type,
334 : : enum hinic_mod_type mod, u8 cmd, u16 prod_idx)
335 : : {
336 : : struct hinic_cmdq_wqe_lcmd *wqe_lcmd = &wqe->wqe_lcmd;
337 : : enum completion_format complete_format = COMPLETE_DIRECT;
338 : :
339 [ # # # # ]: 0 : switch (cmd_type) {
340 : 0 : case SYNC_CMD_SGE_RESP:
341 [ # # ]: 0 : if (buf_out) {
342 : : complete_format = COMPLETE_SGE;
343 : : cmdq_set_completion(&wqe_lcmd->completion, buf_out);
344 : : }
345 : : break;
346 : 0 : case SYNC_CMD_DIRECT_RESP:
347 : : complete_format = COMPLETE_DIRECT;
348 : 0 : wqe_lcmd->completion.direct_resp = 0;
349 : 0 : break;
350 : 0 : case ASYNC_CMD:
351 : : complete_format = COMPLETE_DIRECT;
352 : 0 : wqe_lcmd->completion.direct_resp = 0;
353 : :
354 : 0 : wqe_lcmd->buf_desc.saved_async_buf = (u64)(buf_in);
355 : 0 : break;
356 : : }
357 : :
358 : 0 : cmdq_prepare_wqe_ctrl(wqe, wrapped, ack_type, mod, cmd,
359 : : prod_idx, complete_format, DATA_SGE,
360 : : BUFDESC_LCMD_LEN);
361 : :
362 : : cmdq_set_lcmd_bufdesc(wqe_lcmd, buf_in);
363 : 0 : }
364 : :
365 : : static int cmdq_params_valid(struct hinic_cmd_buf *buf_in)
366 : : {
367 : 0 : if (buf_in->size > HINIC_CMDQ_MAX_DATA_SIZE) {
368 : 0 : PMD_DRV_LOG(ERR, "Invalid CMDQ buffer size");
369 : : return -EINVAL;
370 : : }
371 : :
372 : : return 0;
373 : : }
374 : :
375 : 0 : static int wait_cmdqs_enable(struct hinic_cmdqs *cmdqs)
376 : : {
377 : : unsigned long end;
378 : :
379 : 0 : end = jiffies + msecs_to_jiffies(WAIT_CMDQ_ENABLE_TIMEOUT);
380 : : do {
381 [ # # ]: 0 : if (cmdqs->status & HINIC_CMDQ_ENABLE)
382 : : return 0;
383 : :
384 [ # # ]: 0 : } while (time_before(jiffies, end));
385 : :
386 : : return -EBUSY;
387 : : }
388 : :
389 : : static void cmdq_update_errcode(struct hinic_cmdq *cmdq, u16 prod_idx,
390 : : int errcode)
391 : : {
392 : 0 : cmdq->errcode[prod_idx] = errcode;
393 : : }
394 : :
395 : 0 : static void clear_wqe_complete_bit(struct hinic_cmdq *cmdq,
396 : : struct hinic_cmdq_wqe *wqe)
397 : : {
398 : : struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
399 : : struct hinic_cmdq_inline_wqe *inline_wqe;
400 : : struct hinic_cmdq_wqe_scmd *wqe_scmd;
401 : : struct hinic_ctrl *ctrl;
402 [ # # ]: 0 : u32 header_info = be32_to_cpu(WQE_HEADER(wqe)->header_info);
403 [ # # ]: 0 : int buf_len = CMDQ_WQE_HEADER_GET(header_info, BUFDESC_LEN);
404 : : int wqe_size = cmdq_get_wqe_size(buf_len);
405 : : u16 num_wqebbs;
406 : :
407 : : if (wqe_size == WQE_LCMD_SIZE) {
408 : : wqe_lcmd = &wqe->wqe_lcmd;
409 : 0 : ctrl = &wqe_lcmd->ctrl;
410 : : } else {
411 : : inline_wqe = &wqe->inline_wqe;
412 : : wqe_scmd = &inline_wqe->wqe_scmd;
413 : 0 : ctrl = &wqe_scmd->ctrl;
414 : : }
415 : :
416 : : /* clear HW busy bit */
417 : 0 : ctrl->ctrl_info = 0;
418 : :
419 : : rte_wmb(); /* verify wqe is clear */
420 : :
421 : 0 : num_wqebbs = WQE_NUM_WQEBBS(wqe_size, cmdq->wq);
422 : 0 : hinic_put_wqe(cmdq->wq, num_wqebbs);
423 : 0 : }
424 : :
425 : 0 : static int hinic_set_cmdq_ctxts(struct hinic_hwdev *hwdev)
426 : : {
427 : 0 : struct hinic_cmdqs *cmdqs = hwdev->cmdqs;
428 : : struct hinic_cmdq_ctxt *cmdq_ctxt;
429 : : struct hinic_cmdq_ctxt cmdq_ctxt_out;
430 : : enum hinic_cmdq_type cmdq_type;
431 : 0 : u16 out_size = sizeof(cmdq_ctxt_out);
432 : : u16 in_size;
433 : : int err;
434 : :
435 : : cmdq_type = HINIC_CMDQ_SYNC;
436 : : memset(&cmdq_ctxt_out, 0, out_size);
437 [ # # ]: 0 : for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
438 : 0 : cmdq_ctxt = &cmdqs->cmdq[cmdq_type].cmdq_ctxt;
439 : 0 : cmdq_ctxt->resp_aeq_num = HINIC_AEQ1;
440 : : in_size = sizeof(*cmdq_ctxt);
441 : 0 : err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
442 : : HINIC_MGMT_CMD_CMDQ_CTXT_SET,
443 : : cmdq_ctxt, in_size, &cmdq_ctxt_out,
444 : : &out_size, 0);
445 [ # # # # : 0 : if (err || !out_size || cmdq_ctxt_out.status) {
# # ]
446 : 0 : if (err == HINIC_MBOX_PF_BUSY_ACTIVE_FW ||
447 [ # # ]: 0 : err == HINIC_DEV_BUSY_ACTIVE_FW) {
448 : 0 : cmdqs->status |= HINIC_CMDQ_SET_FAIL;
449 : 0 : PMD_DRV_LOG(ERR, "PF or VF fw is hot active");
450 : : }
451 : 0 : PMD_DRV_LOG(ERR, "Set cmdq ctxt failed, err: %d, status: 0x%x, out_size: 0x%x",
452 : : err, cmdq_ctxt_out.status, out_size);
453 : 0 : return -EIO;
454 : : }
455 : : }
456 : :
457 : 0 : cmdqs->status &= ~HINIC_CMDQ_SET_FAIL;
458 : 0 : cmdqs->status |= HINIC_CMDQ_ENABLE;
459 : :
460 : 0 : return 0;
461 : : }
462 : :
463 : 0 : void hinic_comm_cmdqs_free(struct hinic_hwdev *hwdev)
464 : : {
465 : 0 : hinic_cmdqs_free(hwdev);
466 : 0 : }
467 : :
468 : 0 : int hinic_reinit_cmdq_ctxts(struct hinic_hwdev *hwdev)
469 : : {
470 : 0 : struct hinic_cmdqs *cmdqs = hwdev->cmdqs;
471 : : enum hinic_cmdq_type cmdq_type;
472 : :
473 : : cmdq_type = HINIC_CMDQ_SYNC;
474 [ # # ]: 0 : for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
475 : 0 : cmdqs->cmdq[cmdq_type].wrapped = 1;
476 : 0 : hinic_wq_wqe_pg_clear(cmdqs->cmdq[cmdq_type].wq);
477 : : }
478 : :
479 : 0 : return hinic_set_cmdq_ctxts(hwdev);
480 : : }
481 : :
482 : 0 : static int init_cmdq(struct hinic_cmdq *cmdq, struct hinic_hwdev *hwdev,
483 : : struct hinic_wq *wq, enum hinic_cmdq_type q_type)
484 : : {
485 : : void __iomem *db_base;
486 : : int err = 0;
487 : : size_t errcode_size;
488 : : size_t cmd_infos_size;
489 : :
490 : 0 : cmdq->wq = wq;
491 : 0 : cmdq->cmdq_type = q_type;
492 : 0 : cmdq->wrapped = 1;
493 : :
494 : : spin_lock_init(&cmdq->cmdq_lock);
495 : :
496 : 0 : errcode_size = wq->q_depth * sizeof(*cmdq->errcode);
497 : 0 : cmdq->errcode = kzalloc(errcode_size, GFP_KERNEL);
498 [ # # ]: 0 : if (!cmdq->errcode) {
499 : 0 : PMD_DRV_LOG(ERR, "Allocate errcode for cmdq failed");
500 : : spin_lock_deinit(&cmdq->cmdq_lock);
501 : 0 : return -ENOMEM;
502 : : }
503 : :
504 : 0 : cmd_infos_size = wq->q_depth * sizeof(*cmdq->cmd_infos);
505 : 0 : cmdq->cmd_infos = kzalloc(cmd_infos_size, GFP_KERNEL);
506 [ # # ]: 0 : if (!cmdq->cmd_infos) {
507 : 0 : PMD_DRV_LOG(ERR, "Allocate errcode for cmdq failed");
508 : : err = -ENOMEM;
509 : 0 : goto cmd_infos_err;
510 : : }
511 : :
512 : 0 : err = hinic_alloc_db_addr(hwdev, &db_base);
513 [ # # ]: 0 : if (err)
514 : 0 : goto alloc_db_err;
515 : :
516 : 0 : cmdq->db_base = (u8 *)db_base;
517 : 0 : return 0;
518 : :
519 : : alloc_db_err:
520 : 0 : kfree(cmdq->cmd_infos);
521 : :
522 : 0 : cmd_infos_err:
523 : 0 : kfree(cmdq->errcode);
524 : : spin_lock_deinit(&cmdq->cmdq_lock);
525 : :
526 : 0 : return err;
527 : : }
528 : :
529 : 0 : static void free_cmdq(struct hinic_hwdev *hwdev, struct hinic_cmdq *cmdq)
530 : : {
531 : 0 : hinic_free_db_addr(hwdev, cmdq->db_base);
532 : 0 : kfree(cmdq->cmd_infos);
533 : 0 : kfree(cmdq->errcode);
534 : : spin_lock_deinit(&cmdq->cmdq_lock);
535 : 0 : }
536 : :
537 : 0 : static int hinic_cmdqs_init(struct hinic_hwdev *hwdev)
538 : : {
539 : : struct hinic_cmdqs *cmdqs;
540 : : struct hinic_cmdq_ctxt *cmdq_ctxt;
541 : : enum hinic_cmdq_type type, cmdq_type;
542 : : size_t saved_wqs_size;
543 : : int err;
544 : :
545 : 0 : cmdqs = kzalloc(sizeof(*cmdqs), GFP_KERNEL);
546 [ # # ]: 0 : if (!cmdqs)
547 : : return -ENOMEM;
548 : :
549 : 0 : hwdev->cmdqs = cmdqs;
550 : 0 : cmdqs->hwdev = hwdev;
551 : :
552 : : saved_wqs_size = HINIC_MAX_CMDQ_TYPES * sizeof(struct hinic_wq);
553 : 0 : cmdqs->saved_wqs = kzalloc(saved_wqs_size, GFP_KERNEL);
554 [ # # ]: 0 : if (!cmdqs->saved_wqs) {
555 : 0 : PMD_DRV_LOG(ERR, "Allocate saved wqs failed");
556 : : err = -ENOMEM;
557 : 0 : goto alloc_wqs_err;
558 : : }
559 : :
560 : 0 : cmdqs->cmd_buf_pool = dma_pool_create("hinic_cmdq", hwdev,
561 : : HINIC_CMDQ_BUF_SIZE,
562 : : HINIC_CMDQ_BUF_SIZE, 0ULL);
563 [ # # ]: 0 : if (!cmdqs->cmd_buf_pool) {
564 : 0 : PMD_DRV_LOG(ERR, "Create cmdq buffer pool failed");
565 : : err = -ENOMEM;
566 : 0 : goto pool_create_err;
567 : : }
568 : :
569 : 0 : err = hinic_cmdq_alloc(cmdqs->saved_wqs, hwdev,
570 : : HINIC_MAX_CMDQ_TYPES, HINIC_CMDQ_WQ_BUF_SIZE,
571 : : CMDQ_WQEBB_SHIFT, HINIC_CMDQ_DEPTH);
572 [ # # ]: 0 : if (err) {
573 : 0 : PMD_DRV_LOG(ERR, "Allocate cmdq failed");
574 : 0 : goto cmdq_alloc_err;
575 : : }
576 : :
577 : : cmdq_type = HINIC_CMDQ_SYNC;
578 [ # # ]: 0 : for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
579 : 0 : err = init_cmdq(&cmdqs->cmdq[cmdq_type], hwdev,
580 : 0 : &cmdqs->saved_wqs[cmdq_type], cmdq_type);
581 [ # # ]: 0 : if (err) {
582 : 0 : PMD_DRV_LOG(ERR, "Initialize cmdq failed");
583 : 0 : goto init_cmdq_err;
584 : : }
585 : :
586 : 0 : cmdq_ctxt = &cmdqs->cmdq[cmdq_type].cmdq_ctxt;
587 : 0 : cmdq_init_queue_ctxt(&cmdqs->cmdq[cmdq_type], cmdq_ctxt);
588 : : }
589 : :
590 : 0 : err = hinic_set_cmdq_ctxts(hwdev);
591 [ # # ]: 0 : if (err)
592 : 0 : goto init_cmdq_err;
593 : :
594 : : return 0;
595 : :
596 : 0 : init_cmdq_err:
597 : : type = HINIC_CMDQ_SYNC;
598 [ # # ]: 0 : for ( ; type < cmdq_type; type++)
599 : 0 : free_cmdq(hwdev, &cmdqs->cmdq[type]);
600 : :
601 : 0 : hinic_cmdq_free(hwdev, cmdqs->saved_wqs, HINIC_MAX_CMDQ_TYPES);
602 : :
603 : 0 : cmdq_alloc_err:
604 : 0 : dma_pool_destroy(cmdqs->cmd_buf_pool);
605 : :
606 : 0 : pool_create_err:
607 : 0 : kfree(cmdqs->saved_wqs);
608 : :
609 : 0 : alloc_wqs_err:
610 : 0 : kfree(cmdqs);
611 : :
612 : 0 : return err;
613 : : }
614 : :
615 : 0 : static void hinic_cmdqs_free(struct hinic_hwdev *hwdev)
616 : : {
617 : 0 : struct hinic_cmdqs *cmdqs = hwdev->cmdqs;
618 : : enum hinic_cmdq_type cmdq_type = HINIC_CMDQ_SYNC;
619 : :
620 : 0 : cmdqs->status &= ~HINIC_CMDQ_ENABLE;
621 : :
622 [ # # ]: 0 : for ( ; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++)
623 : 0 : free_cmdq(cmdqs->hwdev, &cmdqs->cmdq[cmdq_type]);
624 : :
625 : 0 : hinic_cmdq_free(hwdev, cmdqs->saved_wqs,
626 : : HINIC_MAX_CMDQ_TYPES);
627 : :
628 : 0 : dma_pool_destroy(cmdqs->cmd_buf_pool);
629 : :
630 : 0 : kfree(cmdqs->saved_wqs);
631 : :
632 : 0 : kfree(cmdqs);
633 : 0 : }
634 : :
635 : 0 : static int hinic_set_cmdq_depth(struct hinic_hwdev *hwdev, u16 cmdq_depth)
636 : : {
637 : : struct hinic_root_ctxt root_ctxt;
638 : 0 : u16 out_size = sizeof(root_ctxt);
639 : : int err;
640 : :
641 : : memset(&root_ctxt, 0, sizeof(root_ctxt));
642 : 0 : root_ctxt.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
643 : 0 : root_ctxt.func_idx = hinic_global_func_id(hwdev);
644 : 0 : root_ctxt.ppf_idx = hinic_ppf_idx(hwdev);
645 : 0 : root_ctxt.set_cmdq_depth = 1;
646 : 0 : root_ctxt.cmdq_depth = (u8)ilog2(cmdq_depth);
647 : 0 : err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
648 : : HINIC_MGMT_CMD_VAT_SET,
649 : : &root_ctxt, sizeof(root_ctxt),
650 : : &root_ctxt, &out_size, 0);
651 [ # # # # : 0 : if (err || !out_size || root_ctxt.mgmt_msg_head.status) {
# # ]
652 : 0 : PMD_DRV_LOG(ERR, "Set cmdq depth failed, err: %d, status: 0x%x, out_size: 0x%x",
653 : : err, root_ctxt.mgmt_msg_head.status, out_size);
654 : 0 : return -EIO;
655 : : }
656 : :
657 : : return 0;
658 : : }
659 : :
660 : 0 : int hinic_comm_cmdqs_init(struct hinic_hwdev *hwdev)
661 : : {
662 : : int err;
663 : :
664 : 0 : err = hinic_cmdqs_init(hwdev);
665 [ # # ]: 0 : if (err) {
666 : 0 : PMD_DRV_LOG(ERR, "Init cmd queues failed");
667 : 0 : return err;
668 : : }
669 : :
670 : 0 : err = hinic_set_cmdq_depth(hwdev, HINIC_CMDQ_DEPTH);
671 [ # # ]: 0 : if (err) {
672 : 0 : PMD_DRV_LOG(ERR, "Set cmdq depth failed");
673 : 0 : goto set_cmdq_depth_err;
674 : : }
675 : :
676 : : return 0;
677 : :
678 : : set_cmdq_depth_err:
679 : 0 : hinic_cmdqs_free(hwdev);
680 : :
681 : 0 : return err;
682 : : }
683 : :
684 : 0 : static void cmdq_init_queue_ctxt(struct hinic_cmdq *cmdq,
685 : : struct hinic_cmdq_ctxt *cmdq_ctxt)
686 : : {
687 : 0 : struct hinic_cmdqs *cmdqs = (struct hinic_cmdqs *)cmdq_to_cmdqs(cmdq);
688 : 0 : struct hinic_hwdev *hwdev = cmdqs->hwdev;
689 : 0 : struct hinic_wq *wq = cmdq->wq;
690 : : struct hinic_cmdq_ctxt_info *ctxt_info = &cmdq_ctxt->ctxt_info;
691 : : u64 wq_first_page_paddr, pfn;
692 : :
693 : 0 : u16 start_ci = (u16)(wq->cons_idx);
694 : :
695 : : /* The data in the HW is in Big Endian Format */
696 : 0 : wq_first_page_paddr = wq->queue_buf_paddr;
697 : :
698 : 0 : pfn = CMDQ_PFN(wq_first_page_paddr, HINIC_PAGE_SIZE);
699 : 0 : ctxt_info->curr_wqe_page_pfn =
700 : : CMDQ_CTXT_PAGE_INFO_SET(1, HW_BUSY_BIT) |
701 : : CMDQ_CTXT_PAGE_INFO_SET(1, CEQ_EN) |
702 : : CMDQ_CTXT_PAGE_INFO_SET(0, CEQ_ARM) |
703 : 0 : CMDQ_CTXT_PAGE_INFO_SET(HINIC_CEQ_ID_CMDQ, EQ_ID) |
704 : 0 : CMDQ_CTXT_PAGE_INFO_SET(pfn, CURR_WQE_PAGE_PFN);
705 : :
706 : 0 : ctxt_info->wq_block_pfn = CMDQ_CTXT_BLOCK_INFO_SET(start_ci, CI) |
707 : : CMDQ_CTXT_BLOCK_INFO_SET(pfn, WQ_BLOCK_PFN);
708 : 0 : cmdq_ctxt->func_idx = HINIC_HWIF_GLOBAL_IDX(hwdev->hwif);
709 : 0 : cmdq_ctxt->ppf_idx = HINIC_HWIF_PPF_IDX(hwdev->hwif);
710 : 0 : cmdq_ctxt->cmdq_id = cmdq->cmdq_type;
711 : 0 : }
712 : :
713 : 0 : static int hinic_cmdq_poll_msg(struct hinic_cmdq *cmdq, u32 timeout)
714 : : {
715 : : struct hinic_cmdq_wqe *wqe;
716 : : struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
717 : : struct hinic_ctrl *ctrl;
718 : : struct hinic_cmdq_cmd_info *cmd_info;
719 : : u32 status_info, ctrl_info;
720 : : u16 ci;
721 : : int errcode;
722 : : unsigned long end;
723 : : int done = 0;
724 : : int rc = 0;
725 : :
726 : 0 : wqe = hinic_read_wqe(cmdq->wq, 1, &ci);
727 [ # # ]: 0 : if (wqe == NULL) {
728 : 0 : PMD_DRV_LOG(ERR, "No outstanding cmdq msg");
729 : 0 : return -EINVAL;
730 : : }
731 : :
732 : 0 : cmd_info = &cmdq->cmd_infos[ci];
733 : : /* this cmd has not been filled and send to hw, or get TMO msg ack*/
734 [ # # ]: 0 : if (cmd_info->cmd_type == HINIC_CMD_TYPE_NONE) {
735 : 0 : PMD_DRV_LOG(ERR, "Cmdq msg has not been filled and send to hw, or get TMO msg ack. cmdq ci: %u",
736 : : ci);
737 : 0 : return -EINVAL;
738 : : }
739 : :
740 : : /* only arm bit is using scmd wqe, the wqe is lcmd */
741 : : wqe_lcmd = &wqe->wqe_lcmd;
742 : : ctrl = &wqe_lcmd->ctrl;
743 : 0 : end = jiffies + msecs_to_jiffies(timeout);
744 : : do {
745 [ # # ]: 0 : ctrl_info = be32_to_cpu((ctrl)->ctrl_info);
746 [ # # ]: 0 : if (WQE_COMPLETED(ctrl_info)) {
747 : : done = 1;
748 : : break;
749 : : }
750 : :
751 : : rte_delay_ms(1);
752 [ # # ]: 0 : } while (time_before(jiffies, end));
753 : :
754 [ # # ]: 0 : if (done) {
755 [ # # ]: 0 : status_info = be32_to_cpu(wqe_lcmd->status.status_info);
756 : 0 : errcode = WQE_ERRCODE_GET(status_info, VAL);
757 : 0 : cmdq_update_errcode(cmdq, ci, errcode);
758 : 0 : clear_wqe_complete_bit(cmdq, wqe);
759 : : rc = 0;
760 : : } else {
761 : 0 : PMD_DRV_LOG(ERR, "Poll cmdq msg time out, ci: %u", ci);
762 : : rc = -ETIMEDOUT;
763 : : }
764 : :
765 : : /* set this cmd invalid */
766 : 0 : cmd_info->cmd_type = HINIC_CMD_TYPE_NONE;
767 : :
768 : 0 : return rc;
769 : : }
770 : :
771 : 0 : static int cmdq_sync_cmd_direct_resp(struct hinic_cmdq *cmdq,
772 : : enum hinic_ack_type ack_type,
773 : : enum hinic_mod_type mod, u8 cmd,
774 : : struct hinic_cmd_buf *buf_in,
775 : : u64 *out_param, u32 timeout)
776 : : {
777 : 0 : struct hinic_wq *wq = cmdq->wq;
778 : : struct hinic_cmdq_wqe *curr_wqe, wqe;
779 : : struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
780 : : u16 curr_prod_idx, next_prod_idx, num_wqebbs;
781 : : int wrapped;
782 : : u32 timeo, wqe_size;
783 : : int err;
784 : :
785 : : wqe_size = cmdq_wqe_size(WQE_LCMD_TYPE);
786 : 0 : num_wqebbs = WQE_NUM_WQEBBS(wqe_size, wq);
787 : :
788 : : /* Keep wrapped and doorbell index correct. */
789 : 0 : spin_lock(&cmdq->cmdq_lock);
790 : :
791 : 0 : curr_wqe = hinic_get_wqe(cmdq->wq, num_wqebbs, &curr_prod_idx);
792 [ # # ]: 0 : if (!curr_wqe) {
793 : : err = -EBUSY;
794 : 0 : goto cmdq_unlock;
795 : : }
796 : :
797 : : memset(&wqe, 0, sizeof(wqe));
798 : 0 : wrapped = cmdq->wrapped;
799 : :
800 : 0 : next_prod_idx = curr_prod_idx + num_wqebbs;
801 [ # # ]: 0 : if (next_prod_idx >= wq->q_depth) {
802 : 0 : cmdq->wrapped = !cmdq->wrapped;
803 : 0 : next_prod_idx -= wq->q_depth;
804 : : }
805 : :
806 : 0 : cmdq_set_lcmd_wqe(&wqe, SYNC_CMD_DIRECT_RESP, buf_in, NULL,
807 : : wrapped, ack_type, mod, cmd, curr_prod_idx);
808 : :
809 : : /* The data that is written to HW should be in Big Endian Format */
810 : 0 : hinic_cpu_to_be32(&wqe, wqe_size);
811 : :
812 : : /* CMDQ WQE is not shadow, therefore wqe will be written to wq */
813 : : cmdq_wqe_fill(curr_wqe, &wqe);
814 : :
815 : 0 : cmdq->cmd_infos[curr_prod_idx].cmd_type = HINIC_CMD_TYPE_NORMAL;
816 : :
817 : 0 : cmdq_set_db(cmdq, HINIC_CMDQ_SYNC, next_prod_idx);
818 : :
819 [ # # ]: 0 : timeo = msecs_to_jiffies(timeout ? timeout : CMDQ_CMD_TIMEOUT);
820 : 0 : err = hinic_cmdq_poll_msg(cmdq, timeo);
821 [ # # ]: 0 : if (err) {
822 : 0 : PMD_DRV_LOG(ERR, "Cmdq poll msg ack failed, prod idx: 0x%x",
823 : : curr_prod_idx);
824 : : err = -ETIMEDOUT;
825 : 0 : goto cmdq_unlock;
826 : : }
827 : :
828 : 0 : rte_smp_rmb(); /* read error code after completion */
829 : :
830 [ # # ]: 0 : if (out_param) {
831 : : wqe_lcmd = &curr_wqe->wqe_lcmd;
832 [ # # ]: 0 : *out_param = cpu_to_be64(wqe_lcmd->completion.direct_resp);
833 : : }
834 : :
835 [ # # ]: 0 : if (cmdq->errcode[curr_prod_idx] > 1) {
836 : : err = cmdq->errcode[curr_prod_idx];
837 : 0 : goto cmdq_unlock;
838 : : }
839 : :
840 : 0 : cmdq_unlock:
841 : : spin_unlock(&cmdq->cmdq_lock);
842 : :
843 : 0 : return err;
844 : : }
845 : :
846 : 0 : int hinic_cmdq_direct_resp(void *hwdev, enum hinic_ack_type ack_type,
847 : : enum hinic_mod_type mod, u8 cmd,
848 : : struct hinic_cmd_buf *buf_in,
849 : : u64 *out_param, u32 timeout)
850 : : {
851 [ # # ]: 0 : struct hinic_cmdqs *cmdqs = ((struct hinic_hwdev *)hwdev)->cmdqs;
852 : : int err = cmdq_params_valid(buf_in);
853 : :
854 : : if (err) {
855 : 0 : PMD_DRV_LOG(ERR, "Invalid CMDQ parameters");
856 : 0 : return err;
857 : : }
858 : :
859 : 0 : err = wait_cmdqs_enable(cmdqs);
860 [ # # ]: 0 : if (err) {
861 : 0 : PMD_DRV_LOG(ERR, "Cmdq is disable");
862 : 0 : return err;
863 : : }
864 : :
865 : 0 : return cmdq_sync_cmd_direct_resp(&cmdqs->cmdq[HINIC_CMDQ_SYNC],
866 : : ack_type, mod, cmd, buf_in,
867 : : out_param, timeout);
868 : : }
|