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_csr.h"
7 : : #include "hinic_pmd_hwdev.h"
8 : : #include "hinic_pmd_hwif.h"
9 : : #include "hinic_pmd_mgmt.h"
10 : : #include "hinic_pmd_mbox.h"
11 : :
12 : : #define BUF_OUT_DEFAULT_SIZE 1
13 : :
14 : : #define MAX_PF_MGMT_BUF_SIZE 2048UL
15 : :
16 : : #define MGMT_MSG_SIZE_MIN 20
17 : : #define MGMT_MSG_SIZE_STEP 16
18 : : #define MGMT_MSG_RSVD_FOR_DEV 8
19 : :
20 : : #define MGMT_MSG_TIMEOUT 5000 /* millisecond */
21 : :
22 : : #define SYNC_MSG_ID_MASK 0x1FF
23 : : #define ASYNC_MSG_ID_MASK 0x1FF
24 : : #define ASYNC_MSG_FLAG 0x200
25 : :
26 : : #define MSG_NO_RESP 0xFFFF
27 : :
28 : : #define MAX_MSG_SZ 2016
29 : :
30 : : #define MSG_SZ_IS_VALID(in_size) ((in_size) <= MAX_MSG_SZ)
31 : :
32 : : #define SYNC_MSG_ID(pf_to_mgmt) ((pf_to_mgmt)->sync_msg_id)
33 : :
34 : : #define SYNC_MSG_ID_INC(pf_to_mgmt) (SYNC_MSG_ID(pf_to_mgmt) = \
35 : : (SYNC_MSG_ID(pf_to_mgmt) + 1) & SYNC_MSG_ID_MASK)
36 : :
37 : : #define ASYNC_MSG_ID(pf_to_mgmt) ((pf_to_mgmt)->async_msg_id)
38 : :
39 : : #define ASYNC_MSG_ID_INC(pf_to_mgmt) (ASYNC_MSG_ID(pf_to_mgmt) = \
40 : : ((ASYNC_MSG_ID(pf_to_mgmt) + 1) & ASYNC_MSG_ID_MASK) \
41 : : | ASYNC_MSG_FLAG)
42 : :
43 : : #define HINIC_SEQ_ID_MAX_VAL 42
44 : : #define HINIC_MSG_SEG_LEN 48
45 : :
46 : : #define GET_CURR_AEQ_ELEM(eq) GET_AEQ_ELEM((eq), (eq)->cons_idx)
47 : :
48 : : #define EQ_ELEM_DESC_TYPE_SHIFT 0
49 : : #define EQ_ELEM_DESC_SRC_SHIFT 7
50 : : #define EQ_ELEM_DESC_SIZE_SHIFT 8
51 : : #define EQ_ELEM_DESC_WRAPPED_SHIFT 31
52 : :
53 : : #define EQ_ELEM_DESC_TYPE_MASK 0x7FU
54 : : #define EQ_ELEM_DESC_SRC_MASK 0x1U
55 : : #define EQ_ELEM_DESC_SIZE_MASK 0xFFU
56 : : #define EQ_ELEM_DESC_WRAPPED_MASK 0x1U
57 : :
58 : : #define EQ_MSIX_RESEND_TIMER_CLEAR 1
59 : :
60 : : #define EQ_ELEM_DESC_GET(val, member) \
61 : : (((val) >> EQ_ELEM_DESC_##member##_SHIFT) & \
62 : : EQ_ELEM_DESC_##member##_MASK)
63 : :
64 : : #define HINIC_MGMT_CHANNEL_STATUS_SHIFT 0x0
65 : : #define HINIC_MGMT_CHANNEL_STATUS_MASK 0x1
66 : :
67 : : #define HINIC_GET_MGMT_CHANNEL_STATUS(val, member) \
68 : : (((val) >> HINIC_##member##_SHIFT) & HINIC_##member##_MASK)
69 : :
70 : : #define HINIC_MSG_TO_MGMT_MAX_LEN 2016
71 : :
72 : : /**
73 : : * mgmt_msg_len - calculate the total message length
74 : : * @msg_data_len: the length of the message data
75 : : * Return: the total message length
76 : : */
77 : : static u16 mgmt_msg_len(u16 msg_data_len)
78 : : {
79 : : /* u64 - the size of the header */
80 : 0 : u16 msg_size = (u16)(MGMT_MSG_RSVD_FOR_DEV + sizeof(u64) +
81 : : msg_data_len);
82 : :
83 : 0 : if (msg_size > MGMT_MSG_SIZE_MIN)
84 : 0 : msg_size = MGMT_MSG_SIZE_MIN +
85 : 0 : ALIGN((msg_size - MGMT_MSG_SIZE_MIN),
86 : : MGMT_MSG_SIZE_STEP);
87 : : else
88 : : msg_size = MGMT_MSG_SIZE_MIN;
89 : :
90 : : return msg_size;
91 : : }
92 : :
93 : : /**
94 : : * prepare_header - prepare the header of the message
95 : : * @pf_to_mgmt: PF to MGMT channel
96 : : * @header: pointer of the header to prepare
97 : : * @msg_len: the length of the message
98 : : * @mod: module in the chip that will get the message
99 : : * @ack_type: the type to response
100 : : * @direction: the direction of the original message
101 : : * @cmd: the command to do
102 : : * @msg_id: message id
103 : : */
104 : 0 : static void prepare_header(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
105 : : u64 *header, int msg_len, enum hinic_mod_type mod,
106 : : enum hinic_msg_ack_type ack_type,
107 : : enum hinic_msg_direction_type direction,
108 : : u8 cmd, u32 msg_id)
109 : : {
110 : 0 : struct hinic_hwif *hwif = pf_to_mgmt->hwdev->hwif;
111 : :
112 : 0 : *header = HINIC_MSG_HEADER_SET(msg_len, MSG_LEN) |
113 : 0 : HINIC_MSG_HEADER_SET(mod, MODULE) |
114 : 0 : HINIC_MSG_HEADER_SET(msg_len, SEG_LEN) |
115 : 0 : HINIC_MSG_HEADER_SET(ack_type, NO_ACK) |
116 : 0 : HINIC_MSG_HEADER_SET(0, ASYNC_MGMT_TO_PF) |
117 : : HINIC_MSG_HEADER_SET(0, SEQID) |
118 : 0 : HINIC_MSG_HEADER_SET(LAST_SEGMENT, LAST) |
119 : 0 : HINIC_MSG_HEADER_SET(direction, DIRECTION) |
120 : 0 : HINIC_MSG_HEADER_SET(cmd, CMD) |
121 : 0 : HINIC_MSG_HEADER_SET(HINIC_PCI_INTF_IDX(hwif), PCI_INTF_IDX) |
122 : 0 : HINIC_MSG_HEADER_SET(hwif->attr.port_to_port_idx, P2P_IDX) |
123 : 0 : HINIC_MSG_HEADER_SET(msg_id, MSG_ID);
124 : 0 : }
125 : :
126 : : /**
127 : : * prepare_mgmt_cmd - prepare the mgmt command
128 : : * @mgmt_cmd: pointer to the command to prepare
129 : : * @header: pointer of the header to prepare
130 : : * @msg: the data of the message
131 : : * @msg_len: the length of the message
132 : : */
133 : 0 : static void prepare_mgmt_cmd(u8 *mgmt_cmd, u64 *header, void *msg,
134 : : int msg_len)
135 : : {
136 : : memset(mgmt_cmd, 0, MGMT_MSG_RSVD_FOR_DEV);
137 : :
138 : 0 : mgmt_cmd += MGMT_MSG_RSVD_FOR_DEV;
139 : : memcpy(mgmt_cmd, header, sizeof(*header));
140 : :
141 : 0 : mgmt_cmd += sizeof(*header);
142 : 0 : memcpy(mgmt_cmd, msg, msg_len);
143 : 0 : }
144 : :
145 : : /**
146 : : * alloc_recv_msg - allocate received message memory
147 : : * @recv_msg: pointer that will hold the allocated data
148 : : * Return: 0 - success, negative - failure
149 : : */
150 : 0 : static int alloc_recv_msg(struct hinic_recv_msg *recv_msg)
151 : : {
152 : : int err;
153 : :
154 : 0 : recv_msg->msg = kzalloc(MAX_PF_MGMT_BUF_SIZE, GFP_KERNEL);
155 [ # # ]: 0 : if (!recv_msg->msg) {
156 : 0 : PMD_DRV_LOG(ERR, "Allocate recv msg buf failed");
157 : 0 : return -ENOMEM;
158 : : }
159 : :
160 : 0 : recv_msg->buf_out = kzalloc(MAX_PF_MGMT_BUF_SIZE, GFP_KERNEL);
161 [ # # ]: 0 : if (!recv_msg->buf_out) {
162 : 0 : PMD_DRV_LOG(ERR, "Allocate recv msg output buf failed");
163 : : err = -ENOMEM;
164 : 0 : goto alloc_buf_out_err;
165 : : }
166 : :
167 : : return 0;
168 : :
169 : : alloc_buf_out_err:
170 : 0 : kfree(recv_msg->msg);
171 : 0 : return err;
172 : : }
173 : :
174 : : /**
175 : : * free_recv_msg - free received message memory
176 : : * @recv_msg: pointer that holds the allocated data
177 : : */
178 : : static void free_recv_msg(struct hinic_recv_msg *recv_msg)
179 : : {
180 : 0 : kfree(recv_msg->buf_out);
181 : 0 : kfree(recv_msg->msg);
182 : 0 : }
183 : :
184 : : /**
185 : : * alloc_msg_buf - allocate all the message buffers of PF to MGMT channel
186 : : * @pf_to_mgmt: PF to MGMT channel
187 : : * Return: 0 - success, negative - failure
188 : : */
189 : 0 : static int alloc_msg_buf(struct hinic_msg_pf_to_mgmt *pf_to_mgmt)
190 : : {
191 : : int err;
192 : :
193 : 0 : err = alloc_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
194 [ # # ]: 0 : if (err) {
195 : 0 : PMD_DRV_LOG(ERR, "Allocate recv msg failed");
196 : 0 : return err;
197 : : }
198 : :
199 : 0 : err = alloc_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt);
200 [ # # ]: 0 : if (err) {
201 : 0 : PMD_DRV_LOG(ERR, "Allocate resp recv msg failed");
202 : 0 : goto alloc_msg_for_resp_err;
203 : : }
204 : :
205 : 0 : pf_to_mgmt->async_msg_buf = kzalloc(MAX_PF_MGMT_BUF_SIZE, GFP_KERNEL);
206 [ # # ]: 0 : if (!pf_to_mgmt->async_msg_buf) {
207 : 0 : PMD_DRV_LOG(ERR, "Allocate async msg buf failed");
208 : : err = -ENOMEM;
209 : 0 : goto async_msg_buf_err;
210 : : }
211 : :
212 : 0 : pf_to_mgmt->sync_msg_buf = kzalloc(MAX_PF_MGMT_BUF_SIZE, GFP_KERNEL);
213 [ # # ]: 0 : if (!pf_to_mgmt->sync_msg_buf) {
214 : 0 : PMD_DRV_LOG(ERR, "Allocate sync msg buf failed");
215 : : err = -ENOMEM;
216 : 0 : goto sync_msg_buf_err;
217 : : }
218 : :
219 : : return 0;
220 : :
221 : : sync_msg_buf_err:
222 : 0 : kfree(pf_to_mgmt->async_msg_buf);
223 : :
224 : 0 : async_msg_buf_err:
225 : : free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt);
226 : :
227 : 0 : alloc_msg_for_resp_err:
228 : : free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
229 : :
230 : 0 : return err;
231 : : }
232 : :
233 : : /**
234 : : * free_msg_buf - free all the message buffers of PF to MGMT channel
235 : : * @pf_to_mgmt: PF to MGMT channel
236 : : * Return: 0 - success, negative - failure
237 : : */
238 : 0 : static void free_msg_buf(struct hinic_msg_pf_to_mgmt *pf_to_mgmt)
239 : : {
240 : 0 : kfree(pf_to_mgmt->sync_msg_buf);
241 : 0 : kfree(pf_to_mgmt->async_msg_buf);
242 : :
243 : : free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt);
244 : : free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
245 : 0 : }
246 : :
247 : : static int hinic_get_mgmt_channel_status(void *hwdev)
248 : : {
249 : 0 : struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
250 : : u32 val;
251 : :
252 [ # # ]: 0 : if (hinic_func_type((struct hinic_hwdev *)hwdev) == TYPE_VF)
253 : : return false;
254 : :
255 : : val = hinic_hwif_read_reg(hwif, HINIC_ICPL_RESERVD_ADDR);
256 : :
257 : 0 : return HINIC_GET_MGMT_CHANNEL_STATUS(val, MGMT_CHANNEL_STATUS);
258 : : }
259 : :
260 : : /**
261 : : * send_msg_to_mgmt_async - send async message
262 : : * @pf_to_mgmt: PF to MGMT channel
263 : : * @mod: module in the chip that will get the message
264 : : * @cmd: command of the message
265 : : * @msg: the data of the message
266 : : * @msg_len: the length of the message
267 : : * @direction: the direction of the original message
268 : : * @resp_msg_id: message id of response
269 : : * Return: 0 - success, negative - failure
270 : : */
271 : 0 : static int send_msg_to_mgmt_async(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
272 : : enum hinic_mod_type mod, u8 cmd,
273 : : void *msg, u16 msg_len,
274 : : enum hinic_msg_direction_type direction,
275 : : u16 resp_msg_id)
276 : : {
277 : 0 : void *mgmt_cmd = pf_to_mgmt->async_msg_buf;
278 : : struct hinic_api_cmd_chain *chain;
279 : : u64 header;
280 [ # # ]: 0 : u16 cmd_size = mgmt_msg_len(msg_len);
281 : :
282 [ # # ]: 0 : if (direction == HINIC_MSG_RESPONSE)
283 : 0 : prepare_header(pf_to_mgmt, &header, msg_len, mod, HINIC_MSG_ACK,
284 : : direction, cmd, resp_msg_id);
285 : : else
286 : 0 : prepare_header(pf_to_mgmt, &header, msg_len, mod, HINIC_MSG_ACK,
287 : 0 : direction, cmd, ASYNC_MSG_ID(pf_to_mgmt));
288 : :
289 : 0 : prepare_mgmt_cmd((u8 *)mgmt_cmd, &header, msg, msg_len);
290 : :
291 : 0 : chain = pf_to_mgmt->cmd_chain[HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU];
292 : :
293 : 0 : return hinic_api_cmd_write(chain, HINIC_NODE_ID_MGMT_HOST, mgmt_cmd,
294 : : cmd_size);
295 : : }
296 : :
297 : : /**
298 : : * send_msg_to_mgmt_sync - send async message
299 : : * @pf_to_mgmt: PF to MGMT channel
300 : : * @mod: module in the chip that will get the message
301 : : * @cmd: command of the message
302 : : * @msg: the msg data
303 : : * @msg_len: the msg data length
304 : : * @ack_type: indicate mgmt command whether need ack or not
305 : : * @direction: the direction of the original message
306 : : * @resp_msg_id: msg id to response for
307 : : * Return: 0 - success, negative - failure
308 : : */
309 : 0 : static int send_msg_to_mgmt_sync(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
310 : : enum hinic_mod_type mod, u8 cmd,
311 : : void *msg, u16 msg_len,
312 : : enum hinic_msg_ack_type ack_type,
313 : : enum hinic_msg_direction_type direction,
314 : : __rte_unused u16 resp_msg_id)
315 : : {
316 : 0 : void *mgmt_cmd = pf_to_mgmt->sync_msg_buf;
317 : : struct hinic_api_cmd_chain *chain;
318 : : u64 header;
319 [ # # ]: 0 : u16 cmd_size = mgmt_msg_len(msg_len);
320 : :
321 : : /* If fw is hot active, return failed */
322 [ # # ]: 0 : if (hinic_get_mgmt_channel_status(pf_to_mgmt->hwdev)) {
323 [ # # ]: 0 : if (mod == HINIC_MOD_COMM || mod == HINIC_MOD_L2NIC)
324 : : return HINIC_DEV_BUSY_ACTIVE_FW;
325 : : else
326 : 0 : return -EBUSY;
327 : : }
328 : :
329 [ # # ]: 0 : if (direction == HINIC_MSG_RESPONSE)
330 : 0 : prepare_header(pf_to_mgmt, &header, msg_len, mod, ack_type,
331 : : direction, cmd, resp_msg_id);
332 : : else
333 : 0 : prepare_header(pf_to_mgmt, &header, msg_len, mod, ack_type,
334 : 0 : direction, cmd, SYNC_MSG_ID(pf_to_mgmt));
335 : :
336 : 0 : prepare_mgmt_cmd((u8 *)mgmt_cmd, &header, msg, msg_len);
337 : :
338 : 0 : chain = pf_to_mgmt->cmd_chain[HINIC_API_CMD_PMD_WRITE_TO_MGMT];
339 : :
340 : 0 : return hinic_api_cmd_write(chain, HINIC_NODE_ID_MGMT_HOST,
341 : : mgmt_cmd, cmd_size);
342 : : }
343 : :
344 : : /**
345 : : * hinic_pf_to_mgmt_init - initialize PF to MGMT channel
346 : : * @hwdev: the pointer to the private hardware device object
347 : : * Return: 0 - success, negative - failure
348 : : */
349 : 0 : static int hinic_pf_to_mgmt_init(struct hinic_hwdev *hwdev)
350 : : {
351 : : struct hinic_msg_pf_to_mgmt *pf_to_mgmt;
352 : : int err;
353 : :
354 : 0 : pf_to_mgmt = kzalloc(sizeof(*pf_to_mgmt), GFP_KERNEL);
355 [ # # ]: 0 : if (!pf_to_mgmt) {
356 : 0 : PMD_DRV_LOG(ERR, "Allocate pf to mgmt mem failed");
357 : 0 : return -ENOMEM;
358 : : }
359 : :
360 : 0 : hwdev->pf_to_mgmt = pf_to_mgmt;
361 : 0 : pf_to_mgmt->hwdev = hwdev;
362 : :
363 : 0 : err = hinic_mutex_init(&pf_to_mgmt->sync_msg_mutex, NULL);
364 [ # # ]: 0 : if (err)
365 : 0 : goto mutex_init_err;
366 : :
367 : 0 : err = alloc_msg_buf(pf_to_mgmt);
368 [ # # ]: 0 : if (err) {
369 : 0 : PMD_DRV_LOG(ERR, "Allocate msg buffers failed");
370 : 0 : goto alloc_msg_buf_err;
371 : : }
372 : :
373 : 0 : err = hinic_api_cmd_init(hwdev, pf_to_mgmt->cmd_chain);
374 [ # # ]: 0 : if (err) {
375 : 0 : PMD_DRV_LOG(ERR, "Init the api cmd chains failed");
376 : 0 : goto api_cmd_init_err;
377 : : }
378 : :
379 : : return 0;
380 : :
381 : : api_cmd_init_err:
382 : 0 : free_msg_buf(pf_to_mgmt);
383 : :
384 : 0 : alloc_msg_buf_err:
385 : 0 : hinic_mutex_destroy(&pf_to_mgmt->sync_msg_mutex);
386 : :
387 : 0 : mutex_init_err:
388 : 0 : kfree(pf_to_mgmt);
389 : :
390 : 0 : return err;
391 : : }
392 : :
393 : : /**
394 : : * hinic_pf_to_mgmt_free - free PF to MGMT channel
395 : : * @hwdev: the pointer to the private hardware device object
396 : : */
397 : 0 : static void hinic_pf_to_mgmt_free(struct hinic_hwdev *hwdev)
398 : : {
399 : 0 : struct hinic_msg_pf_to_mgmt *pf_to_mgmt = hwdev->pf_to_mgmt;
400 : :
401 : 0 : hinic_api_cmd_free(pf_to_mgmt->cmd_chain);
402 : 0 : free_msg_buf(pf_to_mgmt);
403 : 0 : hinic_mutex_destroy(&pf_to_mgmt->sync_msg_mutex);
404 : 0 : kfree(pf_to_mgmt);
405 : 0 : }
406 : :
407 : : static int
408 : 0 : hinic_pf_to_mgmt_sync(struct hinic_hwdev *hwdev,
409 : : enum hinic_mod_type mod, u8 cmd, void *buf_in, u16 in_size,
410 : : void *buf_out, u16 *out_size, u32 timeout)
411 : : {
412 : 0 : struct hinic_msg_pf_to_mgmt *pf_to_mgmt = hwdev->pf_to_mgmt;
413 : : struct hinic_recv_msg *recv_msg;
414 : : u32 timeo;
415 : : int err, i;
416 : :
417 : 0 : err = hinic_mutex_lock(&pf_to_mgmt->sync_msg_mutex);
418 [ # # ]: 0 : if (err)
419 : : return err;
420 : :
421 : 0 : SYNC_MSG_ID_INC(pf_to_mgmt);
422 : : recv_msg = &pf_to_mgmt->recv_resp_msg_from_mgmt;
423 : :
424 : 0 : err = send_msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
425 : : HINIC_MSG_ACK, HINIC_MSG_DIRECT_SEND,
426 : : MSG_NO_RESP);
427 [ # # ]: 0 : if (err) {
428 : 0 : PMD_DRV_LOG(ERR, "Send msg to mgmt failed");
429 : 0 : goto unlock_sync_msg;
430 : : }
431 : :
432 [ # # ]: 0 : timeo = msecs_to_jiffies(timeout ? timeout : MGMT_MSG_TIMEOUT);
433 [ # # ]: 0 : for (i = 0; i < pf_to_mgmt->rx_aeq->poll_retry_nr; i++) {
434 : 0 : err = hinic_aeq_poll_msg(pf_to_mgmt->rx_aeq, timeo, NULL);
435 [ # # ]: 0 : if (err) {
436 : 0 : PMD_DRV_LOG(ERR, "Poll mgmt rsp timeout, mod=%d cmd=%d msg_id=%u rc=%d",
437 : : mod, cmd, pf_to_mgmt->sync_msg_id, err);
438 : : err = -ETIMEDOUT;
439 : 0 : hinic_dump_aeq_info(hwdev);
440 : 0 : goto unlock_sync_msg;
441 : : } else {
442 [ # # # # ]: 0 : if (mod == recv_msg->mod && cmd == recv_msg->cmd &&
443 [ # # ]: 0 : recv_msg->msg_id == pf_to_mgmt->sync_msg_id) {
444 : : /* the expected response polled */
445 : : break;
446 : : }
447 : 0 : PMD_DRV_LOG(ERR, "AEQ[%d] poll(mod=%d, cmd=%d, msg_id=%u) an "
448 : : "unexpected(mod=%d, cmd=%d, msg_id=%u) response",
449 : : pf_to_mgmt->rx_aeq->q_id, mod, cmd,
450 : : pf_to_mgmt->sync_msg_id, recv_msg->mod,
451 : : recv_msg->cmd, recv_msg->msg_id);
452 : : }
453 : : }
454 : :
455 [ # # ]: 0 : if (i == pf_to_mgmt->rx_aeq->poll_retry_nr) {
456 : 0 : PMD_DRV_LOG(ERR, "Get %d unexpected mgmt rsp from AEQ[%d], poll mgmt rsp failed",
457 : : i, pf_to_mgmt->rx_aeq->q_id);
458 : : err = -EBADMSG;
459 : 0 : goto unlock_sync_msg;
460 : : }
461 : :
462 : 0 : rte_smp_rmb();
463 [ # # # # ]: 0 : if (recv_msg->msg_len && buf_out && out_size) {
464 [ # # ]: 0 : if (recv_msg->msg_len <= *out_size) {
465 : 0 : memcpy(buf_out, recv_msg->msg,
466 : : recv_msg->msg_len);
467 : 0 : *out_size = recv_msg->msg_len;
468 : : } else {
469 : 0 : PMD_DRV_LOG(ERR, "Mgmt rsp's msg len: %u overflow.",
470 : : recv_msg->msg_len);
471 : : err = -ERANGE;
472 : : }
473 : : }
474 : :
475 : 0 : unlock_sync_msg:
476 [ # # ]: 0 : if (err && out_size)
477 : 0 : *out_size = 0;
478 : : (void)hinic_mutex_unlock(&pf_to_mgmt->sync_msg_mutex);
479 : 0 : return err;
480 : : }
481 : :
482 : 0 : int hinic_msg_to_mgmt_sync(void *hwdev, enum hinic_mod_type mod, u8 cmd,
483 : : void *buf_in, u16 in_size,
484 : : void *buf_out, u16 *out_size, u32 timeout)
485 : : {
486 : : int rc = HINIC_ERROR;
487 : :
488 [ # # ]: 0 : if (!hwdev || in_size > HINIC_MSG_TO_MGMT_MAX_LEN)
489 : : return -EINVAL;
490 : :
491 [ # # ]: 0 : if (hinic_func_type(hwdev) == TYPE_VF) {
492 : 0 : rc = hinic_mbox_to_pf(hwdev, mod, cmd, buf_in, in_size,
493 : : buf_out, out_size, timeout);
494 : : } else {
495 : 0 : rc = hinic_pf_to_mgmt_sync(hwdev, mod, cmd, buf_in, in_size,
496 : : buf_out, out_size, timeout);
497 : : }
498 : :
499 : : return rc;
500 : : }
501 : :
502 : 0 : int hinic_msg_to_mgmt_no_ack(void *hwdev, enum hinic_mod_type mod, u8 cmd,
503 : : void *buf_in, u16 in_size)
504 : : {
505 : 0 : struct hinic_msg_pf_to_mgmt *pf_to_mgmt =
506 : : ((struct hinic_hwdev *)hwdev)->pf_to_mgmt;
507 : : int err = -EINVAL;
508 : :
509 [ # # ]: 0 : if (!MSG_SZ_IS_VALID(in_size)) {
510 : 0 : PMD_DRV_LOG(ERR, "Mgmt msg buffer size is invalid");
511 : 0 : return err;
512 : : }
513 : :
514 : 0 : err = hinic_mutex_lock(&pf_to_mgmt->sync_msg_mutex);
515 [ # # ]: 0 : if (err)
516 : : return err;
517 : :
518 : 0 : err = send_msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
519 : : HINIC_MSG_NO_ACK, HINIC_MSG_DIRECT_SEND,
520 : : MSG_NO_RESP);
521 : :
522 : : (void)hinic_mutex_unlock(&pf_to_mgmt->sync_msg_mutex);
523 : :
524 : 0 : return err;
525 : : }
526 : :
527 : : static bool check_mgmt_seq_id_and_seg_len(struct hinic_recv_msg *recv_msg,
528 : : u8 seq_id, u8 seg_len, u16 msg_id)
529 : : {
530 : 0 : if (seq_id > HINIC_SEQ_ID_MAX_VAL || seg_len > HINIC_MSG_SEG_LEN)
531 : : return false;
532 : :
533 [ # # ]: 0 : if (seq_id == 0) {
534 : 0 : recv_msg->seq_id = seq_id;
535 : 0 : recv_msg->msg_id = msg_id;
536 : : } else {
537 [ # # ]: 0 : if ((seq_id != recv_msg->seq_id + 1) ||
538 [ # # ]: 0 : msg_id != recv_msg->msg_id) {
539 : 0 : recv_msg->seq_id = 0;
540 : : return false;
541 : : }
542 : 0 : recv_msg->seq_id = seq_id;
543 : : }
544 : :
545 : : return true;
546 : : }
547 : :
548 : : /**
549 : : * hinic_mgmt_recv_msg_handler - handler for message from mgmt cpu
550 : : * @pf_to_mgmt: PF to MGMT channel
551 : : * @recv_msg: received message details
552 : : * @param: customized parameter
553 : : */
554 : 0 : static void hinic_mgmt_recv_msg_handler(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
555 : : struct hinic_recv_msg *recv_msg,
556 : : void *param)
557 : : {
558 : 0 : void *buf_out = recv_msg->buf_out;
559 : 0 : u16 out_size = 0;
560 : :
561 [ # # # # ]: 0 : switch (recv_msg->mod) {
562 : 0 : case HINIC_MOD_COMM:
563 : 0 : hinic_comm_async_event_handle(pf_to_mgmt->hwdev,
564 : 0 : recv_msg->cmd, recv_msg->msg,
565 : 0 : recv_msg->msg_len,
566 : : buf_out, &out_size);
567 : 0 : break;
568 : 0 : case HINIC_MOD_L2NIC:
569 : 0 : hinic_l2nic_async_event_handle(pf_to_mgmt->hwdev, param,
570 : 0 : recv_msg->cmd, recv_msg->msg,
571 : 0 : recv_msg->msg_len,
572 : : buf_out, &out_size);
573 : 0 : break;
574 : 0 : case HINIC_MOD_HILINK:
575 : 0 : hinic_hilink_async_event_handle(pf_to_mgmt->hwdev,
576 : 0 : recv_msg->cmd, recv_msg->msg,
577 : 0 : recv_msg->msg_len,
578 : : buf_out, &out_size);
579 : 0 : break;
580 : 0 : default:
581 : 0 : PMD_DRV_LOG(ERR, "No handler, mod: %d", recv_msg->mod);
582 : 0 : break;
583 : : }
584 : :
585 [ # # ]: 0 : if (!recv_msg->async_mgmt_to_pf) {
586 [ # # ]: 0 : if (!out_size)
587 : 0 : out_size = BUF_OUT_DEFAULT_SIZE;
588 : :
589 : : /* MGMT sent sync msg, send the response */
590 : 0 : (void)send_msg_to_mgmt_async(pf_to_mgmt, recv_msg->mod,
591 : 0 : recv_msg->cmd, buf_out, out_size,
592 : : HINIC_MSG_RESPONSE,
593 : 0 : recv_msg->msg_id);
594 : : }
595 : 0 : }
596 : :
597 : : /**
598 : : * recv_mgmt_msg_handler - handler a message from mgmt cpu
599 : : * @pf_to_mgmt: PF to MGMT channel
600 : : * @header: the header of the message
601 : : * @recv_msg: received message details
602 : : * @param: customized parameter
603 : : * Return: 0 when aeq is response message, -1 default result,
604 : : * and when wrong message or not last message
605 : : */
606 : 0 : static int recv_mgmt_msg_handler(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
607 : : u8 *header, struct hinic_recv_msg *recv_msg,
608 : : void *param)
609 : : {
610 : 0 : u64 msg_header = *((u64 *)header);
611 : 0 : void *msg_body = header + sizeof(msg_header);
612 : : u8 *dest_msg;
613 : : u8 seq_id, seq_len;
614 : : u8 front_id;
615 : : u16 msg_id;
616 : :
617 : 0 : seq_id = HINIC_MSG_HEADER_GET(msg_header, SEQID);
618 : 0 : seq_len = HINIC_MSG_HEADER_GET(msg_header, SEG_LEN);
619 : 0 : front_id = recv_msg->seq_id;
620 : 0 : msg_id = HINIC_MSG_HEADER_GET(msg_header, MSG_ID);
621 : :
622 [ # # ]: 0 : if (!check_mgmt_seq_id_and_seg_len(recv_msg, seq_id, seq_len, msg_id)) {
623 : 0 : PMD_DRV_LOG(ERR,
624 : : "Mgmt msg sequence and segment check failed, "
625 : : "func id: 0x%x, front id: 0x%x, current id: 0x%x, seg len: 0x%x "
626 : : "front msg_id: %d, cur msg_id: %d",
627 : : hinic_global_func_id(pf_to_mgmt->hwdev),
628 : : front_id, seq_id, seq_len, recv_msg->msg_id, msg_id);
629 : 0 : return HINIC_ERROR;
630 : : }
631 : :
632 : 0 : dest_msg = (u8 *)recv_msg->msg + seq_id * HINIC_MSG_SEG_LEN;
633 [ # # ]: 0 : memcpy(dest_msg, msg_body, seq_len);
634 : :
635 [ # # ]: 0 : if (!HINIC_MSG_HEADER_GET(msg_header, LAST))
636 : : return HINIC_ERROR;
637 : :
638 : 0 : recv_msg->cmd = HINIC_MSG_HEADER_GET(msg_header, CMD);
639 : 0 : recv_msg->mod = HINIC_MSG_HEADER_GET(msg_header, MODULE);
640 : 0 : recv_msg->async_mgmt_to_pf = HINIC_MSG_HEADER_GET(msg_header,
641 : : ASYNC_MGMT_TO_PF);
642 : 0 : recv_msg->msg_len = HINIC_MSG_HEADER_GET(msg_header, MSG_LEN);
643 : 0 : recv_msg->msg_id = HINIC_MSG_HEADER_GET(msg_header, MSG_ID);
644 : :
645 [ # # ]: 0 : if (HINIC_MSG_HEADER_GET(msg_header, DIRECTION) == HINIC_MSG_RESPONSE)
646 : : return HINIC_OK;
647 : :
648 : 0 : hinic_mgmt_recv_msg_handler(pf_to_mgmt, recv_msg, param);
649 : :
650 : 0 : return HINIC_ERROR;
651 : : }
652 : :
653 : : /**
654 : : * hinic_mgmt_msg_aeqe_handler - handler for a mgmt message event
655 : : * @hwdev: the pointer to the private hardware device object
656 : : * @header: the header of the message
657 : : * @size: unused
658 : : * @param: customized parameter
659 : : * Return: 0 when aeq is response message,
660 : : * -1 default result, and when wrong message or not last message
661 : : */
662 : : static int hinic_mgmt_msg_aeqe_handler(void *hwdev, u8 *header,
663 : : __rte_unused u8 size, void *param)
664 : : {
665 : 0 : struct hinic_msg_pf_to_mgmt *pf_to_mgmt =
666 : : ((struct hinic_hwdev *)hwdev)->pf_to_mgmt;
667 : : struct hinic_recv_msg *recv_msg;
668 : :
669 : 0 : recv_msg = (HINIC_MSG_HEADER_GET(*(u64 *)header, DIRECTION) ==
670 : : HINIC_MSG_DIRECT_SEND) ?
671 : 0 : &pf_to_mgmt->recv_msg_from_mgmt :
672 : : &pf_to_mgmt->recv_resp_msg_from_mgmt;
673 : :
674 : 0 : return recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg, param);
675 : : }
676 : :
677 : 0 : static int hinic_handle_aeqe(void *handle, enum hinic_aeq_type event,
678 : : u8 *data, u8 size, void *param)
679 : : {
680 : : int rc = 0;
681 : :
682 [ # # # ]: 0 : switch (event) {
683 [ # # ]: 0 : case HINIC_MSG_FROM_MGMT_CPU:
684 : : rc = hinic_mgmt_msg_aeqe_handler(handle, data, size, param);
685 : 0 : break;
686 : 0 : case HINIC_MBX_FROM_FUNC:
687 : 0 : rc = hinic_mbox_func_aeqe_handler(handle, data, size, param);
688 : 0 : break;
689 : 0 : default:
690 : 0 : PMD_DRV_LOG(ERR, "Unknown event type: 0x%x, size: %d",
691 : : event, size);
692 : : rc = HINIC_ERROR;
693 : 0 : break;
694 : : }
695 : :
696 : 0 : return rc;
697 : : }
698 : :
699 : : /**
700 : : * hinic_aeq_poll_msg - poll one or continue aeqe, and call dedicated process
701 : : * @eq: aeq of the chip
702 : : * @timeout: 0 - poll all aeqe in eq, used in interrupt mode,
703 : : * > 0 - poll aeq until get aeqe with 'last' field set to 1,
704 : : * used in polling mode.
705 : : * @param: customized parameter
706 : : * Return: 0 - Success, EIO - poll timeout, ENODEV - swe not support
707 : : */
708 : 0 : int hinic_aeq_poll_msg(struct hinic_eq *eq, u32 timeout, void *param)
709 : : {
710 : : struct hinic_aeq_elem *aeqe_pos;
711 : : enum hinic_aeq_type event;
712 : : u32 aeqe_desc = 0;
713 : : u16 i;
714 : : u8 size;
715 : : int done = HINIC_ERROR;
716 : : int err = -EFAULT;
717 : : unsigned long end;
718 : :
719 [ # # # # ]: 0 : for (i = 0; ((timeout == 0) && (i < eq->eq_len)) ||
720 [ # # ]: 0 : ((timeout > 0) && (done != HINIC_OK) && (i < eq->eq_len)); i++) {
721 : : err = -EIO;
722 : 0 : end = jiffies + msecs_to_jiffies(timeout);
723 : : do {
724 : 0 : aeqe_pos = GET_CURR_AEQ_ELEM(eq);
725 : : rte_rmb();
726 : :
727 : : /* Data in HW is in Big endian Format */
728 [ # # ]: 0 : aeqe_desc = be32_to_cpu(aeqe_pos->desc);
729 : :
730 : : /* HW updates wrapped bit,
731 : : * when it adds eq element event
732 : : */
733 : 0 : if (EQ_ELEM_DESC_GET(aeqe_desc, WRAPPED)
734 [ # # ]: 0 : != eq->wrapped) {
735 : : err = 0;
736 : : break;
737 : : }
738 : :
739 [ # # ]: 0 : if (timeout != 0)
740 : 0 : usleep(1000);
741 [ # # ]: 0 : } while (time_before(jiffies, end));
742 : :
743 [ # # ]: 0 : if (err != HINIC_OK) /*poll time out*/
744 : : break;
745 : :
746 : 0 : event = EQ_ELEM_DESC_GET(aeqe_desc, TYPE);
747 [ # # ]: 0 : if (EQ_ELEM_DESC_GET(aeqe_desc, SRC)) {
748 : 0 : PMD_DRV_LOG(ERR, "AEQ sw event not support %d", event);
749 : 0 : return -ENODEV;
750 : :
751 : : } else {
752 : 0 : size = EQ_ELEM_DESC_GET(aeqe_desc, SIZE);
753 : 0 : done = hinic_handle_aeqe(eq->hwdev, event,
754 : 0 : aeqe_pos->aeqe_data,
755 : : size, param);
756 : : }
757 : :
758 : 0 : eq->cons_idx++;
759 [ # # ]: 0 : if (eq->cons_idx == eq->eq_len) {
760 : 0 : eq->cons_idx = 0;
761 : 0 : eq->wrapped = !eq->wrapped;
762 : : }
763 : : }
764 : :
765 : 0 : eq_update_ci(eq);
766 : :
767 : 0 : return err;
768 : : }
769 : :
770 : 0 : int hinic_comm_pf_to_mgmt_init(struct hinic_hwdev *hwdev)
771 : : {
772 : : int rc;
773 : :
774 : : /* VF do not support send msg to mgmt directly */
775 [ # # ]: 0 : if (hinic_func_type(hwdev) == TYPE_VF)
776 : : return 0;
777 : :
778 : 0 : rc = hinic_pf_to_mgmt_init(hwdev);
779 [ # # ]: 0 : if (rc)
780 : : return rc;
781 : :
782 : 0 : hwdev->pf_to_mgmt->rx_aeq = &hwdev->aeqs->aeq[HINIC_MGMT_RSP_AEQN];
783 : :
784 : 0 : return 0;
785 : : }
786 : :
787 : 0 : void hinic_comm_pf_to_mgmt_free(struct hinic_hwdev *hwdev)
788 : : {
789 : : /* VF do not support send msg to mgmt directly */
790 [ # # ]: 0 : if (hinic_func_type(hwdev) == TYPE_VF)
791 : : return;
792 : :
793 : 0 : hinic_pf_to_mgmt_free(hwdev);
794 : : }
795 : :
796 : 0 : void hinic_dev_handle_aeq_event(struct hinic_hwdev *hwdev, void *param)
797 : : {
798 : 0 : struct hinic_eq *aeq = &hwdev->aeqs->aeq[0];
799 : :
800 : : /* clear resend timer cnt register */
801 : 0 : hinic_misx_intr_clear_resend_bit(hwdev, aeq->eq_irq.msix_entry_idx,
802 : : EQ_MSIX_RESEND_TIMER_CLEAR);
803 : 0 : (void)hinic_aeq_poll_msg(aeq, 0, param);
804 : 0 : }
|