1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // Copyright (c) 2016-2017 Hisilicon Limited. |
3 | |
4 | #include "hclge_mbx.h" |
5 | #include "hclgevf_main.h" |
6 | #include "hnae3.h" |
7 | |
8 | #define CREATE_TRACE_POINTS |
9 | #include "hclgevf_trace.h" |
10 | |
11 | static int hclgevf_resp_to_errno(u16 resp_code) |
12 | { |
13 | return resp_code ? -resp_code : 0; |
14 | } |
15 | |
16 | #define HCLGEVF_MBX_MATCH_ID_START 1 |
17 | static void hclgevf_reset_mbx_resp_status(struct hclgevf_dev *hdev) |
18 | { |
19 | /* this function should be called with mbx_resp.mbx_mutex held |
20 | * to protect the received_response from race condition |
21 | */ |
22 | hdev->mbx_resp.received_resp = false; |
23 | hdev->mbx_resp.origin_mbx_msg = 0; |
24 | hdev->mbx_resp.resp_status = 0; |
25 | hdev->mbx_resp.match_id++; |
26 | /* Update match_id and ensure the value of match_id is not zero */ |
27 | if (hdev->mbx_resp.match_id == 0) |
28 | hdev->mbx_resp.match_id = HCLGEVF_MBX_MATCH_ID_START; |
29 | memset(hdev->mbx_resp.additional_info, 0, HCLGE_MBX_MAX_RESP_DATA_SIZE); |
30 | } |
31 | |
32 | /* hclgevf_get_mbx_resp: used to get a response from PF after VF sends a mailbox |
33 | * message to PF. |
34 | * @hdev: pointer to struct hclgevf_dev |
35 | * @code0: the message opcode VF send to PF. |
36 | * @code1: the message sub-opcode VF send to PF. |
37 | * @resp_data: pointer to store response data from PF to VF. |
38 | * @resp_len: the length of resp_data from PF to VF. |
39 | */ |
40 | static int hclgevf_get_mbx_resp(struct hclgevf_dev *hdev, u16 code0, u16 code1, |
41 | u8 *resp_data, u16 resp_len) |
42 | { |
43 | #define HCLGEVF_MAX_TRY_TIMES 500 |
44 | #define HCLGEVF_SLEEP_USECOND 1000 |
45 | struct hclgevf_mbx_resp_status *mbx_resp; |
46 | u16 r_code0, r_code1; |
47 | int i = 0; |
48 | |
49 | if (resp_len > HCLGE_MBX_MAX_RESP_DATA_SIZE) { |
50 | dev_err(&hdev->pdev->dev, |
51 | "VF mbx response len(=%u) exceeds maximum(=%u)\n" , |
52 | resp_len, |
53 | HCLGE_MBX_MAX_RESP_DATA_SIZE); |
54 | return -EINVAL; |
55 | } |
56 | |
57 | while ((!hdev->mbx_resp.received_resp) && (i < HCLGEVF_MAX_TRY_TIMES)) { |
58 | if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE, |
59 | &hdev->hw.hw.comm_state)) |
60 | return -EIO; |
61 | |
62 | usleep_range(HCLGEVF_SLEEP_USECOND, HCLGEVF_SLEEP_USECOND * 2); |
63 | i++; |
64 | } |
65 | |
66 | /* ensure additional_info will be seen after received_resp */ |
67 | smp_rmb(); |
68 | |
69 | if (i >= HCLGEVF_MAX_TRY_TIMES) { |
70 | dev_err(&hdev->pdev->dev, |
71 | "VF could not get mbx(%u,%u) resp(=%d) from PF in %d tries\n" , |
72 | code0, code1, hdev->mbx_resp.received_resp, i); |
73 | return -EIO; |
74 | } |
75 | |
76 | mbx_resp = &hdev->mbx_resp; |
77 | r_code0 = (u16)(mbx_resp->origin_mbx_msg >> 16); |
78 | r_code1 = (u16)(mbx_resp->origin_mbx_msg & 0xff); |
79 | |
80 | if (mbx_resp->resp_status) |
81 | return mbx_resp->resp_status; |
82 | |
83 | if (resp_data) |
84 | memcpy(resp_data, &mbx_resp->additional_info[0], resp_len); |
85 | |
86 | hclgevf_reset_mbx_resp_status(hdev); |
87 | |
88 | if (!(r_code0 == code0 && r_code1 == code1 && !mbx_resp->resp_status)) { |
89 | dev_err(&hdev->pdev->dev, |
90 | "VF could not match resp code(code0=%u,code1=%u), %d\n" , |
91 | code0, code1, mbx_resp->resp_status); |
92 | dev_err(&hdev->pdev->dev, |
93 | "VF could not match resp r_code(r_code0=%u,r_code1=%u)\n" , |
94 | r_code0, r_code1); |
95 | return -EIO; |
96 | } |
97 | |
98 | return 0; |
99 | } |
100 | |
101 | int hclgevf_send_mbx_msg(struct hclgevf_dev *hdev, |
102 | struct hclge_vf_to_pf_msg *send_msg, bool need_resp, |
103 | u8 *resp_data, u16 resp_len) |
104 | { |
105 | struct hclge_mbx_vf_to_pf_cmd *req; |
106 | struct hclge_desc desc; |
107 | int status; |
108 | |
109 | req = (struct hclge_mbx_vf_to_pf_cmd *)desc.data; |
110 | |
111 | if (!send_msg) { |
112 | dev_err(&hdev->pdev->dev, |
113 | "failed to send mbx, msg is NULL\n" ); |
114 | return -EINVAL; |
115 | } |
116 | |
117 | hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_MBX_VF_TO_PF, false); |
118 | if (need_resp) |
119 | hnae3_set_bit(req->mbx_need_resp, HCLGE_MBX_NEED_RESP_B, 1); |
120 | |
121 | memcpy(&req->msg, send_msg, sizeof(struct hclge_vf_to_pf_msg)); |
122 | |
123 | if (test_bit(HCLGEVF_STATE_NIC_REGISTERED, &hdev->state)) |
124 | trace_hclge_vf_mbx_send(hdev, req); |
125 | |
126 | /* synchronous send */ |
127 | if (need_resp) { |
128 | mutex_lock(&hdev->mbx_resp.mbx_mutex); |
129 | hclgevf_reset_mbx_resp_status(hdev); |
130 | req->match_id = cpu_to_le16(hdev->mbx_resp.match_id); |
131 | status = hclgevf_cmd_send(hw: &hdev->hw, desc: &desc, num: 1); |
132 | if (status) { |
133 | dev_err(&hdev->pdev->dev, |
134 | "VF failed(=%d) to send mbx message to PF\n" , |
135 | status); |
136 | mutex_unlock(lock: &hdev->mbx_resp.mbx_mutex); |
137 | return status; |
138 | } |
139 | |
140 | status = hclgevf_get_mbx_resp(hdev, code0: send_msg->code, |
141 | code1: send_msg->subcode, resp_data, |
142 | resp_len); |
143 | mutex_unlock(lock: &hdev->mbx_resp.mbx_mutex); |
144 | } else { |
145 | /* asynchronous send */ |
146 | status = hclgevf_cmd_send(hw: &hdev->hw, desc: &desc, num: 1); |
147 | if (status) { |
148 | dev_err(&hdev->pdev->dev, |
149 | "VF failed(=%d) to send mbx message to PF\n" , |
150 | status); |
151 | return status; |
152 | } |
153 | } |
154 | |
155 | return status; |
156 | } |
157 | |
158 | static bool hclgevf_cmd_crq_empty(struct hclgevf_hw *hw) |
159 | { |
160 | u32 tail = hclgevf_read_dev(hw, HCLGE_COMM_NIC_CRQ_TAIL_REG); |
161 | |
162 | return tail == hw->hw.cmq.crq.next_to_use; |
163 | } |
164 | |
165 | static void hclgevf_handle_mbx_response(struct hclgevf_dev *hdev, |
166 | struct hclge_mbx_pf_to_vf_cmd *req) |
167 | { |
168 | u16 vf_mbx_msg_subcode = le16_to_cpu(req->msg.vf_mbx_msg_subcode); |
169 | u16 vf_mbx_msg_code = le16_to_cpu(req->msg.vf_mbx_msg_code); |
170 | struct hclgevf_mbx_resp_status *resp = &hdev->mbx_resp; |
171 | u16 resp_status = le16_to_cpu(req->msg.resp_status); |
172 | u16 match_id = le16_to_cpu(req->match_id); |
173 | |
174 | if (resp->received_resp) |
175 | dev_warn(&hdev->pdev->dev, |
176 | "VF mbx resp flag not clear(%u)\n" , |
177 | vf_mbx_msg_code); |
178 | |
179 | resp->origin_mbx_msg = (vf_mbx_msg_code << 16); |
180 | resp->origin_mbx_msg |= vf_mbx_msg_subcode; |
181 | resp->resp_status = hclgevf_resp_to_errno(resp_code: resp_status); |
182 | memcpy(resp->additional_info, req->msg.resp_data, |
183 | HCLGE_MBX_MAX_RESP_DATA_SIZE * sizeof(u8)); |
184 | |
185 | /* ensure additional_info will be seen before setting received_resp */ |
186 | smp_wmb(); |
187 | |
188 | if (match_id) { |
189 | /* If match_id is not zero, it means PF support match_id. |
190 | * if the match_id is right, VF get the right response, or |
191 | * ignore the response. and driver will clear hdev->mbx_resp |
192 | * when send next message which need response. |
193 | */ |
194 | if (match_id == resp->match_id) |
195 | resp->received_resp = true; |
196 | } else { |
197 | resp->received_resp = true; |
198 | } |
199 | } |
200 | |
201 | static void hclgevf_handle_mbx_msg(struct hclgevf_dev *hdev, |
202 | struct hclge_mbx_pf_to_vf_cmd *req) |
203 | { |
204 | /* we will drop the async msg if we find ARQ as full |
205 | * and continue with next message |
206 | */ |
207 | if (atomic_read(v: &hdev->arq.count) >= |
208 | HCLGE_MBX_MAX_ARQ_MSG_NUM) { |
209 | dev_warn(&hdev->pdev->dev, |
210 | "Async Q full, dropping msg(%u)\n" , |
211 | le16_to_cpu(req->msg.code)); |
212 | return; |
213 | } |
214 | |
215 | /* tail the async message in arq */ |
216 | memcpy(hdev->arq.msg_q[hdev->arq.tail], &req->msg, |
217 | HCLGE_MBX_MAX_ARQ_MSG_SIZE * sizeof(u16)); |
218 | hclge_mbx_tail_ptr_move_arq(hdev->arq); |
219 | atomic_inc(v: &hdev->arq.count); |
220 | |
221 | hclgevf_mbx_task_schedule(hdev); |
222 | } |
223 | |
224 | void hclgevf_mbx_handler(struct hclgevf_dev *hdev) |
225 | { |
226 | struct hclge_mbx_pf_to_vf_cmd *req; |
227 | struct hclge_comm_cmq_ring *crq; |
228 | struct hclge_desc *desc; |
229 | u16 flag; |
230 | u16 code; |
231 | |
232 | crq = &hdev->hw.hw.cmq.crq; |
233 | |
234 | while (!hclgevf_cmd_crq_empty(hw: &hdev->hw)) { |
235 | if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE, |
236 | &hdev->hw.hw.comm_state)) { |
237 | dev_info(&hdev->pdev->dev, "vf crq need init\n" ); |
238 | return; |
239 | } |
240 | |
241 | desc = &crq->desc[crq->next_to_use]; |
242 | req = (struct hclge_mbx_pf_to_vf_cmd *)desc->data; |
243 | |
244 | flag = le16_to_cpu(crq->desc[crq->next_to_use].flag); |
245 | code = le16_to_cpu(req->msg.code); |
246 | if (unlikely(!hnae3_get_bit(flag, HCLGEVF_CMDQ_RX_OUTVLD_B))) { |
247 | dev_warn(&hdev->pdev->dev, |
248 | "dropped invalid mailbox message, code = %u\n" , |
249 | code); |
250 | |
251 | /* dropping/not processing this invalid message */ |
252 | crq->desc[crq->next_to_use].flag = 0; |
253 | hclge_mbx_ring_ptr_move_crq(crq); |
254 | continue; |
255 | } |
256 | |
257 | trace_hclge_vf_mbx_get(hdev, req); |
258 | |
259 | /* synchronous messages are time critical and need preferential |
260 | * treatment. Therefore, we need to acknowledge all the sync |
261 | * responses as quickly as possible so that waiting tasks do not |
262 | * timeout and simultaneously queue the async messages for later |
263 | * prcessing in context of mailbox task i.e. the slow path. |
264 | */ |
265 | switch (code) { |
266 | case HCLGE_MBX_PF_VF_RESP: |
267 | hclgevf_handle_mbx_response(hdev, req); |
268 | break; |
269 | case HCLGE_MBX_LINK_STAT_CHANGE: |
270 | case HCLGE_MBX_ASSERTING_RESET: |
271 | case HCLGE_MBX_LINK_STAT_MODE: |
272 | case HCLGE_MBX_PUSH_VLAN_INFO: |
273 | case HCLGE_MBX_PUSH_PROMISC_INFO: |
274 | hclgevf_handle_mbx_msg(hdev, req); |
275 | break; |
276 | default: |
277 | dev_err(&hdev->pdev->dev, |
278 | "VF received unsupported(%u) mbx msg from PF\n" , |
279 | code); |
280 | break; |
281 | } |
282 | crq->desc[crq->next_to_use].flag = 0; |
283 | hclge_mbx_ring_ptr_move_crq(crq); |
284 | } |
285 | |
286 | /* Write back CMDQ_RQ header pointer, M7 need this pointer */ |
287 | hclgevf_write_dev(&hdev->hw, HCLGE_COMM_NIC_CRQ_HEAD_REG, |
288 | crq->next_to_use); |
289 | } |
290 | |
291 | static void hclgevf_parse_promisc_info(struct hclgevf_dev *hdev, |
292 | u16 promisc_info) |
293 | { |
294 | if (!promisc_info) |
295 | dev_info(&hdev->pdev->dev, |
296 | "Promisc mode is closed by host for being untrusted.\n" ); |
297 | } |
298 | |
299 | void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) |
300 | { |
301 | struct hclge_mbx_port_base_vlan *vlan_info; |
302 | struct hclge_mbx_link_status *link_info; |
303 | struct hclge_mbx_link_mode *link_mode; |
304 | enum hnae3_reset_type reset_type; |
305 | u16 link_status, state; |
306 | __le16 *msg_q; |
307 | u16 opcode; |
308 | u8 duplex; |
309 | u32 speed; |
310 | u32 tail; |
311 | u8 flag; |
312 | u16 idx; |
313 | |
314 | tail = hdev->arq.tail; |
315 | |
316 | /* process all the async queue messages */ |
317 | while (tail != hdev->arq.head) { |
318 | if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE, |
319 | &hdev->hw.hw.comm_state)) { |
320 | dev_info(&hdev->pdev->dev, |
321 | "vf crq need init in async\n" ); |
322 | return; |
323 | } |
324 | |
325 | msg_q = hdev->arq.msg_q[hdev->arq.head]; |
326 | opcode = le16_to_cpu(msg_q[0]); |
327 | switch (opcode) { |
328 | case HCLGE_MBX_LINK_STAT_CHANGE: |
329 | link_info = (struct hclge_mbx_link_status *)(msg_q + 1); |
330 | link_status = le16_to_cpu(link_info->link_status); |
331 | speed = le32_to_cpu(link_info->speed); |
332 | duplex = (u8)le16_to_cpu(link_info->duplex); |
333 | flag = link_info->flag; |
334 | |
335 | /* update upper layer with new link link status */ |
336 | hclgevf_update_speed_duplex(hdev, speed, duplex); |
337 | hclgevf_update_link_status(hdev, link_state: link_status); |
338 | |
339 | if (flag & HCLGE_MBX_PUSH_LINK_STATUS_EN) |
340 | set_bit(nr: HCLGEVF_STATE_PF_PUSH_LINK_STATUS, |
341 | addr: &hdev->state); |
342 | |
343 | break; |
344 | case HCLGE_MBX_LINK_STAT_MODE: |
345 | link_mode = (struct hclge_mbx_link_mode *)(msg_q + 1); |
346 | idx = le16_to_cpu(link_mode->idx); |
347 | if (idx) |
348 | hdev->hw.mac.supported = |
349 | le64_to_cpu(link_mode->link_mode); |
350 | else |
351 | hdev->hw.mac.advertising = |
352 | le64_to_cpu(link_mode->link_mode); |
353 | break; |
354 | case HCLGE_MBX_ASSERTING_RESET: |
355 | /* PF has asserted reset hence VF should go in pending |
356 | * state and poll for the hardware reset status till it |
357 | * has been completely reset. After this stack should |
358 | * eventually be re-initialized. |
359 | */ |
360 | reset_type = |
361 | (enum hnae3_reset_type)le16_to_cpu(msg_q[1]); |
362 | set_bit(nr: reset_type, addr: &hdev->reset_pending); |
363 | set_bit(HCLGEVF_RESET_PENDING, addr: &hdev->reset_state); |
364 | hclgevf_reset_task_schedule(hdev); |
365 | |
366 | break; |
367 | case HCLGE_MBX_PUSH_VLAN_INFO: |
368 | vlan_info = |
369 | (struct hclge_mbx_port_base_vlan *)(msg_q + 1); |
370 | state = le16_to_cpu(vlan_info->state); |
371 | hclgevf_update_port_base_vlan_info(hdev, state, |
372 | port_base_vlan: vlan_info); |
373 | break; |
374 | case HCLGE_MBX_PUSH_PROMISC_INFO: |
375 | hclgevf_parse_promisc_info(hdev, le16_to_cpu(msg_q[1])); |
376 | break; |
377 | default: |
378 | dev_err(&hdev->pdev->dev, |
379 | "fetched unsupported(%u) message from arq\n" , |
380 | opcode); |
381 | break; |
382 | } |
383 | |
384 | hclge_mbx_head_ptr_move_arq(hdev->arq); |
385 | atomic_dec(v: &hdev->arq.count); |
386 | msg_q = hdev->arq.msg_q[hdev->arq.head]; |
387 | } |
388 | } |
389 | |