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/pci.h> |
10 | #include <linux/device.h> |
11 | #include <linux/errno.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/bitops.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/jiffies.h> |
16 | #include <linux/log2.h> |
17 | #include <linux/err.h> |
18 | #include <linux/netdevice.h> |
19 | #include <net/devlink.h> |
20 | |
21 | #include "hinic_devlink.h" |
22 | #include "hinic_sriov.h" |
23 | #include "hinic_dev.h" |
24 | #include "hinic_hw_if.h" |
25 | #include "hinic_hw_eqs.h" |
26 | #include "hinic_hw_mgmt.h" |
27 | #include "hinic_hw_qp_ctxt.h" |
28 | #include "hinic_hw_qp.h" |
29 | #include "hinic_hw_io.h" |
30 | #include "hinic_hw_dev.h" |
31 | |
32 | #define OUTBOUND_STATE_TIMEOUT 100 |
33 | #define DB_STATE_TIMEOUT 100 |
34 | |
35 | #define MAX_IRQS(max_qps, num_aeqs, num_ceqs) \ |
36 | (2 * (max_qps) + (num_aeqs) + (num_ceqs)) |
37 | |
38 | #define ADDR_IN_4BYTES(addr) ((addr) >> 2) |
39 | |
40 | enum intr_type { |
41 | INTR_MSIX_TYPE, |
42 | }; |
43 | |
44 | /** |
45 | * parse_capability - convert device capabilities to NIC capabilities |
46 | * @hwdev: the HW device to set and convert device capabilities for |
47 | * @dev_cap: device capabilities from FW |
48 | * |
49 | * Return 0 - Success, negative - Failure |
50 | **/ |
51 | static int parse_capability(struct hinic_hwdev *hwdev, |
52 | struct hinic_dev_cap *dev_cap) |
53 | { |
54 | struct hinic_cap *nic_cap = &hwdev->nic_cap; |
55 | int num_aeqs, num_ceqs, num_irqs; |
56 | |
57 | if (!HINIC_IS_VF(hwdev->hwif) && dev_cap->intr_type != INTR_MSIX_TYPE) |
58 | return -EFAULT; |
59 | |
60 | num_aeqs = HINIC_HWIF_NUM_AEQS(hwdev->hwif); |
61 | num_ceqs = HINIC_HWIF_NUM_CEQS(hwdev->hwif); |
62 | num_irqs = HINIC_HWIF_NUM_IRQS(hwdev->hwif); |
63 | |
64 | /* Each QP has its own (SQ + RQ) interrupts */ |
65 | nic_cap->num_qps = (num_irqs - (num_aeqs + num_ceqs)) / 2; |
66 | |
67 | if (nic_cap->num_qps > HINIC_Q_CTXT_MAX) |
68 | nic_cap->num_qps = HINIC_Q_CTXT_MAX; |
69 | |
70 | if (!HINIC_IS_VF(hwdev->hwif)) |
71 | nic_cap->max_qps = dev_cap->max_sqs + 1; |
72 | else |
73 | nic_cap->max_qps = dev_cap->max_sqs; |
74 | |
75 | if (nic_cap->num_qps > nic_cap->max_qps) |
76 | nic_cap->num_qps = nic_cap->max_qps; |
77 | |
78 | if (!HINIC_IS_VF(hwdev->hwif)) { |
79 | nic_cap->max_vf = dev_cap->max_vf; |
80 | nic_cap->max_vf_qps = dev_cap->max_vf_sqs + 1; |
81 | } |
82 | |
83 | hwdev->port_id = dev_cap->port_id; |
84 | |
85 | return 0; |
86 | } |
87 | |
88 | /** |
89 | * get_capability - get device capabilities from FW |
90 | * @pfhwdev: the PF HW device to get capabilities for |
91 | * |
92 | * Return 0 - Success, negative - Failure |
93 | **/ |
94 | static int get_capability(struct hinic_pfhwdev *pfhwdev) |
95 | { |
96 | struct hinic_hwdev *hwdev = &pfhwdev->hwdev; |
97 | struct hinic_hwif *hwif = hwdev->hwif; |
98 | struct pci_dev *pdev = hwif->pdev; |
99 | struct hinic_dev_cap dev_cap; |
100 | u16 out_len; |
101 | int err; |
102 | |
103 | out_len = sizeof(dev_cap); |
104 | |
105 | err = hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_CFGM, |
106 | cmd: HINIC_CFG_NIC_CAP, buf_in: &dev_cap, in_size: sizeof(dev_cap), |
107 | buf_out: &dev_cap, out_size: &out_len, sync: HINIC_MGMT_MSG_SYNC); |
108 | if (err) { |
109 | dev_err(&pdev->dev, "Failed to get capability from FW\n" ); |
110 | return err; |
111 | } |
112 | |
113 | return parse_capability(hwdev, dev_cap: &dev_cap); |
114 | } |
115 | |
116 | /** |
117 | * get_dev_cap - get device capabilities |
118 | * @hwdev: the NIC HW device to get capabilities for |
119 | * |
120 | * Return 0 - Success, negative - Failure |
121 | **/ |
122 | static int get_dev_cap(struct hinic_hwdev *hwdev) |
123 | { |
124 | struct hinic_hwif *hwif = hwdev->hwif; |
125 | struct pci_dev *pdev = hwif->pdev; |
126 | struct hinic_pfhwdev *pfhwdev; |
127 | int err; |
128 | |
129 | switch (HINIC_FUNC_TYPE(hwif)) { |
130 | case HINIC_PPF: |
131 | case HINIC_PF: |
132 | case HINIC_VF: |
133 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
134 | err = get_capability(pfhwdev); |
135 | if (err) { |
136 | dev_err(&pdev->dev, "Failed to get capability\n" ); |
137 | return err; |
138 | } |
139 | break; |
140 | default: |
141 | dev_err(&pdev->dev, "Unsupported PCI Function type\n" ); |
142 | return -EINVAL; |
143 | } |
144 | |
145 | return 0; |
146 | } |
147 | |
148 | /** |
149 | * init_msix - enable the msix and save the entries |
150 | * @hwdev: the NIC HW device |
151 | * |
152 | * Return 0 - Success, negative - Failure |
153 | **/ |
154 | static int init_msix(struct hinic_hwdev *hwdev) |
155 | { |
156 | struct hinic_hwif *hwif = hwdev->hwif; |
157 | struct pci_dev *pdev = hwif->pdev; |
158 | int nr_irqs, num_aeqs, num_ceqs; |
159 | int i, err; |
160 | |
161 | num_aeqs = HINIC_HWIF_NUM_AEQS(hwif); |
162 | num_ceqs = HINIC_HWIF_NUM_CEQS(hwif); |
163 | nr_irqs = MAX_IRQS(HINIC_MAX_QPS, num_aeqs, num_ceqs); |
164 | if (nr_irqs > HINIC_HWIF_NUM_IRQS(hwif)) |
165 | nr_irqs = HINIC_HWIF_NUM_IRQS(hwif); |
166 | |
167 | hwdev->msix_entries = devm_kcalloc(dev: &pdev->dev, n: nr_irqs, |
168 | size: sizeof(*hwdev->msix_entries), |
169 | GFP_KERNEL); |
170 | if (!hwdev->msix_entries) |
171 | return -ENOMEM; |
172 | |
173 | for (i = 0; i < nr_irqs; i++) |
174 | hwdev->msix_entries[i].entry = i; |
175 | |
176 | err = pci_enable_msix_exact(dev: pdev, entries: hwdev->msix_entries, nvec: nr_irqs); |
177 | if (err) { |
178 | dev_err(&pdev->dev, "Failed to enable pci msix\n" ); |
179 | return err; |
180 | } |
181 | |
182 | return 0; |
183 | } |
184 | |
185 | /** |
186 | * disable_msix - disable the msix |
187 | * @hwdev: the NIC HW device |
188 | **/ |
189 | static void disable_msix(struct hinic_hwdev *hwdev) |
190 | { |
191 | struct hinic_hwif *hwif = hwdev->hwif; |
192 | struct pci_dev *pdev = hwif->pdev; |
193 | |
194 | pci_disable_msix(dev: pdev); |
195 | } |
196 | |
197 | /** |
198 | * hinic_port_msg_cmd - send port msg to mgmt |
199 | * @hwdev: the NIC HW device |
200 | * @cmd: the port command |
201 | * @buf_in: input buffer |
202 | * @in_size: input size |
203 | * @buf_out: output buffer |
204 | * @out_size: returned output size |
205 | * |
206 | * Return 0 - Success, negative - Failure |
207 | **/ |
208 | int hinic_port_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_port_cmd cmd, |
209 | void *buf_in, u16 in_size, void *buf_out, u16 *out_size) |
210 | { |
211 | struct hinic_pfhwdev *pfhwdev; |
212 | |
213 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
214 | |
215 | return hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_L2NIC, cmd, |
216 | buf_in, in_size, buf_out, out_size, |
217 | sync: HINIC_MGMT_MSG_SYNC); |
218 | } |
219 | |
220 | int hinic_hilink_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_hilink_cmd cmd, |
221 | void *buf_in, u16 in_size, void *buf_out, |
222 | u16 *out_size) |
223 | { |
224 | struct hinic_pfhwdev *pfhwdev; |
225 | |
226 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
227 | |
228 | return hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_HILINK, cmd, |
229 | buf_in, in_size, buf_out, out_size, |
230 | sync: HINIC_MGMT_MSG_SYNC); |
231 | } |
232 | |
233 | /** |
234 | * init_fw_ctxt- Init Firmware tables before network mgmt and io operations |
235 | * @hwdev: the NIC HW device |
236 | * |
237 | * Return 0 - Success, negative - Failure |
238 | **/ |
239 | static int init_fw_ctxt(struct hinic_hwdev *hwdev) |
240 | { |
241 | struct hinic_hwif *hwif = hwdev->hwif; |
242 | struct pci_dev *pdev = hwif->pdev; |
243 | struct hinic_cmd_fw_ctxt fw_ctxt; |
244 | u16 out_size = sizeof(fw_ctxt); |
245 | int err; |
246 | |
247 | fw_ctxt.func_idx = HINIC_HWIF_FUNC_IDX(hwif); |
248 | fw_ctxt.rx_buf_sz = HINIC_RX_BUF_SZ; |
249 | |
250 | err = hinic_port_msg_cmd(hwdev, cmd: HINIC_PORT_CMD_FWCTXT_INIT, |
251 | buf_in: &fw_ctxt, in_size: sizeof(fw_ctxt), |
252 | buf_out: &fw_ctxt, out_size: &out_size); |
253 | if (err || out_size != sizeof(fw_ctxt) || fw_ctxt.status) { |
254 | dev_err(&pdev->dev, "Failed to init FW ctxt, err: %d, status: 0x%x, out size: 0x%x\n" , |
255 | err, fw_ctxt.status, out_size); |
256 | return -EIO; |
257 | } |
258 | |
259 | return 0; |
260 | } |
261 | |
262 | /** |
263 | * set_hw_ioctxt - set the shape of the IO queues in FW |
264 | * @hwdev: the NIC HW device |
265 | * @rq_depth: rq depth |
266 | * @sq_depth: sq depth |
267 | * |
268 | * Return 0 - Success, negative - Failure |
269 | **/ |
270 | static int set_hw_ioctxt(struct hinic_hwdev *hwdev, unsigned int sq_depth, |
271 | unsigned int rq_depth) |
272 | { |
273 | struct hinic_hwif *hwif = hwdev->hwif; |
274 | struct hinic_cmd_hw_ioctxt hw_ioctxt; |
275 | struct hinic_pfhwdev *pfhwdev; |
276 | |
277 | hw_ioctxt.func_idx = HINIC_HWIF_FUNC_IDX(hwif); |
278 | hw_ioctxt.ppf_idx = HINIC_HWIF_PPF_IDX(hwif); |
279 | |
280 | hw_ioctxt.set_cmdq_depth = HW_IOCTXT_SET_CMDQ_DEPTH_DEFAULT; |
281 | hw_ioctxt.cmdq_depth = 0; |
282 | |
283 | hw_ioctxt.lro_en = 1; |
284 | |
285 | hw_ioctxt.rq_depth = ilog2(rq_depth); |
286 | |
287 | hw_ioctxt.rx_buf_sz_idx = HINIC_RX_BUF_SZ_IDX; |
288 | |
289 | hw_ioctxt.sq_depth = ilog2(sq_depth); |
290 | |
291 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
292 | |
293 | return hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_COMM, |
294 | cmd: HINIC_COMM_CMD_HWCTXT_SET, |
295 | buf_in: &hw_ioctxt, in_size: sizeof(hw_ioctxt), NULL, |
296 | NULL, sync: HINIC_MGMT_MSG_SYNC); |
297 | } |
298 | |
299 | static int wait_for_outbound_state(struct hinic_hwdev *hwdev) |
300 | { |
301 | enum hinic_outbound_state outbound_state; |
302 | struct hinic_hwif *hwif = hwdev->hwif; |
303 | struct pci_dev *pdev = hwif->pdev; |
304 | unsigned long end; |
305 | |
306 | end = jiffies + msecs_to_jiffies(OUTBOUND_STATE_TIMEOUT); |
307 | do { |
308 | outbound_state = hinic_outbound_state_get(hwif); |
309 | |
310 | if (outbound_state == HINIC_OUTBOUND_ENABLE) |
311 | return 0; |
312 | |
313 | msleep(msecs: 20); |
314 | } while (time_before(jiffies, end)); |
315 | |
316 | dev_err(&pdev->dev, "Wait for OUTBOUND - Timeout\n" ); |
317 | return -EFAULT; |
318 | } |
319 | |
320 | static int wait_for_db_state(struct hinic_hwdev *hwdev) |
321 | { |
322 | struct hinic_hwif *hwif = hwdev->hwif; |
323 | struct pci_dev *pdev = hwif->pdev; |
324 | enum hinic_db_state db_state; |
325 | unsigned long end; |
326 | |
327 | end = jiffies + msecs_to_jiffies(DB_STATE_TIMEOUT); |
328 | do { |
329 | db_state = hinic_db_state_get(hwif); |
330 | |
331 | if (db_state == HINIC_DB_ENABLE) |
332 | return 0; |
333 | |
334 | msleep(msecs: 20); |
335 | } while (time_before(jiffies, end)); |
336 | |
337 | dev_err(&pdev->dev, "Wait for DB - Timeout\n" ); |
338 | return -EFAULT; |
339 | } |
340 | |
341 | /** |
342 | * clear_io_resources - set the IO resources as not active in the NIC |
343 | * @hwdev: the NIC HW device |
344 | * |
345 | * Return 0 - Success, negative - Failure |
346 | **/ |
347 | static int clear_io_resources(struct hinic_hwdev *hwdev) |
348 | { |
349 | struct hinic_cmd_clear_io_res cmd_clear_io_res; |
350 | struct hinic_hwif *hwif = hwdev->hwif; |
351 | struct pci_dev *pdev = hwif->pdev; |
352 | struct hinic_pfhwdev *pfhwdev; |
353 | int err; |
354 | |
355 | /* sleep 100ms to wait for firmware stopping I/O */ |
356 | msleep(msecs: 100); |
357 | |
358 | cmd_clear_io_res.func_idx = HINIC_HWIF_FUNC_IDX(hwif); |
359 | |
360 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
361 | |
362 | err = hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_COMM, |
363 | cmd: HINIC_COMM_CMD_IO_RES_CLEAR, buf_in: &cmd_clear_io_res, |
364 | in_size: sizeof(cmd_clear_io_res), NULL, NULL, |
365 | sync: HINIC_MGMT_MSG_SYNC); |
366 | if (err) { |
367 | dev_err(&pdev->dev, "Failed to clear IO resources\n" ); |
368 | return err; |
369 | } |
370 | |
371 | return 0; |
372 | } |
373 | |
374 | /** |
375 | * set_resources_state - set the state of the resources in the NIC |
376 | * @hwdev: the NIC HW device |
377 | * @state: the state to set |
378 | * |
379 | * Return 0 - Success, negative - Failure |
380 | **/ |
381 | static int set_resources_state(struct hinic_hwdev *hwdev, |
382 | enum hinic_res_state state) |
383 | { |
384 | struct hinic_cmd_set_res_state res_state; |
385 | struct hinic_hwif *hwif = hwdev->hwif; |
386 | struct hinic_pfhwdev *pfhwdev; |
387 | |
388 | res_state.func_idx = HINIC_HWIF_FUNC_IDX(hwif); |
389 | res_state.state = state; |
390 | |
391 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
392 | |
393 | return hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, |
394 | mod: HINIC_MOD_COMM, |
395 | cmd: HINIC_COMM_CMD_RES_STATE_SET, |
396 | buf_in: &res_state, in_size: sizeof(res_state), NULL, |
397 | NULL, sync: HINIC_MGMT_MSG_SYNC); |
398 | } |
399 | |
400 | /** |
401 | * get_base_qpn - get the first qp number |
402 | * @hwdev: the NIC HW device |
403 | * @base_qpn: returned qp number |
404 | * |
405 | * Return 0 - Success, negative - Failure |
406 | **/ |
407 | static int get_base_qpn(struct hinic_hwdev *hwdev, u16 *base_qpn) |
408 | { |
409 | struct hinic_cmd_base_qpn cmd_base_qpn; |
410 | struct hinic_hwif *hwif = hwdev->hwif; |
411 | u16 out_size = sizeof(cmd_base_qpn); |
412 | struct pci_dev *pdev = hwif->pdev; |
413 | int err; |
414 | |
415 | cmd_base_qpn.func_idx = HINIC_HWIF_FUNC_IDX(hwif); |
416 | |
417 | err = hinic_port_msg_cmd(hwdev, cmd: HINIC_PORT_CMD_GET_GLOBAL_QPN, |
418 | buf_in: &cmd_base_qpn, in_size: sizeof(cmd_base_qpn), |
419 | buf_out: &cmd_base_qpn, out_size: &out_size); |
420 | if (err || out_size != sizeof(cmd_base_qpn) || cmd_base_qpn.status) { |
421 | dev_err(&pdev->dev, "Failed to get base qpn, err: %d, status: 0x%x, out size: 0x%x\n" , |
422 | err, cmd_base_qpn.status, out_size); |
423 | return -EIO; |
424 | } |
425 | |
426 | *base_qpn = cmd_base_qpn.qpn; |
427 | return 0; |
428 | } |
429 | |
430 | /** |
431 | * hinic_hwdev_ifup - Preparing the HW for passing IO |
432 | * @hwdev: the NIC HW device |
433 | * @sq_depth: the send queue depth |
434 | * @rq_depth: the receive queue depth |
435 | * |
436 | * Return 0 - Success, negative - Failure |
437 | **/ |
438 | int hinic_hwdev_ifup(struct hinic_hwdev *hwdev, u16 sq_depth, u16 rq_depth) |
439 | { |
440 | struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; |
441 | struct hinic_cap *nic_cap = &hwdev->nic_cap; |
442 | struct hinic_hwif *hwif = hwdev->hwif; |
443 | int err, num_aeqs, num_ceqs, num_qps; |
444 | struct msix_entry *ceq_msix_entries; |
445 | struct msix_entry *sq_msix_entries; |
446 | struct msix_entry *rq_msix_entries; |
447 | struct pci_dev *pdev = hwif->pdev; |
448 | u16 base_qpn; |
449 | |
450 | err = get_base_qpn(hwdev, base_qpn: &base_qpn); |
451 | if (err) { |
452 | dev_err(&pdev->dev, "Failed to get global base qp number\n" ); |
453 | return err; |
454 | } |
455 | |
456 | num_aeqs = HINIC_HWIF_NUM_AEQS(hwif); |
457 | num_ceqs = HINIC_HWIF_NUM_CEQS(hwif); |
458 | |
459 | ceq_msix_entries = &hwdev->msix_entries[num_aeqs]; |
460 | func_to_io->hwdev = hwdev; |
461 | func_to_io->sq_depth = sq_depth; |
462 | func_to_io->rq_depth = rq_depth; |
463 | func_to_io->global_qpn = base_qpn; |
464 | |
465 | err = hinic_io_init(func_to_io, hwif, max_qps: nic_cap->max_qps, num_ceqs, |
466 | ceq_msix_entries); |
467 | if (err) { |
468 | dev_err(&pdev->dev, "Failed to init IO channel\n" ); |
469 | return err; |
470 | } |
471 | |
472 | num_qps = nic_cap->num_qps; |
473 | sq_msix_entries = &hwdev->msix_entries[num_aeqs + num_ceqs]; |
474 | rq_msix_entries = &hwdev->msix_entries[num_aeqs + num_ceqs + num_qps]; |
475 | |
476 | err = hinic_io_create_qps(func_to_io, base_qpn, num_qps, |
477 | sq_msix_entries, rq_msix_entries); |
478 | if (err) { |
479 | dev_err(&pdev->dev, "Failed to create QPs\n" ); |
480 | goto err_create_qps; |
481 | } |
482 | |
483 | err = wait_for_db_state(hwdev); |
484 | if (err) { |
485 | dev_warn(&pdev->dev, "db - disabled, try again\n" ); |
486 | hinic_db_state_set(hwif, db_state: HINIC_DB_ENABLE); |
487 | } |
488 | |
489 | err = set_hw_ioctxt(hwdev, sq_depth, rq_depth); |
490 | if (err) { |
491 | dev_err(&pdev->dev, "Failed to set HW IO ctxt\n" ); |
492 | goto err_hw_ioctxt; |
493 | } |
494 | |
495 | return 0; |
496 | |
497 | err_hw_ioctxt: |
498 | hinic_io_destroy_qps(func_to_io, num_qps); |
499 | |
500 | err_create_qps: |
501 | hinic_io_free(func_to_io); |
502 | return err; |
503 | } |
504 | |
505 | /** |
506 | * hinic_hwdev_ifdown - Closing the HW for passing IO |
507 | * @hwdev: the NIC HW device |
508 | * |
509 | **/ |
510 | void hinic_hwdev_ifdown(struct hinic_hwdev *hwdev) |
511 | { |
512 | struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; |
513 | struct hinic_cap *nic_cap = &hwdev->nic_cap; |
514 | |
515 | clear_io_resources(hwdev); |
516 | |
517 | hinic_io_destroy_qps(func_to_io, num_qps: nic_cap->num_qps); |
518 | hinic_io_free(func_to_io); |
519 | } |
520 | |
521 | /** |
522 | * hinic_hwdev_cb_register - register callback handler for MGMT events |
523 | * @hwdev: the NIC HW device |
524 | * @cmd: the mgmt event |
525 | * @handle: private data for the handler |
526 | * @handler: event handler |
527 | **/ |
528 | void hinic_hwdev_cb_register(struct hinic_hwdev *hwdev, |
529 | enum hinic_mgmt_msg_cmd cmd, void *handle, |
530 | void (*handler)(void *handle, void *buf_in, |
531 | u16 in_size, void *buf_out, |
532 | u16 *out_size)) |
533 | { |
534 | struct hinic_pfhwdev *pfhwdev; |
535 | struct hinic_nic_cb *nic_cb; |
536 | u8 cmd_cb; |
537 | |
538 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
539 | |
540 | cmd_cb = cmd - HINIC_MGMT_MSG_CMD_BASE; |
541 | nic_cb = &pfhwdev->nic_cb[cmd_cb]; |
542 | |
543 | nic_cb->handler = handler; |
544 | nic_cb->handle = handle; |
545 | nic_cb->cb_state = HINIC_CB_ENABLED; |
546 | } |
547 | |
548 | /** |
549 | * hinic_hwdev_cb_unregister - unregister callback handler for MGMT events |
550 | * @hwdev: the NIC HW device |
551 | * @cmd: the mgmt event |
552 | **/ |
553 | void hinic_hwdev_cb_unregister(struct hinic_hwdev *hwdev, |
554 | enum hinic_mgmt_msg_cmd cmd) |
555 | { |
556 | struct hinic_hwif *hwif = hwdev->hwif; |
557 | struct hinic_pfhwdev *pfhwdev; |
558 | struct hinic_nic_cb *nic_cb; |
559 | u8 cmd_cb; |
560 | |
561 | if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) |
562 | return; |
563 | |
564 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
565 | |
566 | cmd_cb = cmd - HINIC_MGMT_MSG_CMD_BASE; |
567 | nic_cb = &pfhwdev->nic_cb[cmd_cb]; |
568 | |
569 | nic_cb->cb_state &= ~HINIC_CB_ENABLED; |
570 | |
571 | while (nic_cb->cb_state & HINIC_CB_RUNNING) |
572 | schedule(); |
573 | |
574 | nic_cb->handler = NULL; |
575 | } |
576 | |
577 | /** |
578 | * nic_mgmt_msg_handler - nic mgmt event handler |
579 | * @handle: private data for the handler |
580 | * @cmd: message command |
581 | * @buf_in: input buffer |
582 | * @in_size: input size |
583 | * @buf_out: output buffer |
584 | * @out_size: returned output size |
585 | **/ |
586 | static void nic_mgmt_msg_handler(void *handle, u8 cmd, void *buf_in, |
587 | u16 in_size, void *buf_out, u16 *out_size) |
588 | { |
589 | struct hinic_pfhwdev *pfhwdev = handle; |
590 | enum hinic_cb_state cb_state; |
591 | struct hinic_nic_cb *nic_cb; |
592 | struct hinic_hwdev *hwdev; |
593 | struct hinic_hwif *hwif; |
594 | struct pci_dev *pdev; |
595 | u8 cmd_cb; |
596 | |
597 | hwdev = &pfhwdev->hwdev; |
598 | hwif = hwdev->hwif; |
599 | pdev = hwif->pdev; |
600 | |
601 | if (cmd < HINIC_MGMT_MSG_CMD_BASE || |
602 | cmd >= HINIC_MGMT_MSG_CMD_MAX) { |
603 | dev_err(&pdev->dev, "unknown L2NIC event, cmd = %d\n" , cmd); |
604 | return; |
605 | } |
606 | |
607 | cmd_cb = cmd - HINIC_MGMT_MSG_CMD_BASE; |
608 | |
609 | nic_cb = &pfhwdev->nic_cb[cmd_cb]; |
610 | |
611 | cb_state = cmpxchg(&nic_cb->cb_state, |
612 | HINIC_CB_ENABLED, |
613 | HINIC_CB_ENABLED | HINIC_CB_RUNNING); |
614 | |
615 | if (cb_state == HINIC_CB_ENABLED && nic_cb->handler) |
616 | nic_cb->handler(nic_cb->handle, buf_in, |
617 | in_size, buf_out, out_size); |
618 | else |
619 | dev_err(&pdev->dev, "Unhandled NIC Event %d\n" , cmd); |
620 | |
621 | nic_cb->cb_state &= ~HINIC_CB_RUNNING; |
622 | } |
623 | |
624 | static void hinic_comm_recv_mgmt_self_cmd_reg(struct hinic_pfhwdev *pfhwdev, |
625 | u8 cmd, |
626 | comm_mgmt_self_msg_proc proc) |
627 | { |
628 | u8 cmd_idx; |
629 | |
630 | cmd_idx = pfhwdev->proc.cmd_num; |
631 | if (cmd_idx >= HINIC_COMM_SELF_CMD_MAX) { |
632 | dev_err(&pfhwdev->hwdev.hwif->pdev->dev, |
633 | "Register recv mgmt process failed, cmd: 0x%x\n" , cmd); |
634 | return; |
635 | } |
636 | |
637 | pfhwdev->proc.info[cmd_idx].cmd = cmd; |
638 | pfhwdev->proc.info[cmd_idx].proc = proc; |
639 | pfhwdev->proc.cmd_num++; |
640 | } |
641 | |
642 | static void hinic_comm_recv_mgmt_self_cmd_unreg(struct hinic_pfhwdev *pfhwdev, |
643 | u8 cmd) |
644 | { |
645 | u8 cmd_idx; |
646 | |
647 | cmd_idx = pfhwdev->proc.cmd_num; |
648 | if (cmd_idx >= HINIC_COMM_SELF_CMD_MAX) { |
649 | dev_err(&pfhwdev->hwdev.hwif->pdev->dev, "Unregister recv mgmt process failed, cmd: 0x%x\n" , |
650 | cmd); |
651 | return; |
652 | } |
653 | |
654 | for (cmd_idx = 0; cmd_idx < HINIC_COMM_SELF_CMD_MAX; cmd_idx++) { |
655 | if (cmd == pfhwdev->proc.info[cmd_idx].cmd) { |
656 | pfhwdev->proc.info[cmd_idx].cmd = 0; |
657 | pfhwdev->proc.info[cmd_idx].proc = NULL; |
658 | pfhwdev->proc.cmd_num--; |
659 | } |
660 | } |
661 | } |
662 | |
663 | static void comm_mgmt_msg_handler(void *handle, u8 cmd, void *buf_in, |
664 | u16 in_size, void *buf_out, u16 *out_size) |
665 | { |
666 | struct hinic_pfhwdev *pfhwdev = handle; |
667 | u8 cmd_idx; |
668 | |
669 | for (cmd_idx = 0; cmd_idx < pfhwdev->proc.cmd_num; cmd_idx++) { |
670 | if (cmd == pfhwdev->proc.info[cmd_idx].cmd) { |
671 | if (!pfhwdev->proc.info[cmd_idx].proc) { |
672 | dev_warn(&pfhwdev->hwdev.hwif->pdev->dev, |
673 | "PF recv mgmt comm msg handle null, cmd: 0x%x\n" , |
674 | cmd); |
675 | } else { |
676 | pfhwdev->proc.info[cmd_idx].proc |
677 | (&pfhwdev->hwdev, buf_in, in_size, |
678 | buf_out, out_size); |
679 | } |
680 | |
681 | return; |
682 | } |
683 | } |
684 | |
685 | dev_warn(&pfhwdev->hwdev.hwif->pdev->dev, "Received unknown mgmt cpu event: 0x%x\n" , |
686 | cmd); |
687 | |
688 | *out_size = 0; |
689 | } |
690 | |
691 | /* pf fault report event */ |
692 | static void pf_fault_event_handler(void *dev, void *buf_in, u16 in_size, |
693 | void *buf_out, u16 *out_size) |
694 | { |
695 | struct hinic_cmd_fault_event *fault_event = buf_in; |
696 | struct hinic_hwdev *hwdev = dev; |
697 | |
698 | if (in_size != sizeof(*fault_event)) { |
699 | dev_err(&hwdev->hwif->pdev->dev, "Invalid fault event report, length: %d, should be %zu\n" , |
700 | in_size, sizeof(*fault_event)); |
701 | return; |
702 | } |
703 | |
704 | if (!hwdev->devlink_dev || IS_ERR_OR_NULL(ptr: hwdev->devlink_dev->hw_fault_reporter)) |
705 | return; |
706 | |
707 | devlink_health_report(reporter: hwdev->devlink_dev->hw_fault_reporter, |
708 | msg: "HW fatal error reported" , priv_ctx: &fault_event->event); |
709 | } |
710 | |
711 | static void mgmt_watchdog_timeout_event_handler(void *dev, |
712 | void *buf_in, u16 in_size, |
713 | void *buf_out, u16 *out_size) |
714 | { |
715 | struct hinic_mgmt_watchdog_info *watchdog_info = buf_in; |
716 | struct hinic_hwdev *hwdev = dev; |
717 | |
718 | if (in_size != sizeof(*watchdog_info)) { |
719 | dev_err(&hwdev->hwif->pdev->dev, "Invalid mgmt watchdog report, length: %d, should be %zu\n" , |
720 | in_size, sizeof(*watchdog_info)); |
721 | return; |
722 | } |
723 | |
724 | if (!hwdev->devlink_dev || IS_ERR_OR_NULL(ptr: hwdev->devlink_dev->fw_fault_reporter)) |
725 | return; |
726 | |
727 | devlink_health_report(reporter: hwdev->devlink_dev->fw_fault_reporter, |
728 | msg: "FW fatal error reported" , priv_ctx: watchdog_info); |
729 | } |
730 | |
731 | /** |
732 | * init_pfhwdev - Initialize the extended components of PF |
733 | * @pfhwdev: the HW device for PF |
734 | * |
735 | * Return 0 - success, negative - failure |
736 | **/ |
737 | static int init_pfhwdev(struct hinic_pfhwdev *pfhwdev) |
738 | { |
739 | struct hinic_hwdev *hwdev = &pfhwdev->hwdev; |
740 | struct hinic_hwif *hwif = hwdev->hwif; |
741 | struct pci_dev *pdev = hwif->pdev; |
742 | int err; |
743 | |
744 | err = hinic_pf_to_mgmt_init(pf_to_mgmt: &pfhwdev->pf_to_mgmt, hwif); |
745 | if (err) { |
746 | dev_err(&pdev->dev, "Failed to initialize PF to MGMT channel\n" ); |
747 | return err; |
748 | } |
749 | |
750 | err = hinic_func_to_func_init(hwdev); |
751 | if (err) { |
752 | dev_err(&hwif->pdev->dev, "Failed to init mailbox\n" ); |
753 | hinic_pf_to_mgmt_free(pf_to_mgmt: &pfhwdev->pf_to_mgmt); |
754 | return err; |
755 | } |
756 | |
757 | if (!HINIC_IS_VF(hwif)) { |
758 | hinic_register_mgmt_msg_cb(pf_to_mgmt: &pfhwdev->pf_to_mgmt, |
759 | mod: HINIC_MOD_L2NIC, handle: pfhwdev, |
760 | callback: nic_mgmt_msg_handler); |
761 | hinic_register_mgmt_msg_cb(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_COMM, |
762 | handle: pfhwdev, callback: comm_mgmt_msg_handler); |
763 | hinic_comm_recv_mgmt_self_cmd_reg(pfhwdev, |
764 | cmd: HINIC_COMM_CMD_FAULT_REPORT, |
765 | proc: pf_fault_event_handler); |
766 | hinic_comm_recv_mgmt_self_cmd_reg |
767 | (pfhwdev, cmd: HINIC_COMM_CMD_WATCHDOG_INFO, |
768 | proc: mgmt_watchdog_timeout_event_handler); |
769 | } else { |
770 | hinic_register_vf_mbox_cb(hwdev, mod: HINIC_MOD_L2NIC, |
771 | callback: nic_mgmt_msg_handler); |
772 | } |
773 | |
774 | hinic_set_pf_action(hwif, action: HINIC_PF_MGMT_ACTIVE); |
775 | hinic_devlink_register(priv: hwdev->devlink_dev); |
776 | return 0; |
777 | } |
778 | |
779 | /** |
780 | * free_pfhwdev - Free the extended components of PF |
781 | * @pfhwdev: the HW device for PF |
782 | **/ |
783 | static void free_pfhwdev(struct hinic_pfhwdev *pfhwdev) |
784 | { |
785 | struct hinic_hwdev *hwdev = &pfhwdev->hwdev; |
786 | |
787 | hinic_devlink_unregister(priv: hwdev->devlink_dev); |
788 | hinic_set_pf_action(hwif: hwdev->hwif, action: HINIC_PF_MGMT_INIT); |
789 | |
790 | if (!HINIC_IS_VF(hwdev->hwif)) { |
791 | hinic_comm_recv_mgmt_self_cmd_unreg(pfhwdev, |
792 | cmd: HINIC_COMM_CMD_WATCHDOG_INFO); |
793 | hinic_comm_recv_mgmt_self_cmd_unreg(pfhwdev, |
794 | cmd: HINIC_COMM_CMD_FAULT_REPORT); |
795 | hinic_unregister_mgmt_msg_cb(pf_to_mgmt: &pfhwdev->pf_to_mgmt, |
796 | mod: HINIC_MOD_COMM); |
797 | hinic_unregister_mgmt_msg_cb(pf_to_mgmt: &pfhwdev->pf_to_mgmt, |
798 | mod: HINIC_MOD_L2NIC); |
799 | } else { |
800 | hinic_unregister_vf_mbox_cb(hwdev, mod: HINIC_MOD_L2NIC); |
801 | } |
802 | |
803 | hinic_func_to_func_free(hwdev); |
804 | |
805 | hinic_pf_to_mgmt_free(pf_to_mgmt: &pfhwdev->pf_to_mgmt); |
806 | } |
807 | |
808 | static int hinic_l2nic_reset(struct hinic_hwdev *hwdev) |
809 | { |
810 | struct hinic_cmd_l2nic_reset l2nic_reset = {0}; |
811 | u16 out_size = sizeof(l2nic_reset); |
812 | struct hinic_pfhwdev *pfhwdev; |
813 | int err; |
814 | |
815 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
816 | |
817 | l2nic_reset.func_id = HINIC_HWIF_FUNC_IDX(hwdev->hwif); |
818 | /* 0 represents standard l2nic reset flow */ |
819 | l2nic_reset.reset_flag = 0; |
820 | |
821 | err = hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_COMM, |
822 | cmd: HINIC_COMM_CMD_L2NIC_RESET, buf_in: &l2nic_reset, |
823 | in_size: sizeof(l2nic_reset), buf_out: &l2nic_reset, |
824 | out_size: &out_size, sync: HINIC_MGMT_MSG_SYNC); |
825 | if (err || !out_size || l2nic_reset.status) { |
826 | dev_err(&hwdev->hwif->pdev->dev, "Failed to reset L2NIC resources, err: %d, status: 0x%x, out_size: 0x%x\n" , |
827 | err, l2nic_reset.status, out_size); |
828 | return -EIO; |
829 | } |
830 | |
831 | return 0; |
832 | } |
833 | |
834 | static int hinic_get_interrupt_cfg(struct hinic_hwdev *hwdev, |
835 | struct hinic_msix_config *interrupt_info) |
836 | { |
837 | u16 out_size = sizeof(*interrupt_info); |
838 | struct hinic_pfhwdev *pfhwdev; |
839 | int err; |
840 | |
841 | if (!hwdev || !interrupt_info) |
842 | return -EINVAL; |
843 | |
844 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
845 | |
846 | interrupt_info->func_id = HINIC_HWIF_FUNC_IDX(hwdev->hwif); |
847 | |
848 | err = hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_COMM, |
849 | cmd: HINIC_COMM_CMD_MSI_CTRL_REG_RD_BY_UP, |
850 | buf_in: interrupt_info, in_size: sizeof(*interrupt_info), |
851 | buf_out: interrupt_info, out_size: &out_size, sync: HINIC_MGMT_MSG_SYNC); |
852 | if (err || !out_size || interrupt_info->status) { |
853 | dev_err(&hwdev->hwif->pdev->dev, "Failed to get interrupt config, err: %d, status: 0x%x, out size: 0x%x\n" , |
854 | err, interrupt_info->status, out_size); |
855 | return -EIO; |
856 | } |
857 | |
858 | return 0; |
859 | } |
860 | |
861 | int hinic_set_interrupt_cfg(struct hinic_hwdev *hwdev, |
862 | struct hinic_msix_config *interrupt_info) |
863 | { |
864 | u16 out_size = sizeof(*interrupt_info); |
865 | struct hinic_msix_config temp_info; |
866 | struct hinic_pfhwdev *pfhwdev; |
867 | int err; |
868 | |
869 | if (!hwdev) |
870 | return -EINVAL; |
871 | |
872 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
873 | |
874 | interrupt_info->func_id = HINIC_HWIF_FUNC_IDX(hwdev->hwif); |
875 | |
876 | err = hinic_get_interrupt_cfg(hwdev, interrupt_info: &temp_info); |
877 | if (err) |
878 | return -EINVAL; |
879 | |
880 | interrupt_info->lli_credit_cnt = temp_info.lli_credit_cnt; |
881 | interrupt_info->lli_timer_cnt = temp_info.lli_timer_cnt; |
882 | |
883 | err = hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_COMM, |
884 | cmd: HINIC_COMM_CMD_MSI_CTRL_REG_WR_BY_UP, |
885 | buf_in: interrupt_info, in_size: sizeof(*interrupt_info), |
886 | buf_out: interrupt_info, out_size: &out_size, sync: HINIC_MGMT_MSG_SYNC); |
887 | if (err || !out_size || interrupt_info->status) { |
888 | dev_err(&hwdev->hwif->pdev->dev, "Failed to get interrupt config, err: %d, status: 0x%x, out size: 0x%x\n" , |
889 | err, interrupt_info->status, out_size); |
890 | return -EIO; |
891 | } |
892 | |
893 | return 0; |
894 | } |
895 | |
896 | /** |
897 | * hinic_init_hwdev - Initialize the NIC HW |
898 | * @pdev: the NIC pci device |
899 | * @devlink: the poniter of hinic devlink |
900 | * |
901 | * Return initialized NIC HW device |
902 | * |
903 | * Initialize the NIC HW device and return a pointer to it |
904 | **/ |
905 | struct hinic_hwdev *hinic_init_hwdev(struct pci_dev *pdev, struct devlink *devlink) |
906 | { |
907 | struct hinic_pfhwdev *pfhwdev; |
908 | struct hinic_hwdev *hwdev; |
909 | struct hinic_hwif *hwif; |
910 | int err, num_aeqs; |
911 | |
912 | hwif = devm_kzalloc(dev: &pdev->dev, size: sizeof(*hwif), GFP_KERNEL); |
913 | if (!hwif) |
914 | return ERR_PTR(error: -ENOMEM); |
915 | |
916 | err = hinic_init_hwif(hwif, pdev); |
917 | if (err) { |
918 | dev_err(&pdev->dev, "Failed to init HW interface\n" ); |
919 | return ERR_PTR(error: err); |
920 | } |
921 | |
922 | pfhwdev = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pfhwdev), GFP_KERNEL); |
923 | if (!pfhwdev) { |
924 | err = -ENOMEM; |
925 | goto err_pfhwdev_alloc; |
926 | } |
927 | |
928 | hwdev = &pfhwdev->hwdev; |
929 | hwdev->hwif = hwif; |
930 | hwdev->devlink_dev = devlink_priv(devlink); |
931 | hwdev->devlink_dev->hwdev = hwdev; |
932 | |
933 | err = init_msix(hwdev); |
934 | if (err) { |
935 | dev_err(&pdev->dev, "Failed to init msix\n" ); |
936 | goto err_init_msix; |
937 | } |
938 | |
939 | err = wait_for_outbound_state(hwdev); |
940 | if (err) { |
941 | dev_warn(&pdev->dev, "outbound - disabled, try again\n" ); |
942 | hinic_outbound_state_set(hwif, outbound_state: HINIC_OUTBOUND_ENABLE); |
943 | } |
944 | |
945 | num_aeqs = HINIC_HWIF_NUM_AEQS(hwif); |
946 | |
947 | err = hinic_aeqs_init(aeqs: &hwdev->aeqs, hwif, num_aeqs, |
948 | HINIC_DEFAULT_AEQ_LEN, HINIC_EQ_PAGE_SIZE, |
949 | msix_entries: hwdev->msix_entries); |
950 | if (err) { |
951 | dev_err(&pdev->dev, "Failed to init async event queues\n" ); |
952 | goto err_aeqs_init; |
953 | } |
954 | |
955 | err = init_pfhwdev(pfhwdev); |
956 | if (err) { |
957 | dev_err(&pdev->dev, "Failed to init PF HW device\n" ); |
958 | goto err_init_pfhwdev; |
959 | } |
960 | |
961 | err = hinic_l2nic_reset(hwdev); |
962 | if (err) |
963 | goto err_l2nic_reset; |
964 | |
965 | err = get_dev_cap(hwdev); |
966 | if (err) { |
967 | dev_err(&pdev->dev, "Failed to get device capabilities\n" ); |
968 | goto err_dev_cap; |
969 | } |
970 | |
971 | mutex_init(&hwdev->func_to_io.nic_cfg.cfg_mutex); |
972 | |
973 | err = hinic_vf_func_init(hwdev); |
974 | if (err) { |
975 | dev_err(&pdev->dev, "Failed to init nic mbox\n" ); |
976 | goto err_vf_func_init; |
977 | } |
978 | |
979 | err = init_fw_ctxt(hwdev); |
980 | if (err) { |
981 | dev_err(&pdev->dev, "Failed to init function table\n" ); |
982 | goto err_init_fw_ctxt; |
983 | } |
984 | |
985 | err = set_resources_state(hwdev, state: HINIC_RES_ACTIVE); |
986 | if (err) { |
987 | dev_err(&pdev->dev, "Failed to set resources state\n" ); |
988 | goto err_resources_state; |
989 | } |
990 | |
991 | return hwdev; |
992 | |
993 | err_resources_state: |
994 | err_init_fw_ctxt: |
995 | hinic_vf_func_free(hwdev); |
996 | err_vf_func_init: |
997 | err_l2nic_reset: |
998 | err_dev_cap: |
999 | free_pfhwdev(pfhwdev); |
1000 | |
1001 | err_init_pfhwdev: |
1002 | hinic_aeqs_free(aeqs: &hwdev->aeqs); |
1003 | |
1004 | err_aeqs_init: |
1005 | disable_msix(hwdev); |
1006 | |
1007 | err_init_msix: |
1008 | err_pfhwdev_alloc: |
1009 | hinic_free_hwif(hwif); |
1010 | if (err > 0) |
1011 | err = -EIO; |
1012 | return ERR_PTR(error: err); |
1013 | } |
1014 | |
1015 | /** |
1016 | * hinic_free_hwdev - Free the NIC HW device |
1017 | * @hwdev: the NIC HW device |
1018 | **/ |
1019 | void hinic_free_hwdev(struct hinic_hwdev *hwdev) |
1020 | { |
1021 | struct hinic_pfhwdev *pfhwdev = container_of(hwdev, |
1022 | struct hinic_pfhwdev, |
1023 | hwdev); |
1024 | |
1025 | set_resources_state(hwdev, state: HINIC_RES_CLEAN); |
1026 | |
1027 | hinic_vf_func_free(hwdev); |
1028 | |
1029 | free_pfhwdev(pfhwdev); |
1030 | |
1031 | hinic_aeqs_free(aeqs: &hwdev->aeqs); |
1032 | |
1033 | disable_msix(hwdev); |
1034 | |
1035 | hinic_free_hwif(hwif: hwdev->hwif); |
1036 | } |
1037 | |
1038 | /** |
1039 | * hinic_hwdev_num_qps - return the number QPs available for use |
1040 | * @hwdev: the NIC HW device |
1041 | * |
1042 | * Return number QPs available for use |
1043 | **/ |
1044 | int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev) |
1045 | { |
1046 | struct hinic_cap *nic_cap = &hwdev->nic_cap; |
1047 | |
1048 | return nic_cap->num_qps; |
1049 | } |
1050 | |
1051 | /** |
1052 | * hinic_hwdev_get_sq - get SQ |
1053 | * @hwdev: the NIC HW device |
1054 | * @i: the position of the SQ |
1055 | * |
1056 | * Return: the SQ in the i position |
1057 | **/ |
1058 | struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i) |
1059 | { |
1060 | struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; |
1061 | struct hinic_qp *qp = &func_to_io->qps[i]; |
1062 | |
1063 | if (i >= hinic_hwdev_num_qps(hwdev)) |
1064 | return NULL; |
1065 | |
1066 | return &qp->sq; |
1067 | } |
1068 | |
1069 | /** |
1070 | * hinic_hwdev_get_rq - get RQ |
1071 | * @hwdev: the NIC HW device |
1072 | * @i: the position of the RQ |
1073 | * |
1074 | * Return: the RQ in the i position |
1075 | **/ |
1076 | struct hinic_rq *hinic_hwdev_get_rq(struct hinic_hwdev *hwdev, int i) |
1077 | { |
1078 | struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; |
1079 | struct hinic_qp *qp = &func_to_io->qps[i]; |
1080 | |
1081 | if (i >= hinic_hwdev_num_qps(hwdev)) |
1082 | return NULL; |
1083 | |
1084 | return &qp->rq; |
1085 | } |
1086 | |
1087 | /** |
1088 | * hinic_hwdev_msix_cnt_set - clear message attribute counters for msix entry |
1089 | * @hwdev: the NIC HW device |
1090 | * @msix_index: msix_index |
1091 | * |
1092 | * Return 0 - Success, negative - Failure |
1093 | **/ |
1094 | int hinic_hwdev_msix_cnt_set(struct hinic_hwdev *hwdev, u16 msix_index) |
1095 | { |
1096 | return hinic_msix_attr_cnt_clear(hwif: hwdev->hwif, msix_index); |
1097 | } |
1098 | |
1099 | /** |
1100 | * hinic_hwdev_msix_set - set message attribute for msix entry |
1101 | * @hwdev: the NIC HW device |
1102 | * @msix_index: msix_index |
1103 | * @pending_limit: the maximum pending interrupt events (unit 8) |
1104 | * @coalesc_timer: coalesc period for interrupt (unit 8 us) |
1105 | * @lli_timer_cfg: replenishing period for low latency credit (unit 8 us) |
1106 | * @lli_credit_limit: maximum credits for low latency msix messages (unit 8) |
1107 | * @resend_timer: maximum wait for resending msix (unit coalesc period) |
1108 | * |
1109 | * Return 0 - Success, negative - Failure |
1110 | **/ |
1111 | int hinic_hwdev_msix_set(struct hinic_hwdev *hwdev, u16 msix_index, |
1112 | u8 pending_limit, u8 coalesc_timer, |
1113 | u8 lli_timer_cfg, u8 lli_credit_limit, |
1114 | u8 resend_timer) |
1115 | { |
1116 | return hinic_msix_attr_set(hwif: hwdev->hwif, msix_index, |
1117 | pending_limit, coalesc_timer, |
1118 | lli_timer_cfg, lli_credit_limit, |
1119 | resend_timer); |
1120 | } |
1121 | |
1122 | /** |
1123 | * hinic_hwdev_hw_ci_addr_set - set cons idx addr and attributes in HW for sq |
1124 | * @hwdev: the NIC HW device |
1125 | * @sq: send queue |
1126 | * @pending_limit: the maximum pending update ci events (unit 8) |
1127 | * @coalesc_timer: coalesc period for update ci (unit 8 us) |
1128 | * |
1129 | * Return 0 - Success, negative - Failure |
1130 | **/ |
1131 | int hinic_hwdev_hw_ci_addr_set(struct hinic_hwdev *hwdev, struct hinic_sq *sq, |
1132 | u8 pending_limit, u8 coalesc_timer) |
1133 | { |
1134 | struct hinic_qp *qp = container_of(sq, struct hinic_qp, sq); |
1135 | struct hinic_hwif *hwif = hwdev->hwif; |
1136 | struct hinic_pfhwdev *pfhwdev; |
1137 | struct hinic_cmd_hw_ci hw_ci; |
1138 | |
1139 | hw_ci.dma_attr_off = 0; |
1140 | hw_ci.pending_limit = pending_limit; |
1141 | hw_ci.coalesc_timer = coalesc_timer; |
1142 | |
1143 | hw_ci.msix_en = 1; |
1144 | hw_ci.msix_entry_idx = sq->msix_entry; |
1145 | |
1146 | hw_ci.func_idx = HINIC_HWIF_FUNC_IDX(hwif); |
1147 | |
1148 | hw_ci.sq_id = qp->q_id; |
1149 | |
1150 | hw_ci.ci_addr = ADDR_IN_4BYTES(sq->hw_ci_dma_addr); |
1151 | |
1152 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
1153 | return hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, |
1154 | mod: HINIC_MOD_COMM, |
1155 | cmd: HINIC_COMM_CMD_SQ_HI_CI_SET, |
1156 | buf_in: &hw_ci, in_size: sizeof(hw_ci), NULL, |
1157 | NULL, sync: HINIC_MGMT_MSG_SYNC); |
1158 | } |
1159 | |
1160 | /** |
1161 | * hinic_hwdev_set_msix_state- set msix state |
1162 | * @hwdev: the NIC HW device |
1163 | * @msix_index: IRQ corresponding index number |
1164 | * @flag: msix state |
1165 | * |
1166 | **/ |
1167 | void hinic_hwdev_set_msix_state(struct hinic_hwdev *hwdev, u16 msix_index, |
1168 | enum hinic_msix_state flag) |
1169 | { |
1170 | hinic_set_msix_state(hwif: hwdev->hwif, msix_idx: msix_index, flag); |
1171 | } |
1172 | |
1173 | int hinic_get_board_info(struct hinic_hwdev *hwdev, |
1174 | struct hinic_comm_board_info *board_info) |
1175 | { |
1176 | u16 out_size = sizeof(*board_info); |
1177 | struct hinic_pfhwdev *pfhwdev; |
1178 | int err; |
1179 | |
1180 | if (!hwdev || !board_info) |
1181 | return -EINVAL; |
1182 | |
1183 | pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
1184 | |
1185 | err = hinic_msg_to_mgmt(pf_to_mgmt: &pfhwdev->pf_to_mgmt, mod: HINIC_MOD_COMM, |
1186 | cmd: HINIC_COMM_CMD_GET_BOARD_INFO, |
1187 | buf_in: board_info, in_size: sizeof(*board_info), |
1188 | buf_out: board_info, out_size: &out_size, sync: HINIC_MGMT_MSG_SYNC); |
1189 | if (err || board_info->status || !out_size) { |
1190 | dev_err(&hwdev->hwif->pdev->dev, |
1191 | "Failed to get board info, err: %d, status: 0x%x, out size: 0x%x\n" , |
1192 | err, board_info->status, out_size); |
1193 | return -EIO; |
1194 | } |
1195 | |
1196 | return 0; |
1197 | } |
1198 | |