• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Huawei HiNIC PCI Express Linux driver
4  * Copyright(c) 2017 Huawei Technologies Co., Ltd
5  */
6 
7 #include <linux/kernel.h>
8 #include <linux/types.h>
9 #include <linux/errno.h>
10 #include <linux/pci.h>
11 #include <linux/device.h>
12 #include <linux/semaphore.h>
13 #include <linux/completion.h>
14 #include <linux/slab.h>
15 #include <net/devlink.h>
16 #include <asm/barrier.h>
17 
18 #include "hinic_devlink.h"
19 #include "hinic_hw_if.h"
20 #include "hinic_hw_eqs.h"
21 #include "hinic_hw_api_cmd.h"
22 #include "hinic_hw_mgmt.h"
23 #include "hinic_hw_dev.h"
24 
25 #define SYNC_MSG_ID_MASK                0x1FF
26 
27 #define SYNC_MSG_ID(pf_to_mgmt)         ((pf_to_mgmt)->sync_msg_id)
28 
29 #define SYNC_MSG_ID_INC(pf_to_mgmt)     (SYNC_MSG_ID(pf_to_mgmt) = \
30 					((SYNC_MSG_ID(pf_to_mgmt) + 1) & \
31 					 SYNC_MSG_ID_MASK))
32 
33 #define MSG_SZ_IS_VALID(in_size)        ((in_size) <= MAX_MSG_LEN)
34 
35 #define MGMT_MSG_LEN_MIN                20
36 #define MGMT_MSG_LEN_STEP               16
37 #define MGMT_MSG_RSVD_FOR_DEV           8
38 
39 #define SEGMENT_LEN                     48
40 
41 #define MAX_PF_MGMT_BUF_SIZE            2048
42 
43 /* Data should be SEG LEN size aligned */
44 #define MAX_MSG_LEN                     2016
45 
46 #define MSG_NOT_RESP                    0xFFFF
47 
48 #define MGMT_MSG_TIMEOUT                5000
49 
50 #define SET_FUNC_PORT_MBOX_TIMEOUT	30000
51 
52 #define SET_FUNC_PORT_MGMT_TIMEOUT	25000
53 
54 #define UPDATE_FW_MGMT_TIMEOUT		20000
55 
56 #define mgmt_to_pfhwdev(pf_mgmt)        \
57 		container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt)
58 
59 enum msg_segment_type {
60 	NOT_LAST_SEGMENT = 0,
61 	LAST_SEGMENT     = 1,
62 };
63 
64 enum mgmt_direction_type {
65 	MGMT_DIRECT_SEND = 0,
66 	MGMT_RESP        = 1,
67 };
68 
69 enum msg_ack_type {
70 	MSG_ACK         = 0,
71 	MSG_NO_ACK      = 1,
72 };
73 
74 /**
75  * hinic_register_mgmt_msg_cb - register msg handler for a msg from a module
76  * @pf_to_mgmt: PF to MGMT channel
77  * @mod: module in the chip that this handler will handle its messages
78  * @handle: private data for the callback
79  * @callback: the handler that will handle messages
80  **/
hinic_register_mgmt_msg_cb(struct hinic_pf_to_mgmt * pf_to_mgmt,enum hinic_mod_type mod,void * handle,void (* callback)(void * handle,u8 cmd,void * buf_in,u16 in_size,void * buf_out,u16 * out_size))81 void hinic_register_mgmt_msg_cb(struct hinic_pf_to_mgmt *pf_to_mgmt,
82 				enum hinic_mod_type mod,
83 				void *handle,
84 				void (*callback)(void *handle,
85 						 u8 cmd, void *buf_in,
86 						 u16 in_size, void *buf_out,
87 						 u16 *out_size))
88 {
89 	struct hinic_mgmt_cb *mgmt_cb = &pf_to_mgmt->mgmt_cb[mod];
90 
91 	mgmt_cb->cb = callback;
92 	mgmt_cb->handle = handle;
93 	mgmt_cb->state = HINIC_MGMT_CB_ENABLED;
94 }
95 
96 /**
97  * hinic_unregister_mgmt_msg_cb - unregister msg handler for a msg from a module
98  * @pf_to_mgmt: PF to MGMT channel
99  * @mod: module in the chip that this handler handles its messages
100  **/
hinic_unregister_mgmt_msg_cb(struct hinic_pf_to_mgmt * pf_to_mgmt,enum hinic_mod_type mod)101 void hinic_unregister_mgmt_msg_cb(struct hinic_pf_to_mgmt *pf_to_mgmt,
102 				  enum hinic_mod_type mod)
103 {
104 	struct hinic_mgmt_cb *mgmt_cb = &pf_to_mgmt->mgmt_cb[mod];
105 
106 	mgmt_cb->state &= ~HINIC_MGMT_CB_ENABLED;
107 
108 	while (mgmt_cb->state & HINIC_MGMT_CB_RUNNING)
109 		schedule();
110 
111 	mgmt_cb->cb = NULL;
112 }
113 
114 /**
115  * prepare_header - prepare the header of the message
116  * @pf_to_mgmt: PF to MGMT channel
117  * @msg_len: the length of the message
118  * @mod: module in the chip that will get the message
119  * @ack_type: ask for response
120  * @direction: the direction of the message
121  * @cmd: command of the message
122  * @msg_id: message id
123  *
124  * Return the prepared header value
125  **/
prepare_header(struct hinic_pf_to_mgmt * pf_to_mgmt,u16 msg_len,enum hinic_mod_type mod,enum msg_ack_type ack_type,enum mgmt_direction_type direction,u16 cmd,u16 msg_id)126 static u64 prepare_header(struct hinic_pf_to_mgmt *pf_to_mgmt,
127 			  u16 msg_len, enum hinic_mod_type mod,
128 			  enum msg_ack_type ack_type,
129 			  enum mgmt_direction_type direction,
130 			  u16 cmd, u16 msg_id)
131 {
132 	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
133 
134 	return HINIC_MSG_HEADER_SET(msg_len, MSG_LEN)           |
135 	       HINIC_MSG_HEADER_SET(mod, MODULE)                |
136 	       HINIC_MSG_HEADER_SET(SEGMENT_LEN, SEG_LEN)       |
137 	       HINIC_MSG_HEADER_SET(ack_type, NO_ACK)           |
138 	       HINIC_MSG_HEADER_SET(0, ASYNC_MGMT_TO_PF)        |
139 	       HINIC_MSG_HEADER_SET(0, SEQID)                   |
140 	       HINIC_MSG_HEADER_SET(LAST_SEGMENT, LAST)         |
141 	       HINIC_MSG_HEADER_SET(direction, DIRECTION)       |
142 	       HINIC_MSG_HEADER_SET(cmd, CMD)                   |
143 	       HINIC_MSG_HEADER_SET(HINIC_HWIF_PCI_INTF(hwif), PCI_INTF) |
144 	       HINIC_MSG_HEADER_SET(HINIC_HWIF_PF_IDX(hwif), PF_IDX)     |
145 	       HINIC_MSG_HEADER_SET(msg_id, MSG_ID);
146 }
147 
148 /**
149  * prepare_mgmt_cmd - prepare the mgmt command
150  * @mgmt_cmd: pointer to the command to prepare
151  * @header: pointer of the header for the message
152  * @msg: the data of the message
153  * @msg_len: the length of the message
154  **/
prepare_mgmt_cmd(u8 * mgmt_cmd,u64 * header,u8 * msg,u16 msg_len)155 static void prepare_mgmt_cmd(u8 *mgmt_cmd, u64 *header, u8 *msg, u16 msg_len)
156 {
157 	memset(mgmt_cmd, 0, MGMT_MSG_RSVD_FOR_DEV);
158 
159 	mgmt_cmd += MGMT_MSG_RSVD_FOR_DEV;
160 	memcpy(mgmt_cmd, header, sizeof(*header));
161 
162 	mgmt_cmd += sizeof(*header);
163 	memcpy(mgmt_cmd, msg, msg_len);
164 }
165 
166 /**
167  * mgmt_msg_len - calculate the total message length
168  * @msg_data_len: the length of the message data
169  *
170  * Return the total message length
171  **/
mgmt_msg_len(u16 msg_data_len)172 static u16 mgmt_msg_len(u16 msg_data_len)
173 {
174 	/* RSVD + HEADER_SIZE + DATA_LEN */
175 	u16 msg_len = MGMT_MSG_RSVD_FOR_DEV + sizeof(u64) + msg_data_len;
176 
177 	if (msg_len > MGMT_MSG_LEN_MIN)
178 		msg_len = MGMT_MSG_LEN_MIN +
179 			   ALIGN((msg_len - MGMT_MSG_LEN_MIN),
180 				 MGMT_MSG_LEN_STEP);
181 	else
182 		msg_len = MGMT_MSG_LEN_MIN;
183 
184 	return msg_len;
185 }
186 
187 /**
188  * send_msg_to_mgmt - send message to mgmt by API CMD
189  * @pf_to_mgmt: PF to MGMT channel
190  * @mod: module in the chip that will get the message
191  * @cmd: command of the message
192  * @data: the msg data
193  * @data_len: the msg data length
194  * @ack_type: ask for response
195  * @direction: the direction of the original message
196  * @resp_msg_id: msg id to response for
197  *
198  * Return 0 - Success, negative - Failure
199  **/
send_msg_to_mgmt(struct hinic_pf_to_mgmt * pf_to_mgmt,enum hinic_mod_type mod,u8 cmd,u8 * data,u16 data_len,enum msg_ack_type ack_type,enum mgmt_direction_type direction,u16 resp_msg_id)200 static int send_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
201 			    enum hinic_mod_type mod, u8 cmd,
202 			    u8 *data, u16 data_len,
203 			    enum msg_ack_type ack_type,
204 			    enum mgmt_direction_type direction,
205 			    u16 resp_msg_id)
206 {
207 	struct hinic_api_cmd_chain *chain;
208 	u64 header;
209 	u16 msg_id;
210 
211 	msg_id = SYNC_MSG_ID(pf_to_mgmt);
212 
213 	if (direction == MGMT_RESP) {
214 		header = prepare_header(pf_to_mgmt, data_len, mod, ack_type,
215 					direction, cmd, resp_msg_id);
216 	} else {
217 		SYNC_MSG_ID_INC(pf_to_mgmt);
218 		header = prepare_header(pf_to_mgmt, data_len, mod, ack_type,
219 					direction, cmd, msg_id);
220 	}
221 
222 	prepare_mgmt_cmd(pf_to_mgmt->sync_msg_buf, &header, data, data_len);
223 
224 	chain = pf_to_mgmt->cmd_chain[HINIC_API_CMD_WRITE_TO_MGMT_CPU];
225 	return hinic_api_cmd_write(chain, HINIC_NODE_ID_MGMT,
226 				   pf_to_mgmt->sync_msg_buf,
227 				   mgmt_msg_len(data_len));
228 }
229 
230 /**
231  * msg_to_mgmt_sync - send sync message to mgmt
232  * @pf_to_mgmt: PF to MGMT channel
233  * @mod: module in the chip that will get the message
234  * @cmd: command of the message
235  * @buf_in: the msg data
236  * @in_size: the msg data length
237  * @buf_out: response
238  * @out_size: response length
239  * @direction: the direction of the original message
240  * @resp_msg_id: msg id to response for
241  * @timeout: time-out period of waiting for response
242  *
243  * Return 0 - Success, negative - Failure
244  **/
msg_to_mgmt_sync(struct hinic_pf_to_mgmt * pf_to_mgmt,enum hinic_mod_type mod,u8 cmd,u8 * buf_in,u16 in_size,u8 * buf_out,u16 * out_size,enum mgmt_direction_type direction,u16 resp_msg_id,u32 timeout)245 static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt,
246 			    enum hinic_mod_type mod, u8 cmd,
247 			    u8 *buf_in, u16 in_size,
248 			    u8 *buf_out, u16 *out_size,
249 			    enum mgmt_direction_type direction,
250 			    u16 resp_msg_id, u32 timeout)
251 {
252 	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
253 	struct pci_dev *pdev = hwif->pdev;
254 	struct hinic_recv_msg *recv_msg;
255 	struct completion *recv_done;
256 	unsigned long timeo;
257 	u16 msg_id;
258 	int err;
259 
260 	/* Lock the sync_msg_buf */
261 	down(&pf_to_mgmt->sync_msg_lock);
262 
263 	recv_msg = &pf_to_mgmt->recv_resp_msg_from_mgmt;
264 	recv_done = &recv_msg->recv_done;
265 
266 	if (resp_msg_id == MSG_NOT_RESP)
267 		msg_id = SYNC_MSG_ID(pf_to_mgmt);
268 	else
269 		msg_id = resp_msg_id;
270 
271 	init_completion(recv_done);
272 
273 	err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size,
274 			       MSG_ACK, direction, resp_msg_id);
275 	if (err) {
276 		dev_err(&pdev->dev, "Failed to send sync msg to mgmt\n");
277 		goto unlock_sync_msg;
278 	}
279 
280 	timeo = msecs_to_jiffies(timeout ? timeout : MGMT_MSG_TIMEOUT);
281 
282 	if (!wait_for_completion_timeout(recv_done, timeo)) {
283 		dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id);
284 		hinic_dump_aeq_info(pf_to_mgmt->hwdev);
285 		err = -ETIMEDOUT;
286 		goto unlock_sync_msg;
287 	}
288 
289 	smp_rmb();      /* verify reading after completion */
290 
291 	if (recv_msg->msg_id != msg_id) {
292 		dev_err(&pdev->dev, "incorrect MSG for id = %d\n", msg_id);
293 		err = -EFAULT;
294 		goto unlock_sync_msg;
295 	}
296 
297 	if ((buf_out) && (recv_msg->msg_len <= MAX_PF_MGMT_BUF_SIZE)) {
298 		memcpy(buf_out, recv_msg->msg, recv_msg->msg_len);
299 		*out_size = recv_msg->msg_len;
300 	}
301 
302 unlock_sync_msg:
303 	up(&pf_to_mgmt->sync_msg_lock);
304 	return err;
305 }
306 
307 /**
308  * msg_to_mgmt_async - send message to mgmt without response
309  * @pf_to_mgmt: PF to MGMT channel
310  * @mod: module in the chip that will get the message
311  * @cmd: command of the message
312  * @buf_in: the msg data
313  * @in_size: the msg data length
314  * @direction: the direction of the original message
315  * @resp_msg_id: msg id to response for
316  *
317  * Return 0 - Success, negative - Failure
318  **/
msg_to_mgmt_async(struct hinic_pf_to_mgmt * pf_to_mgmt,enum hinic_mod_type mod,u8 cmd,u8 * buf_in,u16 in_size,enum mgmt_direction_type direction,u16 resp_msg_id)319 static int msg_to_mgmt_async(struct hinic_pf_to_mgmt *pf_to_mgmt,
320 			     enum hinic_mod_type mod, u8 cmd,
321 			     u8 *buf_in, u16 in_size,
322 			     enum mgmt_direction_type direction,
323 			     u16 resp_msg_id)
324 {
325 	int err;
326 
327 	/* Lock the sync_msg_buf */
328 	down(&pf_to_mgmt->sync_msg_lock);
329 
330 	err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size,
331 			       MSG_NO_ACK, direction, resp_msg_id);
332 
333 	up(&pf_to_mgmt->sync_msg_lock);
334 	return err;
335 }
336 
337 /**
338  * hinic_msg_to_mgmt - send message to mgmt
339  * @pf_to_mgmt: PF to MGMT channel
340  * @mod: module in the chip that will get the message
341  * @cmd: command of the message
342  * @buf_in: the msg data
343  * @in_size: the msg data length
344  * @buf_out: response
345  * @out_size: returned response length
346  * @sync: sync msg or async msg
347  *
348  * Return 0 - Success, negative - Failure
349  **/
hinic_msg_to_mgmt(struct hinic_pf_to_mgmt * pf_to_mgmt,enum hinic_mod_type mod,u8 cmd,void * buf_in,u16 in_size,void * buf_out,u16 * out_size,enum hinic_mgmt_msg_type sync)350 int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
351 		      enum hinic_mod_type mod, u8 cmd,
352 		      void *buf_in, u16 in_size, void *buf_out, u16 *out_size,
353 		      enum hinic_mgmt_msg_type sync)
354 {
355 	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
356 	struct pci_dev *pdev = hwif->pdev;
357 	u32 timeout = 0;
358 
359 	if (sync != HINIC_MGMT_MSG_SYNC) {
360 		dev_err(&pdev->dev, "Invalid MGMT msg type\n");
361 		return -EINVAL;
362 	}
363 
364 	if (!MSG_SZ_IS_VALID(in_size)) {
365 		dev_err(&pdev->dev, "Invalid MGMT msg buffer size\n");
366 		return -EINVAL;
367 	}
368 
369 	if (HINIC_IS_VF(hwif)) {
370 		if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
371 			timeout = SET_FUNC_PORT_MBOX_TIMEOUT;
372 
373 		return hinic_mbox_to_pf(pf_to_mgmt->hwdev, mod, cmd, buf_in,
374 					in_size, buf_out, out_size, timeout);
375 	} else {
376 		if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
377 			timeout = SET_FUNC_PORT_MGMT_TIMEOUT;
378 		else if (cmd == HINIC_PORT_CMD_UPDATE_FW)
379 			timeout = UPDATE_FW_MGMT_TIMEOUT;
380 
381 		return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
382 				buf_out, out_size, MGMT_DIRECT_SEND,
383 				MSG_NOT_RESP, timeout);
384 	}
385 }
386 
recv_mgmt_msg_work_handler(struct work_struct * work)387 static void recv_mgmt_msg_work_handler(struct work_struct *work)
388 {
389 	struct hinic_mgmt_msg_handle_work *mgmt_work =
390 		container_of(work, struct hinic_mgmt_msg_handle_work, work);
391 	struct hinic_pf_to_mgmt *pf_to_mgmt = mgmt_work->pf_to_mgmt;
392 	struct pci_dev *pdev = pf_to_mgmt->hwif->pdev;
393 	u8 *buf_out = pf_to_mgmt->mgmt_ack_buf;
394 	struct hinic_mgmt_cb *mgmt_cb;
395 	unsigned long cb_state;
396 	u16 out_size = 0;
397 
398 	memset(buf_out, 0, MAX_PF_MGMT_BUF_SIZE);
399 
400 	if (mgmt_work->mod >= HINIC_MOD_MAX) {
401 		dev_err(&pdev->dev, "Unknown MGMT MSG module = %d\n",
402 			mgmt_work->mod);
403 		kfree(mgmt_work->msg);
404 		kfree(mgmt_work);
405 		return;
406 	}
407 
408 	mgmt_cb = &pf_to_mgmt->mgmt_cb[mgmt_work->mod];
409 
410 	cb_state = cmpxchg(&mgmt_cb->state,
411 			   HINIC_MGMT_CB_ENABLED,
412 			   HINIC_MGMT_CB_ENABLED | HINIC_MGMT_CB_RUNNING);
413 
414 	if ((cb_state == HINIC_MGMT_CB_ENABLED) && (mgmt_cb->cb))
415 		mgmt_cb->cb(mgmt_cb->handle, mgmt_work->cmd,
416 			    mgmt_work->msg, mgmt_work->msg_len,
417 			    buf_out, &out_size);
418 	else
419 		dev_err(&pdev->dev, "No MGMT msg handler, mod: %d, cmd: %d\n",
420 			mgmt_work->mod, mgmt_work->cmd);
421 
422 	mgmt_cb->state &= ~HINIC_MGMT_CB_RUNNING;
423 
424 	if (!mgmt_work->async_mgmt_to_pf)
425 		/* MGMT sent sync msg, send the response */
426 		msg_to_mgmt_async(pf_to_mgmt, mgmt_work->mod, mgmt_work->cmd,
427 				  buf_out, out_size, MGMT_RESP,
428 				  mgmt_work->msg_id);
429 
430 	kfree(mgmt_work->msg);
431 	kfree(mgmt_work);
432 }
433 
434 /**
435  * mgmt_recv_msg_handler - handler for message from mgmt cpu
436  * @pf_to_mgmt: PF to MGMT channel
437  * @recv_msg: received message details
438  **/
mgmt_recv_msg_handler(struct hinic_pf_to_mgmt * pf_to_mgmt,struct hinic_recv_msg * recv_msg)439 static void mgmt_recv_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
440 				  struct hinic_recv_msg *recv_msg)
441 {
442 	struct hinic_mgmt_msg_handle_work *mgmt_work = NULL;
443 	struct pci_dev *pdev = pf_to_mgmt->hwif->pdev;
444 
445 	mgmt_work = kzalloc(sizeof(*mgmt_work), GFP_KERNEL);
446 	if (!mgmt_work) {
447 		dev_err(&pdev->dev, "Allocate mgmt work memory failed\n");
448 		return;
449 	}
450 
451 	if (recv_msg->msg_len) {
452 		mgmt_work->msg = kzalloc(recv_msg->msg_len, GFP_KERNEL);
453 		if (!mgmt_work->msg) {
454 			dev_err(&pdev->dev, "Allocate mgmt msg memory failed\n");
455 			kfree(mgmt_work);
456 			return;
457 		}
458 	}
459 
460 	mgmt_work->pf_to_mgmt = pf_to_mgmt;
461 	mgmt_work->msg_len = recv_msg->msg_len;
462 	memcpy(mgmt_work->msg, recv_msg->msg, recv_msg->msg_len);
463 	mgmt_work->msg_id = recv_msg->msg_id;
464 	mgmt_work->mod = recv_msg->mod;
465 	mgmt_work->cmd = recv_msg->cmd;
466 	mgmt_work->async_mgmt_to_pf = recv_msg->async_mgmt_to_pf;
467 
468 	INIT_WORK(&mgmt_work->work, recv_mgmt_msg_work_handler);
469 	queue_work(pf_to_mgmt->workq, &mgmt_work->work);
470 }
471 
472 /**
473  * mgmt_resp_msg_handler - handler for a response message from mgmt cpu
474  * @pf_to_mgmt: PF to MGMT channel
475  * @recv_msg: received message details
476  **/
mgmt_resp_msg_handler(struct hinic_pf_to_mgmt * pf_to_mgmt,struct hinic_recv_msg * recv_msg)477 static void mgmt_resp_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
478 				  struct hinic_recv_msg *recv_msg)
479 {
480 	wmb();  /* verify writing all, before reading */
481 
482 	complete(&recv_msg->recv_done);
483 }
484 
485 /**
486  * recv_mgmt_msg_handler - handler for a message from mgmt cpu
487  * @pf_to_mgmt: PF to MGMT channel
488  * @header: the header of the message
489  * @recv_msg: received message details
490  **/
recv_mgmt_msg_handler(struct hinic_pf_to_mgmt * pf_to_mgmt,u64 * header,struct hinic_recv_msg * recv_msg)491 static void recv_mgmt_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
492 				  u64 *header, struct hinic_recv_msg *recv_msg)
493 {
494 	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
495 	struct pci_dev *pdev = hwif->pdev;
496 	int seq_id, seg_len;
497 	u8 *msg_body;
498 
499 	seq_id = HINIC_MSG_HEADER_GET(*header, SEQID);
500 	seg_len = HINIC_MSG_HEADER_GET(*header, SEG_LEN);
501 
502 	if (seq_id >= (MAX_MSG_LEN / SEGMENT_LEN)) {
503 		dev_err(&pdev->dev, "recv big mgmt msg\n");
504 		return;
505 	}
506 
507 	msg_body = (u8 *)header + sizeof(*header);
508 	memcpy(recv_msg->msg + seq_id * SEGMENT_LEN, msg_body, seg_len);
509 
510 	if (!HINIC_MSG_HEADER_GET(*header, LAST))
511 		return;
512 
513 	recv_msg->cmd = HINIC_MSG_HEADER_GET(*header, CMD);
514 	recv_msg->mod = HINIC_MSG_HEADER_GET(*header, MODULE);
515 	recv_msg->async_mgmt_to_pf = HINIC_MSG_HEADER_GET(*header,
516 							  ASYNC_MGMT_TO_PF);
517 	recv_msg->msg_len = HINIC_MSG_HEADER_GET(*header, MSG_LEN);
518 	recv_msg->msg_id = HINIC_MSG_HEADER_GET(*header, MSG_ID);
519 
520 	if (HINIC_MSG_HEADER_GET(*header, DIRECTION) == MGMT_RESP)
521 		mgmt_resp_msg_handler(pf_to_mgmt, recv_msg);
522 	else
523 		mgmt_recv_msg_handler(pf_to_mgmt, recv_msg);
524 }
525 
526 /**
527  * mgmt_msg_aeqe_handler - handler for a mgmt message event
528  * @handle: PF to MGMT channel
529  * @data: the header of the message
530  * @size: unused
531  **/
mgmt_msg_aeqe_handler(void * handle,void * data,u8 size)532 static void mgmt_msg_aeqe_handler(void *handle, void *data, u8 size)
533 {
534 	struct hinic_pf_to_mgmt *pf_to_mgmt = handle;
535 	struct hinic_recv_msg *recv_msg;
536 	u64 *header = (u64 *)data;
537 
538 	recv_msg = HINIC_MSG_HEADER_GET(*header, DIRECTION) ==
539 		   MGMT_DIRECT_SEND ?
540 		   &pf_to_mgmt->recv_msg_from_mgmt :
541 		   &pf_to_mgmt->recv_resp_msg_from_mgmt;
542 
543 	recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg);
544 }
545 
546 /**
547  * alloc_recv_msg - allocate receive message memory
548  * @pf_to_mgmt: PF to MGMT channel
549  * @recv_msg: pointer that will hold the allocated data
550  *
551  * Return 0 - Success, negative - Failure
552  **/
alloc_recv_msg(struct hinic_pf_to_mgmt * pf_to_mgmt,struct hinic_recv_msg * recv_msg)553 static int alloc_recv_msg(struct hinic_pf_to_mgmt *pf_to_mgmt,
554 			  struct hinic_recv_msg *recv_msg)
555 {
556 	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
557 	struct pci_dev *pdev = hwif->pdev;
558 
559 	recv_msg->msg = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
560 				     GFP_KERNEL);
561 	if (!recv_msg->msg)
562 		return -ENOMEM;
563 
564 	recv_msg->buf_out = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
565 					 GFP_KERNEL);
566 	if (!recv_msg->buf_out)
567 		return -ENOMEM;
568 
569 	return 0;
570 }
571 
572 /**
573  * alloc_msg_buf - allocate all the message buffers of PF to MGMT channel
574  * @pf_to_mgmt: PF to MGMT channel
575  *
576  * Return 0 - Success, negative - Failure
577  **/
alloc_msg_buf(struct hinic_pf_to_mgmt * pf_to_mgmt)578 static int alloc_msg_buf(struct hinic_pf_to_mgmt *pf_to_mgmt)
579 {
580 	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
581 	struct pci_dev *pdev = hwif->pdev;
582 	int err;
583 
584 	err = alloc_recv_msg(pf_to_mgmt,
585 			     &pf_to_mgmt->recv_msg_from_mgmt);
586 	if (err) {
587 		dev_err(&pdev->dev, "Failed to allocate recv msg\n");
588 		return err;
589 	}
590 
591 	err = alloc_recv_msg(pf_to_mgmt,
592 			     &pf_to_mgmt->recv_resp_msg_from_mgmt);
593 	if (err) {
594 		dev_err(&pdev->dev, "Failed to allocate resp recv msg\n");
595 		return err;
596 	}
597 
598 	pf_to_mgmt->sync_msg_buf = devm_kzalloc(&pdev->dev,
599 						MAX_PF_MGMT_BUF_SIZE,
600 						GFP_KERNEL);
601 	if (!pf_to_mgmt->sync_msg_buf)
602 		return -ENOMEM;
603 
604 	pf_to_mgmt->mgmt_ack_buf = devm_kzalloc(&pdev->dev,
605 						MAX_PF_MGMT_BUF_SIZE,
606 						GFP_KERNEL);
607 	if (!pf_to_mgmt->mgmt_ack_buf)
608 		return -ENOMEM;
609 
610 	return 0;
611 }
612 
613 /**
614  * hinic_pf_to_mgmt_init - initialize PF to MGMT channel
615  * @pf_to_mgmt: PF to MGMT channel
616  * @hwif: HW interface the PF to MGMT will use for accessing HW
617  *
618  * Return 0 - Success, negative - Failure
619  **/
hinic_pf_to_mgmt_init(struct hinic_pf_to_mgmt * pf_to_mgmt,struct hinic_hwif * hwif)620 int hinic_pf_to_mgmt_init(struct hinic_pf_to_mgmt *pf_to_mgmt,
621 			  struct hinic_hwif *hwif)
622 {
623 	struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
624 	struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
625 	struct pci_dev *pdev = hwif->pdev;
626 	int err;
627 
628 	pf_to_mgmt->hwif = hwif;
629 	pf_to_mgmt->hwdev = hwdev;
630 
631 	if (HINIC_IS_VF(hwif))
632 		return 0;
633 
634 	err = hinic_health_reporters_create(hwdev->devlink_dev);
635 	if (err)
636 		return err;
637 
638 	sema_init(&pf_to_mgmt->sync_msg_lock, 1);
639 	pf_to_mgmt->workq = create_singlethread_workqueue("hinic_mgmt");
640 	if (!pf_to_mgmt->workq) {
641 		dev_err(&pdev->dev, "Failed to initialize MGMT workqueue\n");
642 		hinic_health_reporters_destroy(hwdev->devlink_dev);
643 		return -ENOMEM;
644 	}
645 	pf_to_mgmt->sync_msg_id = 0;
646 
647 	err = alloc_msg_buf(pf_to_mgmt);
648 	if (err) {
649 		dev_err(&pdev->dev, "Failed to allocate msg buffers\n");
650 		hinic_health_reporters_destroy(hwdev->devlink_dev);
651 		return err;
652 	}
653 
654 	err = hinic_api_cmd_init(pf_to_mgmt->cmd_chain, hwif);
655 	if (err) {
656 		dev_err(&pdev->dev, "Failed to initialize cmd chains\n");
657 		hinic_health_reporters_destroy(hwdev->devlink_dev);
658 		return err;
659 	}
660 
661 	hinic_aeq_register_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU,
662 				 pf_to_mgmt,
663 				 mgmt_msg_aeqe_handler);
664 	return 0;
665 }
666 
667 /**
668  * hinic_pf_to_mgmt_free - free PF to MGMT channel
669  * @pf_to_mgmt: PF to MGMT channel
670  **/
hinic_pf_to_mgmt_free(struct hinic_pf_to_mgmt * pf_to_mgmt)671 void hinic_pf_to_mgmt_free(struct hinic_pf_to_mgmt *pf_to_mgmt)
672 {
673 	struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
674 	struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
675 
676 	if (HINIC_IS_VF(hwdev->hwif))
677 		return;
678 
679 	hinic_aeq_unregister_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU);
680 	hinic_api_cmd_free(pf_to_mgmt->cmd_chain);
681 	destroy_workqueue(pf_to_mgmt->workq);
682 	hinic_health_reporters_destroy(hwdev->devlink_dev);
683 }
684