Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018-2021 HiSilicon Limited.
3 : : */
4 : :
5 : : #include <ethdev_driver.h>
6 : : #include <rte_io.h>
7 : :
8 : : #include "hns3_common.h"
9 : : #include "hns3_regs.h"
10 : : #include "hns3_logs.h"
11 : : #include "hns3_intr.h"
12 : : #include "hns3_rxtx.h"
13 : :
14 : : #define HNS3_CMD_CODE_OFFSET 2
15 : :
16 : : static const struct errno_respcode_map err_code_map[] = {
17 : : {0, 0},
18 : : {1, -EPERM},
19 : : {2, -ENOENT},
20 : : {5, -EIO},
21 : : {11, -EAGAIN},
22 : : {12, -ENOMEM},
23 : : {16, -EBUSY},
24 : : {22, -EINVAL},
25 : : {28, -ENOSPC},
26 : : {95, -EOPNOTSUPP},
27 : : };
28 : :
29 : : static int
30 : : hns3_resp_to_errno(uint16_t resp_code)
31 : : {
32 : : uint32_t i, num;
33 : :
34 : : num = sizeof(err_code_map) / sizeof(struct errno_respcode_map);
35 [ # # # # ]: 0 : for (i = 0; i < num; i++) {
36 [ # # # # ]: 0 : if (err_code_map[i].resp_code == resp_code)
37 : 0 : return err_code_map[i].err_no;
38 : : }
39 : :
40 : : return -EIO;
41 : : }
42 : :
43 : : static int
44 : 0 : hns3_get_mbx_resp(struct hns3_hw *hw, uint16_t code, uint16_t subcode,
45 : : uint8_t *resp_data, uint16_t resp_len)
46 : : {
47 : : #define HNS3_WAIT_RESP_US 100
48 : : #define US_PER_MS 1000
49 : : uint32_t mbx_time_limit;
50 : : struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
51 : : struct hns3_mbx_resp_status *mbx_resp;
52 : : uint32_t wait_time = 0;
53 : :
54 [ # # ]: 0 : if (resp_len > HNS3_MBX_MAX_RESP_DATA_SIZE) {
55 : 0 : hns3_err(hw, "VF mbx response len(=%u) exceeds maximum(=%d)",
56 : : resp_len, HNS3_MBX_MAX_RESP_DATA_SIZE);
57 : 0 : return -EINVAL;
58 : : }
59 : :
60 : 0 : mbx_time_limit = (uint32_t)hns->mbx_time_limit_ms * US_PER_MS;
61 [ # # ]: 0 : while (wait_time < mbx_time_limit) {
62 [ # # ]: 0 : if (__atomic_load_n(&hw->reset.disable_cmd, __ATOMIC_RELAXED)) {
63 : 0 : hns3_err(hw, "Don't wait for mbx response because of "
64 : : "disable_cmd");
65 : 0 : return -EBUSY;
66 : : }
67 : :
68 [ # # ]: 0 : if (is_reset_pending(hns)) {
69 : 0 : hw->mbx_resp.req_msg_data = 0;
70 : 0 : hns3_err(hw, "Don't wait for mbx response because of "
71 : : "reset pending");
72 : 0 : return -EIO;
73 : : }
74 : :
75 : 0 : hns3_dev_handle_mbx_msg(hw);
76 : 0 : rte_delay_us(HNS3_WAIT_RESP_US);
77 : :
78 [ # # ]: 0 : if (hw->mbx_resp.received_match_resp)
79 : : break;
80 : :
81 : 0 : wait_time += HNS3_WAIT_RESP_US;
82 : : }
83 : 0 : hw->mbx_resp.req_msg_data = 0;
84 [ # # ]: 0 : if (wait_time >= mbx_time_limit) {
85 : 0 : hns3_err(hw, "VF could not get mbx(%u,%u) from PF", code, subcode);
86 : 0 : return -ETIME;
87 : : }
88 : 0 : rte_io_rmb();
89 : : mbx_resp = &hw->mbx_resp;
90 : :
91 [ # # ]: 0 : if (mbx_resp->resp_status)
92 : : return mbx_resp->resp_status;
93 : :
94 [ # # ]: 0 : if (resp_data)
95 : 0 : memcpy(resp_data, &mbx_resp->additional_info[0], resp_len);
96 : :
97 : : return 0;
98 : : }
99 : :
100 : : static void
101 : 0 : hns3_mbx_prepare_resp(struct hns3_hw *hw, uint16_t code, uint16_t subcode)
102 : : {
103 : : /*
104 : : * Init both matching scheme fields because we may not know the exact
105 : : * scheme will be used when in the initial phase.
106 : : *
107 : : * Also, there are OK to init both matching scheme fields even though
108 : : * we get the exact scheme which is used.
109 : : */
110 : 0 : hw->mbx_resp.req_msg_data = (uint32_t)code << 16 | subcode;
111 : :
112 : : /* Update match_id and ensure the value of match_id is not zero */
113 : 0 : hw->mbx_resp.match_id++;
114 [ # # ]: 0 : if (hw->mbx_resp.match_id == 0)
115 : 0 : hw->mbx_resp.match_id = 1;
116 : 0 : hw->mbx_resp.received_match_resp = false;
117 : :
118 : 0 : hw->mbx_resp.resp_status = 0;
119 : 0 : memset(hw->mbx_resp.additional_info, 0, HNS3_MBX_MAX_RESP_DATA_SIZE);
120 : 0 : }
121 : :
122 : : int
123 : 0 : hns3_send_mbx_msg(struct hns3_hw *hw, uint16_t code, uint16_t subcode,
124 : : const uint8_t *msg_data, uint8_t msg_len, bool need_resp,
125 : : uint8_t *resp_data, uint16_t resp_len)
126 : : {
127 : : struct hns3_mbx_vf_to_pf_cmd *req;
128 : : struct hns3_cmd_desc desc;
129 : : bool is_ring_vector_msg;
130 : : int offset;
131 : : int ret;
132 : :
133 : : req = (struct hns3_mbx_vf_to_pf_cmd *)desc.data;
134 : :
135 : : /* first two bytes are reserved for code & subcode */
136 [ # # ]: 0 : if (msg_len > (HNS3_MBX_MAX_MSG_SIZE - HNS3_CMD_CODE_OFFSET)) {
137 : 0 : hns3_err(hw,
138 : : "VF send mbx msg fail, msg len %u exceeds max payload len %d",
139 : : msg_len, HNS3_MBX_MAX_MSG_SIZE - HNS3_CMD_CODE_OFFSET);
140 : 0 : return -EINVAL;
141 : : }
142 : :
143 : 0 : hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MBX_VF_TO_PF, false);
144 : 0 : req->msg[0] = code;
145 : 0 : is_ring_vector_msg = (code == HNS3_MBX_MAP_RING_TO_VECTOR) ||
146 : 0 : (code == HNS3_MBX_UNMAP_RING_TO_VECTOR) ||
147 : 0 : (code == HNS3_MBX_GET_RING_VECTOR_MAP);
148 [ # # ]: 0 : if (!is_ring_vector_msg)
149 : 0 : req->msg[1] = subcode;
150 [ # # ]: 0 : if (msg_data) {
151 [ # # ]: 0 : offset = is_ring_vector_msg ? 1 : HNS3_CMD_CODE_OFFSET;
152 : 0 : memcpy(&req->msg[offset], msg_data, msg_len);
153 : : }
154 : :
155 : : /* synchronous send */
156 [ # # ]: 0 : if (need_resp) {
157 : 0 : req->mbx_need_resp |= HNS3_MBX_NEED_RESP_BIT;
158 : 0 : rte_spinlock_lock(&hw->mbx_resp.lock);
159 : 0 : hns3_mbx_prepare_resp(hw, code, subcode);
160 : 0 : req->match_id = hw->mbx_resp.match_id;
161 : 0 : ret = hns3_cmd_send(hw, &desc, 1);
162 [ # # ]: 0 : if (ret) {
163 : : rte_spinlock_unlock(&hw->mbx_resp.lock);
164 : 0 : hns3_err(hw, "VF failed(=%d) to send mbx message to PF",
165 : : ret);
166 : 0 : return ret;
167 : : }
168 : :
169 : 0 : ret = hns3_get_mbx_resp(hw, code, subcode, resp_data, resp_len);
170 : : rte_spinlock_unlock(&hw->mbx_resp.lock);
171 : : } else {
172 : : /* asynchronous send */
173 : 0 : ret = hns3_cmd_send(hw, &desc, 1);
174 [ # # ]: 0 : if (ret) {
175 : 0 : hns3_err(hw, "VF failed(=%d) to send mbx message to PF",
176 : : ret);
177 : 0 : return ret;
178 : : }
179 : : }
180 : :
181 : : return ret;
182 : : }
183 : :
184 : : static bool
185 : : hns3_cmd_crq_empty(struct hns3_hw *hw)
186 : : {
187 : 0 : uint32_t tail = hns3_read_dev(hw, HNS3_CMDQ_RX_TAIL_REG);
188 : :
189 : 0 : return tail == hw->cmq.crq.next_to_use;
190 : : }
191 : :
192 : : static void
193 : 0 : hns3vf_handle_link_change_event(struct hns3_hw *hw,
194 : : struct hns3_mbx_pf_to_vf_cmd *req)
195 : : {
196 : : uint8_t link_status, link_duplex;
197 : : uint16_t *msg_q = req->msg;
198 : : uint8_t support_push_lsc;
199 : : uint32_t link_speed;
200 : :
201 : : memcpy(&link_speed, &msg_q[2], sizeof(link_speed));
202 : 0 : link_status = rte_le_to_cpu_16(msg_q[1]);
203 : 0 : link_duplex = (uint8_t)rte_le_to_cpu_16(msg_q[4]);
204 : 0 : hns3vf_update_link_status(hw, link_status, link_speed,
205 : : link_duplex);
206 : 0 : support_push_lsc = (*(uint8_t *)&msg_q[5]) & 1u;
207 : 0 : hns3vf_update_push_lsc_cap(hw, support_push_lsc);
208 : 0 : }
209 : :
210 : : static void
211 : 0 : hns3_handle_asserting_reset(struct hns3_hw *hw,
212 : : struct hns3_mbx_pf_to_vf_cmd *req)
213 : : {
214 : : enum hns3_reset_level reset_level;
215 : : uint16_t *msg_q = req->msg;
216 : :
217 : : /*
218 : : * PF has asserted reset hence VF should go in pending
219 : : * state and poll for the hardware reset status till it
220 : : * has been completely reset. After this stack should
221 : : * eventually be re-initialized.
222 : : */
223 : 0 : reset_level = rte_le_to_cpu_16(msg_q[1]);
224 : 0 : hns3_atomic_set_bit(reset_level, &hw->reset.pending);
225 : :
226 : 0 : hns3_warn(hw, "PF inform reset level %d", reset_level);
227 : 0 : hw->reset.stats.request_cnt++;
228 : 0 : hns3_schedule_reset(HNS3_DEV_HW_TO_ADAPTER(hw));
229 : 0 : }
230 : :
231 : : static void
232 : 0 : hns3_handle_mbx_response(struct hns3_hw *hw, struct hns3_mbx_pf_to_vf_cmd *req)
233 : : {
234 : : #define HNS3_MBX_RESP_CODE_OFFSET 16
235 : : struct hns3_mbx_resp_status *resp = &hw->mbx_resp;
236 : : uint32_t msg_data;
237 : :
238 [ # # ]: 0 : if (req->match_id != 0) {
239 : : /*
240 : : * If match_id is not zero, it means PF support copy request's
241 : : * match_id to its response. So VF could use the match_id
242 : : * to match the request.
243 : : */
244 [ # # ]: 0 : if (req->match_id == resp->match_id) {
245 : 0 : resp->resp_status = hns3_resp_to_errno(req->msg[3]);
246 : 0 : memcpy(resp->additional_info, &req->msg[4],
247 : : HNS3_MBX_MAX_RESP_DATA_SIZE);
248 : 0 : rte_io_wmb();
249 : 0 : resp->received_match_resp = true;
250 : : }
251 : 0 : return;
252 : : }
253 : :
254 : : /*
255 : : * If the below instructions can be executed, it means PF does not
256 : : * support copy request's match_id to its response. So VF follows the
257 : : * original scheme to process.
258 : : */
259 : 0 : msg_data = (uint32_t)req->msg[1] << HNS3_MBX_RESP_CODE_OFFSET | req->msg[2];
260 [ # # ]: 0 : if (resp->req_msg_data != msg_data) {
261 : 0 : hns3_warn(hw,
262 : : "received response tag (%u) is mismatched with requested tag (%u)",
263 : : msg_data, resp->req_msg_data);
264 : 0 : return;
265 : : }
266 : :
267 : 0 : resp->resp_status = hns3_resp_to_errno(req->msg[3]);
268 : 0 : memcpy(resp->additional_info, &req->msg[4],
269 : : HNS3_MBX_MAX_RESP_DATA_SIZE);
270 : 0 : rte_io_wmb();
271 : 0 : resp->received_match_resp = true;
272 : : }
273 : :
274 : : static void
275 : 0 : hns3_link_fail_parse(struct hns3_hw *hw, uint8_t link_fail_code)
276 : : {
277 [ # # # # : 0 : switch (link_fail_code) {
# ]
278 : : case HNS3_MBX_LF_NORMAL:
279 : : break;
280 : 0 : case HNS3_MBX_LF_REF_CLOCK_LOST:
281 : 0 : hns3_warn(hw, "Reference clock lost!");
282 : 0 : break;
283 : 0 : case HNS3_MBX_LF_XSFP_TX_DISABLE:
284 : 0 : hns3_warn(hw, "SFP tx is disabled!");
285 : 0 : break;
286 : 0 : case HNS3_MBX_LF_XSFP_ABSENT:
287 : 0 : hns3_warn(hw, "SFP is absent!");
288 : 0 : break;
289 : 0 : default:
290 : 0 : hns3_warn(hw, "Unknown fail code:%u!", link_fail_code);
291 : 0 : break;
292 : : }
293 : 0 : }
294 : :
295 : : static void
296 : 0 : hns3pf_handle_link_change_event(struct hns3_hw *hw,
297 : : struct hns3_mbx_vf_to_pf_cmd *req)
298 : : {
299 : : #define LINK_STATUS_OFFSET 1
300 : : #define LINK_FAIL_CODE_OFFSET 2
301 : :
302 [ # # ]: 0 : if (!req->msg[LINK_STATUS_OFFSET])
303 : 0 : hns3_link_fail_parse(hw, req->msg[LINK_FAIL_CODE_OFFSET]);
304 : :
305 : 0 : hns3_update_linkstatus_and_event(hw, true);
306 : 0 : }
307 : :
308 : : static void
309 : : hns3_update_port_base_vlan_info(struct hns3_hw *hw,
310 : : struct hns3_mbx_pf_to_vf_cmd *req)
311 : : {
312 : : #define PVID_STATE_OFFSET 1
313 : 0 : uint16_t new_pvid_state = req->msg[PVID_STATE_OFFSET] ?
314 : 0 : HNS3_PORT_BASE_VLAN_ENABLE : HNS3_PORT_BASE_VLAN_DISABLE;
315 : : /*
316 : : * Currently, hardware doesn't support more than two layers VLAN offload
317 : : * based on hns3 network engine, which would cause packets loss or wrong
318 : : * packets for these types of packets. If the hns3 PF kernel ethdev
319 : : * driver sets the PVID for VF device after initialization of the
320 : : * related VF device, the PF driver will notify VF driver to update the
321 : : * PVID configuration state. The VF driver will update the PVID
322 : : * configuration state immediately to ensure that the VLAN process in Tx
323 : : * and Rx is correct. But in the window period of this state transition,
324 : : * packets loss or packets with wrong VLAN may occur.
325 : : */
326 [ # # ]: 0 : if (hw->port_base_vlan_cfg.state != new_pvid_state) {
327 : 0 : hw->port_base_vlan_cfg.state = new_pvid_state;
328 : 0 : hns3_update_all_queues_pvid_proc_en(hw);
329 : : }
330 : : }
331 : :
332 : : static void
333 : 0 : hns3_handle_promisc_info(struct hns3_hw *hw, uint16_t promisc_en)
334 : : {
335 [ # # ]: 0 : if (!promisc_en) {
336 : : /*
337 : : * When promisc/allmulti mode is closed by the hns3 PF kernel
338 : : * ethdev driver for untrusted, modify VF's related status.
339 : : */
340 : 0 : hns3_warn(hw, "Promisc mode will be closed by host for being "
341 : : "untrusted.");
342 : 0 : hw->data->promiscuous = 0;
343 : 0 : hw->data->all_multicast = 0;
344 : : }
345 : 0 : }
346 : :
347 : : static void
348 : 0 : hns3_handle_mbx_msg_out_intr(struct hns3_hw *hw)
349 : : {
350 : : struct hns3_cmq_ring *crq = &hw->cmq.crq;
351 : : struct hns3_mbx_pf_to_vf_cmd *req;
352 : : struct hns3_cmd_desc *desc;
353 : : uint32_t tail, next_to_use;
354 : : uint8_t opcode;
355 : : uint16_t flag;
356 : :
357 : 0 : tail = hns3_read_dev(hw, HNS3_CMDQ_RX_TAIL_REG);
358 : 0 : next_to_use = crq->next_to_use;
359 [ # # ]: 0 : while (next_to_use != tail) {
360 : 0 : desc = &crq->desc[next_to_use];
361 : 0 : req = (struct hns3_mbx_pf_to_vf_cmd *)desc->data;
362 : 0 : opcode = req->msg[0] & 0xff;
363 : :
364 : 0 : flag = rte_le_to_cpu_16(crq->desc[next_to_use].flag);
365 [ # # ]: 0 : if (!hns3_get_bit(flag, HNS3_CMDQ_RX_OUTVLD_B))
366 : 0 : goto scan_next;
367 : :
368 [ # # ]: 0 : if (crq->desc[next_to_use].opcode == 0)
369 : 0 : goto scan_next;
370 : :
371 [ # # ]: 0 : if (opcode == HNS3_MBX_PF_VF_RESP) {
372 : 0 : hns3_handle_mbx_response(hw, req);
373 : : /*
374 : : * Clear opcode to inform intr thread don't process
375 : : * again.
376 : : */
377 : 0 : crq->desc[next_to_use].opcode = 0;
378 : : }
379 : :
380 : 0 : scan_next:
381 : 0 : next_to_use = (next_to_use + 1) % hw->cmq.crq.desc_num;
382 : : }
383 : :
384 : : /*
385 : : * Note: the crq->next_to_use field should not updated, otherwise,
386 : : * mailbox messages may be discarded.
387 : : */
388 : 0 : }
389 : :
390 : : void
391 : 0 : hns3_dev_handle_mbx_msg(struct hns3_hw *hw)
392 : : {
393 : : struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
394 : : struct hns3_cmq_ring *crq = &hw->cmq.crq;
395 : : struct hns3_mbx_pf_to_vf_cmd *req;
396 : : struct hns3_cmd_desc *desc;
397 : : bool handle_out;
398 : : uint8_t opcode;
399 : : uint16_t flag;
400 : :
401 : 0 : rte_spinlock_lock(&hw->cmq.crq.lock);
402 : :
403 [ # # ]: 0 : handle_out = (rte_eal_process_type() != RTE_PROC_PRIMARY ||
404 [ # # # # ]: 0 : !rte_thread_is_intr()) && hns->is_vf;
405 [ # # ]: 0 : if (handle_out) {
406 : : /*
407 : : * Currently, any threads in the primary and secondary processes
408 : : * could send mailbox sync request, so it will need to process
409 : : * the crq message (which is the HNS3_MBX_PF_VF_RESP) in there
410 : : * own thread context. It may also process other messages
411 : : * because it uses the policy of processing all pending messages
412 : : * at once.
413 : : * But some messages such as HNS3_MBX_PUSH_LINK_STATUS could
414 : : * only process within the intr thread in primary process,
415 : : * otherwise it may lead to report lsc event in secondary
416 : : * process.
417 : : * So the threads other than intr thread in primary process
418 : : * could only process HNS3_MBX_PF_VF_RESP message, if the
419 : : * message processed, its opcode will rewrite with zero, then
420 : : * the intr thread in primary process will not process again.
421 : : */
422 : 0 : hns3_handle_mbx_msg_out_intr(hw);
423 : : rte_spinlock_unlock(&hw->cmq.crq.lock);
424 : 0 : return;
425 : : }
426 : :
427 [ # # ]: 0 : while (!hns3_cmd_crq_empty(hw)) {
428 [ # # ]: 0 : if (__atomic_load_n(&hw->reset.disable_cmd, __ATOMIC_RELAXED)) {
429 : : rte_spinlock_unlock(&hw->cmq.crq.lock);
430 : 0 : return;
431 : : }
432 : :
433 : 0 : desc = &crq->desc[crq->next_to_use];
434 : 0 : req = (struct hns3_mbx_pf_to_vf_cmd *)desc->data;
435 : 0 : opcode = req->msg[0] & 0xff;
436 : :
437 : 0 : flag = rte_le_to_cpu_16(crq->desc[crq->next_to_use].flag);
438 [ # # ]: 0 : if (unlikely(!hns3_get_bit(flag, HNS3_CMDQ_RX_OUTVLD_B))) {
439 : 0 : hns3_warn(hw,
440 : : "dropped invalid mailbox message, code = %u",
441 : : opcode);
442 : :
443 : : /* dropping/not processing this invalid message */
444 : 0 : crq->desc[crq->next_to_use].flag = 0;
445 : 0 : hns3_mbx_ring_ptr_move_crq(crq);
446 : 0 : continue;
447 : : }
448 : :
449 [ # # # # ]: 0 : handle_out = hns->is_vf && desc->opcode == 0;
450 [ # # ]: 0 : if (handle_out) {
451 : : /* Message already processed by other thread */
452 : 0 : crq->desc[crq->next_to_use].flag = 0;
453 : 0 : hns3_mbx_ring_ptr_move_crq(crq);
454 : 0 : continue;
455 : : }
456 : :
457 [ # # # # : 0 : switch (opcode) {
# # # ]
458 : 0 : case HNS3_MBX_PF_VF_RESP:
459 : 0 : hns3_handle_mbx_response(hw, req);
460 : 0 : break;
461 : 0 : case HNS3_MBX_LINK_STAT_CHANGE:
462 : 0 : hns3vf_handle_link_change_event(hw, req);
463 : 0 : break;
464 : 0 : case HNS3_MBX_ASSERTING_RESET:
465 : 0 : hns3_handle_asserting_reset(hw, req);
466 : 0 : break;
467 : 0 : case HNS3_MBX_PUSH_LINK_STATUS:
468 : : /*
469 : : * This message is reported by the firmware and is
470 : : * reported in 'struct hns3_mbx_vf_to_pf_cmd' format.
471 : : * Therefore, we should cast the req variable to
472 : : * 'struct hns3_mbx_vf_to_pf_cmd' and then process it.
473 : : */
474 : 0 : hns3pf_handle_link_change_event(hw,
475 : : (struct hns3_mbx_vf_to_pf_cmd *)req);
476 : 0 : break;
477 : : case HNS3_MBX_PUSH_VLAN_INFO:
478 : : /*
479 : : * When the PVID configuration status of VF device is
480 : : * changed by the hns3 PF kernel driver, VF driver will
481 : : * receive this mailbox message from PF driver.
482 : : */
483 : : hns3_update_port_base_vlan_info(hw, req);
484 : : break;
485 : 0 : case HNS3_MBX_PUSH_PROMISC_INFO:
486 : : /*
487 : : * When the trust status of VF device changed by the
488 : : * hns3 PF kernel driver, VF driver will receive this
489 : : * mailbox message from PF driver.
490 : : */
491 : 0 : hns3_handle_promisc_info(hw, req->msg[1]);
492 : 0 : break;
493 : 0 : default:
494 : 0 : hns3_err(hw, "received unsupported(%u) mbx msg",
495 : : opcode);
496 : 0 : break;
497 : : }
498 : :
499 : 0 : crq->desc[crq->next_to_use].flag = 0;
500 : 0 : hns3_mbx_ring_ptr_move_crq(crq);
501 : : }
502 : :
503 : : /* Write back CMDQ_RQ header pointer, IMP need this pointer */
504 : 0 : hns3_write_dev(hw, HNS3_CMDQ_RX_HEAD_REG, crq->next_to_use);
505 : :
506 : : rte_spinlock_unlock(&hw->cmq.crq.lock);
507 : : }
|