1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2005 - 2016 Broadcom |
4 | * All rights reserved. |
5 | * |
6 | * Contact Information: |
7 | * linux-drivers@emulex.com |
8 | * |
9 | * Emulex |
10 | * 3333 Susan Street |
11 | * Costa Mesa, CA 92626 |
12 | */ |
13 | |
14 | #include <linux/module.h> |
15 | #include "be.h" |
16 | #include "be_cmds.h" |
17 | |
18 | const char * const be_misconfig_evt_port_state[] = { |
19 | "Physical Link is functional" , |
20 | "Optics faulted/incorrectly installed/not installed - Reseat optics. If issue not resolved, replace." , |
21 | "Optics of two types installed – Remove one optic or install matching pair of optics." , |
22 | "Incompatible optics – Replace with compatible optics for card to function." , |
23 | "Unqualified optics – Replace with Avago optics for Warranty and Technical Support." , |
24 | "Uncertified optics – Replace with Avago-certified optics to enable link operation." |
25 | }; |
26 | |
27 | static char *be_port_misconfig_evt_severity[] = { |
28 | "KERN_WARN" , |
29 | "KERN_INFO" , |
30 | "KERN_ERR" , |
31 | "KERN_WARN" |
32 | }; |
33 | |
34 | static char *phy_state_oper_desc[] = { |
35 | "Link is non-operational" , |
36 | "Link is operational" , |
37 | "" |
38 | }; |
39 | |
40 | static struct be_cmd_priv_map cmd_priv_map[] = { |
41 | { |
42 | OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, |
43 | CMD_SUBSYSTEM_ETH, |
44 | BE_PRIV_LNKMGMT | BE_PRIV_VHADM | |
45 | BE_PRIV_DEVCFG | BE_PRIV_DEVSEC |
46 | }, |
47 | { |
48 | OPCODE_COMMON_GET_FLOW_CONTROL, |
49 | CMD_SUBSYSTEM_COMMON, |
50 | BE_PRIV_LNKQUERY | BE_PRIV_VHADM | |
51 | BE_PRIV_DEVCFG | BE_PRIV_DEVSEC |
52 | }, |
53 | { |
54 | OPCODE_COMMON_SET_FLOW_CONTROL, |
55 | CMD_SUBSYSTEM_COMMON, |
56 | BE_PRIV_LNKMGMT | BE_PRIV_VHADM | |
57 | BE_PRIV_DEVCFG | BE_PRIV_DEVSEC |
58 | }, |
59 | { |
60 | OPCODE_ETH_GET_PPORT_STATS, |
61 | CMD_SUBSYSTEM_ETH, |
62 | BE_PRIV_LNKMGMT | BE_PRIV_VHADM | |
63 | BE_PRIV_DEVCFG | BE_PRIV_DEVSEC |
64 | }, |
65 | { |
66 | OPCODE_COMMON_GET_PHY_DETAILS, |
67 | CMD_SUBSYSTEM_COMMON, |
68 | BE_PRIV_LNKMGMT | BE_PRIV_VHADM | |
69 | BE_PRIV_DEVCFG | BE_PRIV_DEVSEC |
70 | }, |
71 | { |
72 | OPCODE_LOWLEVEL_HOST_DDR_DMA, |
73 | CMD_SUBSYSTEM_LOWLEVEL, |
74 | BE_PRIV_DEVCFG | BE_PRIV_DEVSEC |
75 | }, |
76 | { |
77 | OPCODE_LOWLEVEL_LOOPBACK_TEST, |
78 | CMD_SUBSYSTEM_LOWLEVEL, |
79 | BE_PRIV_DEVCFG | BE_PRIV_DEVSEC |
80 | }, |
81 | { |
82 | OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, |
83 | CMD_SUBSYSTEM_LOWLEVEL, |
84 | BE_PRIV_DEVCFG | BE_PRIV_DEVSEC |
85 | }, |
86 | { |
87 | OPCODE_COMMON_SET_HSW_CONFIG, |
88 | CMD_SUBSYSTEM_COMMON, |
89 | BE_PRIV_DEVCFG | BE_PRIV_VHADM | |
90 | BE_PRIV_DEVSEC |
91 | }, |
92 | { |
93 | OPCODE_COMMON_GET_EXT_FAT_CAPABILITIES, |
94 | CMD_SUBSYSTEM_COMMON, |
95 | BE_PRIV_DEVCFG |
96 | } |
97 | }; |
98 | |
99 | static bool be_cmd_allowed(struct be_adapter *adapter, u8 opcode, u8 subsystem) |
100 | { |
101 | int i; |
102 | int num_entries = ARRAY_SIZE(cmd_priv_map); |
103 | u32 cmd_privileges = adapter->cmd_privileges; |
104 | |
105 | for (i = 0; i < num_entries; i++) |
106 | if (opcode == cmd_priv_map[i].opcode && |
107 | subsystem == cmd_priv_map[i].subsystem) |
108 | if (!(cmd_privileges & cmd_priv_map[i].priv_mask)) |
109 | return false; |
110 | |
111 | return true; |
112 | } |
113 | |
114 | static inline void *embedded_payload(struct be_mcc_wrb *wrb) |
115 | { |
116 | return wrb->payload.embedded_payload; |
117 | } |
118 | |
119 | static int be_mcc_notify(struct be_adapter *adapter) |
120 | { |
121 | struct be_queue_info *mccq = &adapter->mcc_obj.q; |
122 | u32 val = 0; |
123 | |
124 | if (be_check_error(adapter, BE_ERROR_ANY)) |
125 | return -EIO; |
126 | |
127 | val |= mccq->id & DB_MCCQ_RING_ID_MASK; |
128 | val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; |
129 | |
130 | wmb(); |
131 | iowrite32(val, adapter->db + DB_MCCQ_OFFSET); |
132 | |
133 | return 0; |
134 | } |
135 | |
136 | /* To check if valid bit is set, check the entire word as we don't know |
137 | * the endianness of the data (old entry is host endian while a new entry is |
138 | * little endian) |
139 | */ |
140 | static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) |
141 | { |
142 | u32 flags; |
143 | |
144 | if (compl->flags != 0) { |
145 | flags = le32_to_cpu(compl->flags); |
146 | if (flags & CQE_FLAGS_VALID_MASK) { |
147 | compl->flags = flags; |
148 | return true; |
149 | } |
150 | } |
151 | return false; |
152 | } |
153 | |
154 | /* Need to reset the entire word that houses the valid bit */ |
155 | static inline void be_mcc_compl_use(struct be_mcc_compl *compl) |
156 | { |
157 | compl->flags = 0; |
158 | } |
159 | |
160 | static struct be_cmd_resp_hdr *be_decode_resp_hdr(u32 tag0, u32 tag1) |
161 | { |
162 | unsigned long addr; |
163 | |
164 | addr = tag1; |
165 | addr = ((addr << 16) << 16) | tag0; |
166 | return (void *)addr; |
167 | } |
168 | |
169 | static bool be_skip_err_log(u8 opcode, u16 base_status, u16 addl_status) |
170 | { |
171 | if (base_status == MCC_STATUS_NOT_SUPPORTED || |
172 | base_status == MCC_STATUS_ILLEGAL_REQUEST || |
173 | addl_status == MCC_ADDL_STATUS_TOO_MANY_INTERFACES || |
174 | addl_status == MCC_ADDL_STATUS_INSUFFICIENT_VLANS || |
175 | (opcode == OPCODE_COMMON_WRITE_FLASHROM && |
176 | (base_status == MCC_STATUS_ILLEGAL_FIELD || |
177 | addl_status == MCC_ADDL_STATUS_FLASH_IMAGE_CRC_MISMATCH))) |
178 | return true; |
179 | else |
180 | return false; |
181 | } |
182 | |
183 | /* Place holder for all the async MCC cmds wherein the caller is not in a busy |
184 | * loop (has not issued be_mcc_notify_wait()) |
185 | */ |
186 | static void be_async_cmd_process(struct be_adapter *adapter, |
187 | struct be_mcc_compl *compl, |
188 | struct be_cmd_resp_hdr *resp_hdr) |
189 | { |
190 | enum mcc_base_status base_status = base_status(compl->status); |
191 | u8 opcode = 0, subsystem = 0; |
192 | |
193 | if (resp_hdr) { |
194 | opcode = resp_hdr->opcode; |
195 | subsystem = resp_hdr->subsystem; |
196 | } |
197 | |
198 | if (opcode == OPCODE_LOWLEVEL_LOOPBACK_TEST && |
199 | subsystem == CMD_SUBSYSTEM_LOWLEVEL) { |
200 | complete(&adapter->et_cmd_compl); |
201 | return; |
202 | } |
203 | |
204 | if (opcode == OPCODE_LOWLEVEL_SET_LOOPBACK_MODE && |
205 | subsystem == CMD_SUBSYSTEM_LOWLEVEL) { |
206 | complete(&adapter->et_cmd_compl); |
207 | return; |
208 | } |
209 | |
210 | if ((opcode == OPCODE_COMMON_WRITE_FLASHROM || |
211 | opcode == OPCODE_COMMON_WRITE_OBJECT) && |
212 | subsystem == CMD_SUBSYSTEM_COMMON) { |
213 | adapter->flash_status = compl->status; |
214 | complete(&adapter->et_cmd_compl); |
215 | return; |
216 | } |
217 | |
218 | if ((opcode == OPCODE_ETH_GET_STATISTICS || |
219 | opcode == OPCODE_ETH_GET_PPORT_STATS) && |
220 | subsystem == CMD_SUBSYSTEM_ETH && |
221 | base_status == MCC_STATUS_SUCCESS) { |
222 | be_parse_stats(adapter); |
223 | adapter->stats_cmd_sent = false; |
224 | return; |
225 | } |
226 | |
227 | if (opcode == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES && |
228 | subsystem == CMD_SUBSYSTEM_COMMON) { |
229 | if (base_status == MCC_STATUS_SUCCESS) { |
230 | struct be_cmd_resp_get_cntl_addnl_attribs *resp = |
231 | (void *)resp_hdr; |
232 | adapter->hwmon_info.be_on_die_temp = |
233 | resp->on_die_temperature; |
234 | } else { |
235 | adapter->be_get_temp_freq = 0; |
236 | adapter->hwmon_info.be_on_die_temp = |
237 | BE_INVALID_DIE_TEMP; |
238 | } |
239 | return; |
240 | } |
241 | } |
242 | |
243 | static int be_mcc_compl_process(struct be_adapter *adapter, |
244 | struct be_mcc_compl *compl) |
245 | { |
246 | enum mcc_base_status base_status; |
247 | enum mcc_addl_status addl_status; |
248 | struct be_cmd_resp_hdr *resp_hdr; |
249 | u8 opcode = 0, subsystem = 0; |
250 | |
251 | /* Just swap the status to host endian; mcc tag is opaquely copied |
252 | * from mcc_wrb |
253 | */ |
254 | be_dws_le_to_cpu(compl, 4); |
255 | |
256 | base_status = base_status(compl->status); |
257 | addl_status = addl_status(compl->status); |
258 | |
259 | resp_hdr = be_decode_resp_hdr(tag0: compl->tag0, tag1: compl->tag1); |
260 | if (resp_hdr) { |
261 | opcode = resp_hdr->opcode; |
262 | subsystem = resp_hdr->subsystem; |
263 | } |
264 | |
265 | be_async_cmd_process(adapter, compl, resp_hdr); |
266 | |
267 | if (base_status != MCC_STATUS_SUCCESS && |
268 | !be_skip_err_log(opcode, base_status, addl_status)) { |
269 | if (base_status == MCC_STATUS_UNAUTHORIZED_REQUEST || |
270 | addl_status == MCC_ADDL_STATUS_INSUFFICIENT_PRIVILEGES) { |
271 | dev_warn(&adapter->pdev->dev, |
272 | "VF is not privileged to issue opcode %d-%d\n" , |
273 | opcode, subsystem); |
274 | } else { |
275 | dev_err(&adapter->pdev->dev, |
276 | "opcode %d-%d failed:status %d-%d\n" , |
277 | opcode, subsystem, base_status, addl_status); |
278 | } |
279 | } |
280 | return compl->status; |
281 | } |
282 | |
283 | /* Link state evt is a string of bytes; no need for endian swapping */ |
284 | static void be_async_link_state_process(struct be_adapter *adapter, |
285 | struct be_mcc_compl *compl) |
286 | { |
287 | struct be_async_event_link_state *evt = |
288 | (struct be_async_event_link_state *)compl; |
289 | |
290 | /* When link status changes, link speed must be re-queried from FW */ |
291 | adapter->phy.link_speed = -1; |
292 | |
293 | /* On BEx the FW does not send a separate link status |
294 | * notification for physical and logical link. |
295 | * On other chips just process the logical link |
296 | * status notification |
297 | */ |
298 | if (!BEx_chip(adapter) && |
299 | !(evt->port_link_status & LOGICAL_LINK_STATUS_MASK)) |
300 | return; |
301 | |
302 | /* For the initial link status do not rely on the ASYNC event as |
303 | * it may not be received in some cases. |
304 | */ |
305 | if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT) |
306 | be_link_status_update(adapter, |
307 | link_status: evt->port_link_status & LINK_STATUS_MASK); |
308 | } |
309 | |
310 | static void be_async_port_misconfig_event_process(struct be_adapter *adapter, |
311 | struct be_mcc_compl *compl) |
312 | { |
313 | struct be_async_event_misconfig_port *evt = |
314 | (struct be_async_event_misconfig_port *)compl; |
315 | u32 sfp_misconfig_evt_word1 = le32_to_cpu(evt->event_data_word1); |
316 | u32 sfp_misconfig_evt_word2 = le32_to_cpu(evt->event_data_word2); |
317 | u8 phy_oper_state = PHY_STATE_OPER_MSG_NONE; |
318 | struct device *dev = &adapter->pdev->dev; |
319 | u8 msg_severity = DEFAULT_MSG_SEVERITY; |
320 | u8 phy_state_info; |
321 | u8 new_phy_state; |
322 | |
323 | new_phy_state = |
324 | (sfp_misconfig_evt_word1 >> (adapter->hba_port_num * 8)) & 0xff; |
325 | |
326 | if (new_phy_state == adapter->phy_state) |
327 | return; |
328 | |
329 | adapter->phy_state = new_phy_state; |
330 | |
331 | /* for older fw that doesn't populate link effect data */ |
332 | if (!sfp_misconfig_evt_word2) |
333 | goto log_message; |
334 | |
335 | phy_state_info = |
336 | (sfp_misconfig_evt_word2 >> (adapter->hba_port_num * 8)) & 0xff; |
337 | |
338 | if (phy_state_info & PHY_STATE_INFO_VALID) { |
339 | msg_severity = (phy_state_info & PHY_STATE_MSG_SEVERITY) >> 1; |
340 | |
341 | if (be_phy_unqualified(new_phy_state)) |
342 | phy_oper_state = (phy_state_info & PHY_STATE_OPER); |
343 | } |
344 | |
345 | log_message: |
346 | /* Log an error message that would allow a user to determine |
347 | * whether the SFPs have an issue |
348 | */ |
349 | if (be_phy_state_unknown(new_phy_state)) |
350 | dev_printk(be_port_misconfig_evt_severity[msg_severity], dev, |
351 | "Port %c: Unrecognized Optics state: 0x%x. %s" , |
352 | adapter->port_name, |
353 | new_phy_state, |
354 | phy_state_oper_desc[phy_oper_state]); |
355 | else |
356 | dev_printk(be_port_misconfig_evt_severity[msg_severity], dev, |
357 | "Port %c: %s %s" , |
358 | adapter->port_name, |
359 | be_misconfig_evt_port_state[new_phy_state], |
360 | phy_state_oper_desc[phy_oper_state]); |
361 | |
362 | /* Log Vendor name and part no. if a misconfigured SFP is detected */ |
363 | if (be_phy_misconfigured(new_phy_state)) |
364 | adapter->flags |= BE_FLAGS_PHY_MISCONFIGURED; |
365 | } |
366 | |
367 | /* Grp5 CoS Priority evt */ |
368 | static void be_async_grp5_cos_priority_process(struct be_adapter *adapter, |
369 | struct be_mcc_compl *compl) |
370 | { |
371 | struct be_async_event_grp5_cos_priority *evt = |
372 | (struct be_async_event_grp5_cos_priority *)compl; |
373 | |
374 | if (evt->valid) { |
375 | adapter->vlan_prio_bmap = evt->available_priority_bmap; |
376 | adapter->recommended_prio_bits = |
377 | evt->reco_default_priority << VLAN_PRIO_SHIFT; |
378 | } |
379 | } |
380 | |
381 | /* Grp5 QOS Speed evt: qos_link_speed is in units of 10 Mbps */ |
382 | static void be_async_grp5_qos_speed_process(struct be_adapter *adapter, |
383 | struct be_mcc_compl *compl) |
384 | { |
385 | struct be_async_event_grp5_qos_link_speed *evt = |
386 | (struct be_async_event_grp5_qos_link_speed *)compl; |
387 | |
388 | if (adapter->phy.link_speed >= 0 && |
389 | evt->physical_port == adapter->port_num) |
390 | adapter->phy.link_speed = le16_to_cpu(evt->qos_link_speed) * 10; |
391 | } |
392 | |
393 | /*Grp5 PVID evt*/ |
394 | static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, |
395 | struct be_mcc_compl *compl) |
396 | { |
397 | struct be_async_event_grp5_pvid_state *evt = |
398 | (struct be_async_event_grp5_pvid_state *)compl; |
399 | |
400 | if (evt->enabled) { |
401 | adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK; |
402 | dev_info(&adapter->pdev->dev, "LPVID: %d\n" , adapter->pvid); |
403 | } else { |
404 | adapter->pvid = 0; |
405 | } |
406 | } |
407 | |
408 | #define MGMT_ENABLE_MASK 0x4 |
409 | static void be_async_grp5_fw_control_process(struct be_adapter *adapter, |
410 | struct be_mcc_compl *compl) |
411 | { |
412 | struct be_async_fw_control *evt = (struct be_async_fw_control *)compl; |
413 | u32 evt_dw1 = le32_to_cpu(evt->event_data_word1); |
414 | |
415 | if (evt_dw1 & MGMT_ENABLE_MASK) { |
416 | adapter->flags |= BE_FLAGS_OS2BMC; |
417 | adapter->bmc_filt_mask = le32_to_cpu(evt->event_data_word2); |
418 | } else { |
419 | adapter->flags &= ~BE_FLAGS_OS2BMC; |
420 | } |
421 | } |
422 | |
423 | static void be_async_grp5_evt_process(struct be_adapter *adapter, |
424 | struct be_mcc_compl *compl) |
425 | { |
426 | u8 event_type = (compl->flags >> ASYNC_EVENT_TYPE_SHIFT) & |
427 | ASYNC_EVENT_TYPE_MASK; |
428 | |
429 | switch (event_type) { |
430 | case ASYNC_EVENT_COS_PRIORITY: |
431 | be_async_grp5_cos_priority_process(adapter, compl); |
432 | break; |
433 | case ASYNC_EVENT_QOS_SPEED: |
434 | be_async_grp5_qos_speed_process(adapter, compl); |
435 | break; |
436 | case ASYNC_EVENT_PVID_STATE: |
437 | be_async_grp5_pvid_state_process(adapter, compl); |
438 | break; |
439 | /* Async event to disable/enable os2bmc and/or mac-learning */ |
440 | case ASYNC_EVENT_FW_CONTROL: |
441 | be_async_grp5_fw_control_process(adapter, compl); |
442 | break; |
443 | default: |
444 | break; |
445 | } |
446 | } |
447 | |
448 | static void be_async_dbg_evt_process(struct be_adapter *adapter, |
449 | struct be_mcc_compl *cmp) |
450 | { |
451 | u8 event_type = 0; |
452 | struct be_async_event_qnq *evt = (struct be_async_event_qnq *)cmp; |
453 | |
454 | event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) & |
455 | ASYNC_EVENT_TYPE_MASK; |
456 | |
457 | switch (event_type) { |
458 | case ASYNC_DEBUG_EVENT_TYPE_QNQ: |
459 | if (evt->valid) |
460 | adapter->qnq_vid = le16_to_cpu(evt->vlan_tag); |
461 | adapter->flags |= BE_FLAGS_QNQ_ASYNC_EVT_RCVD; |
462 | break; |
463 | default: |
464 | dev_warn(&adapter->pdev->dev, "Unknown debug event 0x%x!\n" , |
465 | event_type); |
466 | break; |
467 | } |
468 | } |
469 | |
470 | static void be_async_sliport_evt_process(struct be_adapter *adapter, |
471 | struct be_mcc_compl *cmp) |
472 | { |
473 | u8 event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) & |
474 | ASYNC_EVENT_TYPE_MASK; |
475 | |
476 | if (event_type == ASYNC_EVENT_PORT_MISCONFIG) |
477 | be_async_port_misconfig_event_process(adapter, compl: cmp); |
478 | } |
479 | |
480 | static inline bool is_link_state_evt(u32 flags) |
481 | { |
482 | return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == |
483 | ASYNC_EVENT_CODE_LINK_STATE; |
484 | } |
485 | |
486 | static inline bool is_grp5_evt(u32 flags) |
487 | { |
488 | return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == |
489 | ASYNC_EVENT_CODE_GRP_5; |
490 | } |
491 | |
492 | static inline bool is_dbg_evt(u32 flags) |
493 | { |
494 | return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == |
495 | ASYNC_EVENT_CODE_QNQ; |
496 | } |
497 | |
498 | static inline bool is_sliport_evt(u32 flags) |
499 | { |
500 | return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == |
501 | ASYNC_EVENT_CODE_SLIPORT; |
502 | } |
503 | |
504 | static void be_mcc_event_process(struct be_adapter *adapter, |
505 | struct be_mcc_compl *compl) |
506 | { |
507 | if (is_link_state_evt(flags: compl->flags)) |
508 | be_async_link_state_process(adapter, compl); |
509 | else if (is_grp5_evt(flags: compl->flags)) |
510 | be_async_grp5_evt_process(adapter, compl); |
511 | else if (is_dbg_evt(flags: compl->flags)) |
512 | be_async_dbg_evt_process(adapter, cmp: compl); |
513 | else if (is_sliport_evt(flags: compl->flags)) |
514 | be_async_sliport_evt_process(adapter, cmp: compl); |
515 | } |
516 | |
517 | static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) |
518 | { |
519 | struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; |
520 | struct be_mcc_compl *compl = queue_tail_node(q: mcc_cq); |
521 | |
522 | if (be_mcc_compl_is_new(compl)) { |
523 | queue_tail_inc(q: mcc_cq); |
524 | return compl; |
525 | } |
526 | return NULL; |
527 | } |
528 | |
529 | void be_async_mcc_enable(struct be_adapter *adapter) |
530 | { |
531 | spin_lock_bh(lock: &adapter->mcc_cq_lock); |
532 | |
533 | be_cq_notify(adapter, qid: adapter->mcc_obj.cq.id, arm: true, num_popped: 0); |
534 | adapter->mcc_obj.rearm_cq = true; |
535 | |
536 | spin_unlock_bh(lock: &adapter->mcc_cq_lock); |
537 | } |
538 | |
539 | void be_async_mcc_disable(struct be_adapter *adapter) |
540 | { |
541 | spin_lock_bh(lock: &adapter->mcc_cq_lock); |
542 | |
543 | adapter->mcc_obj.rearm_cq = false; |
544 | be_cq_notify(adapter, qid: adapter->mcc_obj.cq.id, arm: false, num_popped: 0); |
545 | |
546 | spin_unlock_bh(lock: &adapter->mcc_cq_lock); |
547 | } |
548 | |
549 | int be_process_mcc(struct be_adapter *adapter) |
550 | { |
551 | struct be_mcc_compl *compl; |
552 | int num = 0, status = 0; |
553 | struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; |
554 | |
555 | spin_lock(lock: &adapter->mcc_cq_lock); |
556 | |
557 | while ((compl = be_mcc_compl_get(adapter))) { |
558 | if (compl->flags & CQE_FLAGS_ASYNC_MASK) { |
559 | be_mcc_event_process(adapter, compl); |
560 | } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { |
561 | status = be_mcc_compl_process(adapter, compl); |
562 | atomic_dec(v: &mcc_obj->q.used); |
563 | } |
564 | be_mcc_compl_use(compl); |
565 | num++; |
566 | } |
567 | |
568 | if (num) |
569 | be_cq_notify(adapter, qid: mcc_obj->cq.id, arm: mcc_obj->rearm_cq, num_popped: num); |
570 | |
571 | spin_unlock(lock: &adapter->mcc_cq_lock); |
572 | return status; |
573 | } |
574 | |
575 | /* Wait till no more pending mcc requests are present */ |
576 | static int be_mcc_wait_compl(struct be_adapter *adapter) |
577 | { |
578 | #define mcc_timeout 12000 /* 12s timeout */ |
579 | int i, status = 0; |
580 | struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; |
581 | |
582 | for (i = 0; i < mcc_timeout; i++) { |
583 | if (be_check_error(adapter, BE_ERROR_ANY)) |
584 | return -EIO; |
585 | |
586 | local_bh_disable(); |
587 | status = be_process_mcc(adapter); |
588 | local_bh_enable(); |
589 | |
590 | if (atomic_read(v: &mcc_obj->q.used) == 0) |
591 | break; |
592 | usleep_range(min: 500, max: 1000); |
593 | } |
594 | if (i == mcc_timeout) { |
595 | dev_err(&adapter->pdev->dev, "FW not responding\n" ); |
596 | be_set_error(adapter, BE_ERROR_FW); |
597 | return -EIO; |
598 | } |
599 | return status; |
600 | } |
601 | |
602 | /* Notify MCC requests and wait for completion */ |
603 | static int be_mcc_notify_wait(struct be_adapter *adapter) |
604 | { |
605 | int status; |
606 | struct be_mcc_wrb *wrb; |
607 | struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; |
608 | u32 index = mcc_obj->q.head; |
609 | struct be_cmd_resp_hdr *resp; |
610 | |
611 | index_dec(index: &index, limit: mcc_obj->q.len); |
612 | wrb = queue_index_node(q: &mcc_obj->q, index); |
613 | |
614 | resp = be_decode_resp_hdr(tag0: wrb->tag0, tag1: wrb->tag1); |
615 | |
616 | status = be_mcc_notify(adapter); |
617 | if (status) |
618 | goto out; |
619 | |
620 | status = be_mcc_wait_compl(adapter); |
621 | if (status == -EIO) |
622 | goto out; |
623 | |
624 | status = (resp->base_status | |
625 | ((resp->addl_status & CQE_ADDL_STATUS_MASK) << |
626 | CQE_ADDL_STATUS_SHIFT)); |
627 | out: |
628 | return status; |
629 | } |
630 | |
631 | static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) |
632 | { |
633 | int msecs = 0; |
634 | u32 ready; |
635 | |
636 | do { |
637 | if (be_check_error(adapter, BE_ERROR_ANY)) |
638 | return -EIO; |
639 | |
640 | ready = ioread32(db); |
641 | if (ready == 0xffffffff) |
642 | return -1; |
643 | |
644 | ready &= MPU_MAILBOX_DB_RDY_MASK; |
645 | if (ready) |
646 | break; |
647 | |
648 | if (msecs > 4000) { |
649 | dev_err(&adapter->pdev->dev, "FW not responding\n" ); |
650 | be_set_error(adapter, BE_ERROR_FW); |
651 | be_detect_error(adapter); |
652 | return -1; |
653 | } |
654 | |
655 | msleep(msecs: 1); |
656 | msecs++; |
657 | } while (true); |
658 | |
659 | return 0; |
660 | } |
661 | |
662 | /* Insert the mailbox address into the doorbell in two steps |
663 | * Polls on the mbox doorbell till a command completion (or a timeout) occurs |
664 | */ |
665 | static int be_mbox_notify_wait(struct be_adapter *adapter) |
666 | { |
667 | int status; |
668 | u32 val = 0; |
669 | void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET; |
670 | struct be_dma_mem *mbox_mem = &adapter->mbox_mem; |
671 | struct be_mcc_mailbox *mbox = mbox_mem->va; |
672 | struct be_mcc_compl *compl = &mbox->compl; |
673 | |
674 | /* wait for ready to be set */ |
675 | status = be_mbox_db_ready_wait(adapter, db); |
676 | if (status != 0) |
677 | return status; |
678 | |
679 | val |= MPU_MAILBOX_DB_HI_MASK; |
680 | /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ |
681 | val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; |
682 | iowrite32(val, db); |
683 | |
684 | /* wait for ready to be set */ |
685 | status = be_mbox_db_ready_wait(adapter, db); |
686 | if (status != 0) |
687 | return status; |
688 | |
689 | val = 0; |
690 | /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */ |
691 | val |= (u32)(mbox_mem->dma >> 4) << 2; |
692 | iowrite32(val, db); |
693 | |
694 | status = be_mbox_db_ready_wait(adapter, db); |
695 | if (status != 0) |
696 | return status; |
697 | |
698 | /* A cq entry has been made now */ |
699 | if (be_mcc_compl_is_new(compl)) { |
700 | status = be_mcc_compl_process(adapter, compl: &mbox->compl); |
701 | be_mcc_compl_use(compl); |
702 | if (status) |
703 | return status; |
704 | } else { |
705 | dev_err(&adapter->pdev->dev, "invalid mailbox completion\n" ); |
706 | return -1; |
707 | } |
708 | return 0; |
709 | } |
710 | |
711 | u16 be_POST_stage_get(struct be_adapter *adapter) |
712 | { |
713 | u32 sem; |
714 | |
715 | if (BEx_chip(adapter)) |
716 | sem = ioread32(adapter->csr + SLIPORT_SEMAPHORE_OFFSET_BEx); |
717 | else |
718 | pci_read_config_dword(dev: adapter->pdev, |
719 | SLIPORT_SEMAPHORE_OFFSET_SH, val: &sem); |
720 | |
721 | return sem & POST_STAGE_MASK; |
722 | } |
723 | |
724 | static int lancer_wait_ready(struct be_adapter *adapter) |
725 | { |
726 | #define SLIPORT_READY_TIMEOUT 30 |
727 | u32 sliport_status; |
728 | int i; |
729 | |
730 | for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) { |
731 | sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); |
732 | if (sliport_status & SLIPORT_STATUS_RDY_MASK) |
733 | return 0; |
734 | |
735 | if (sliport_status & SLIPORT_STATUS_ERR_MASK && |
736 | !(sliport_status & SLIPORT_STATUS_RN_MASK)) |
737 | return -EIO; |
738 | |
739 | msleep(msecs: 1000); |
740 | } |
741 | |
742 | return sliport_status ? : -1; |
743 | } |
744 | |
745 | int be_fw_wait_ready(struct be_adapter *adapter) |
746 | { |
747 | u16 stage; |
748 | int status, timeout = 0; |
749 | struct device *dev = &adapter->pdev->dev; |
750 | |
751 | if (lancer_chip(adapter)) { |
752 | status = lancer_wait_ready(adapter); |
753 | if (status) { |
754 | stage = status; |
755 | goto err; |
756 | } |
757 | return 0; |
758 | } |
759 | |
760 | do { |
761 | /* There's no means to poll POST state on BE2/3 VFs */ |
762 | if (BEx_chip(adapter) && be_virtfn(adapter)) |
763 | return 0; |
764 | |
765 | stage = be_POST_stage_get(adapter); |
766 | if (stage == POST_STAGE_ARMFW_RDY) |
767 | return 0; |
768 | |
769 | dev_info(dev, "Waiting for POST, %ds elapsed\n" , timeout); |
770 | if (msleep_interruptible(msecs: 2000)) { |
771 | dev_err(dev, "Waiting for POST aborted\n" ); |
772 | return -EINTR; |
773 | } |
774 | timeout += 2; |
775 | } while (timeout < 60); |
776 | |
777 | err: |
778 | dev_err(dev, "POST timeout; stage=%#x\n" , stage); |
779 | return -ETIMEDOUT; |
780 | } |
781 | |
782 | static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) |
783 | { |
784 | return &wrb->payload.sgl[0]; |
785 | } |
786 | |
787 | static inline void fill_wrb_tags(struct be_mcc_wrb *wrb, unsigned long addr) |
788 | { |
789 | wrb->tag0 = addr & 0xFFFFFFFF; |
790 | wrb->tag1 = upper_32_bits(addr); |
791 | } |
792 | |
793 | /* Don't touch the hdr after it's prepared */ |
794 | /* mem will be NULL for embedded commands */ |
795 | static void be_wrb_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, |
796 | u8 subsystem, u8 opcode, int cmd_len, |
797 | struct be_mcc_wrb *wrb, |
798 | struct be_dma_mem *mem) |
799 | { |
800 | struct be_sge *sge; |
801 | |
802 | req_hdr->opcode = opcode; |
803 | req_hdr->subsystem = subsystem; |
804 | req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); |
805 | req_hdr->version = 0; |
806 | fill_wrb_tags(wrb, addr: (ulong)req_hdr); |
807 | wrb->payload_length = cmd_len; |
808 | if (mem) { |
809 | wrb->embedded |= (1 & MCC_WRB_SGE_CNT_MASK) << |
810 | MCC_WRB_SGE_CNT_SHIFT; |
811 | sge = nonembedded_sgl(wrb); |
812 | sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma)); |
813 | sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF); |
814 | sge->len = cpu_to_le32(mem->size); |
815 | } else |
816 | wrb->embedded |= MCC_WRB_EMBEDDED_MASK; |
817 | be_dws_cpu_to_le(wrb, 8); |
818 | } |
819 | |
820 | static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages, |
821 | struct be_dma_mem *mem) |
822 | { |
823 | int i, buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages); |
824 | u64 dma = (u64)mem->dma; |
825 | |
826 | for (i = 0; i < buf_pages; i++) { |
827 | pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF); |
828 | pages[i].hi = cpu_to_le32(upper_32_bits(dma)); |
829 | dma += PAGE_SIZE_4K; |
830 | } |
831 | } |
832 | |
833 | static inline struct be_mcc_wrb *wrb_from_mbox(struct be_adapter *adapter) |
834 | { |
835 | struct be_dma_mem *mbox_mem = &adapter->mbox_mem; |
836 | struct be_mcc_wrb *wrb = &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb; |
837 | |
838 | memset(wrb, 0, sizeof(*wrb)); |
839 | return wrb; |
840 | } |
841 | |
842 | static struct be_mcc_wrb *wrb_from_mccq(struct be_adapter *adapter) |
843 | { |
844 | struct be_queue_info *mccq = &adapter->mcc_obj.q; |
845 | struct be_mcc_wrb *wrb; |
846 | |
847 | if (!mccq->created) |
848 | return NULL; |
849 | |
850 | if (atomic_read(v: &mccq->used) >= mccq->len) |
851 | return NULL; |
852 | |
853 | wrb = queue_head_node(q: mccq); |
854 | queue_head_inc(q: mccq); |
855 | atomic_inc(v: &mccq->used); |
856 | memset(wrb, 0, sizeof(*wrb)); |
857 | return wrb; |
858 | } |
859 | |
860 | static bool use_mcc(struct be_adapter *adapter) |
861 | { |
862 | return adapter->mcc_obj.q.created; |
863 | } |
864 | |
865 | /* Must be used only in process context */ |
866 | static int be_cmd_lock(struct be_adapter *adapter) |
867 | { |
868 | if (use_mcc(adapter)) { |
869 | mutex_lock(&adapter->mcc_lock); |
870 | return 0; |
871 | } else { |
872 | return mutex_lock_interruptible(&adapter->mbox_lock); |
873 | } |
874 | } |
875 | |
876 | /* Must be used only in process context */ |
877 | static void be_cmd_unlock(struct be_adapter *adapter) |
878 | { |
879 | if (use_mcc(adapter)) |
880 | return mutex_unlock(lock: &adapter->mcc_lock); |
881 | else |
882 | return mutex_unlock(lock: &adapter->mbox_lock); |
883 | } |
884 | |
885 | static struct be_mcc_wrb *be_cmd_copy(struct be_adapter *adapter, |
886 | struct be_mcc_wrb *wrb) |
887 | { |
888 | struct be_mcc_wrb *dest_wrb; |
889 | |
890 | if (use_mcc(adapter)) { |
891 | dest_wrb = wrb_from_mccq(adapter); |
892 | if (!dest_wrb) |
893 | return NULL; |
894 | } else { |
895 | dest_wrb = wrb_from_mbox(adapter); |
896 | } |
897 | |
898 | memcpy(dest_wrb, wrb, sizeof(*wrb)); |
899 | if (wrb->embedded & cpu_to_le32(MCC_WRB_EMBEDDED_MASK)) |
900 | fill_wrb_tags(wrb: dest_wrb, addr: (ulong)embedded_payload(wrb)); |
901 | |
902 | return dest_wrb; |
903 | } |
904 | |
905 | /* Must be used only in process context */ |
906 | static int be_cmd_notify_wait(struct be_adapter *adapter, |
907 | struct be_mcc_wrb *wrb) |
908 | { |
909 | struct be_mcc_wrb *dest_wrb; |
910 | int status; |
911 | |
912 | status = be_cmd_lock(adapter); |
913 | if (status) |
914 | return status; |
915 | |
916 | dest_wrb = be_cmd_copy(adapter, wrb); |
917 | if (!dest_wrb) { |
918 | status = -EBUSY; |
919 | goto unlock; |
920 | } |
921 | |
922 | if (use_mcc(adapter)) |
923 | status = be_mcc_notify_wait(adapter); |
924 | else |
925 | status = be_mbox_notify_wait(adapter); |
926 | |
927 | if (!status) |
928 | memcpy(wrb, dest_wrb, sizeof(*wrb)); |
929 | |
930 | unlock: |
931 | be_cmd_unlock(adapter); |
932 | return status; |
933 | } |
934 | |
935 | /* Tell fw we're about to start firing cmds by writing a |
936 | * special pattern across the wrb hdr; uses mbox |
937 | */ |
938 | int be_cmd_fw_init(struct be_adapter *adapter) |
939 | { |
940 | u8 *wrb; |
941 | int status; |
942 | |
943 | if (lancer_chip(adapter)) |
944 | return 0; |
945 | |
946 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
947 | return -1; |
948 | |
949 | wrb = (u8 *)wrb_from_mbox(adapter); |
950 | *wrb++ = 0xFF; |
951 | *wrb++ = 0x12; |
952 | *wrb++ = 0x34; |
953 | *wrb++ = 0xFF; |
954 | *wrb++ = 0xFF; |
955 | *wrb++ = 0x56; |
956 | *wrb++ = 0x78; |
957 | *wrb = 0xFF; |
958 | |
959 | status = be_mbox_notify_wait(adapter); |
960 | |
961 | mutex_unlock(lock: &adapter->mbox_lock); |
962 | return status; |
963 | } |
964 | |
965 | /* Tell fw we're done with firing cmds by writing a |
966 | * special pattern across the wrb hdr; uses mbox |
967 | */ |
968 | int be_cmd_fw_clean(struct be_adapter *adapter) |
969 | { |
970 | u8 *wrb; |
971 | int status; |
972 | |
973 | if (lancer_chip(adapter)) |
974 | return 0; |
975 | |
976 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
977 | return -1; |
978 | |
979 | wrb = (u8 *)wrb_from_mbox(adapter); |
980 | *wrb++ = 0xFF; |
981 | *wrb++ = 0xAA; |
982 | *wrb++ = 0xBB; |
983 | *wrb++ = 0xFF; |
984 | *wrb++ = 0xFF; |
985 | *wrb++ = 0xCC; |
986 | *wrb++ = 0xDD; |
987 | *wrb = 0xFF; |
988 | |
989 | status = be_mbox_notify_wait(adapter); |
990 | |
991 | mutex_unlock(lock: &adapter->mbox_lock); |
992 | return status; |
993 | } |
994 | |
995 | int be_cmd_eq_create(struct be_adapter *adapter, struct be_eq_obj *eqo) |
996 | { |
997 | struct be_mcc_wrb *wrb; |
998 | struct be_cmd_req_eq_create *req; |
999 | struct be_dma_mem *q_mem = &eqo->q.dma_mem; |
1000 | int status, ver = 0; |
1001 | |
1002 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
1003 | return -1; |
1004 | |
1005 | wrb = wrb_from_mbox(adapter); |
1006 | req = embedded_payload(wrb); |
1007 | |
1008 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1009 | OPCODE_COMMON_EQ_CREATE, cmd_len: sizeof(*req), wrb, |
1010 | NULL); |
1011 | |
1012 | /* Support for EQ_CREATEv2 available only SH-R onwards */ |
1013 | if (!(BEx_chip(adapter) || lancer_chip(adapter))) |
1014 | ver = 2; |
1015 | |
1016 | req->hdr.version = ver; |
1017 | req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); |
1018 | |
1019 | AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); |
1020 | /* 4byte eqe*/ |
1021 | AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); |
1022 | AMAP_SET_BITS(struct amap_eq_context, count, req->context, |
1023 | __ilog2_u32(eqo->q.len / 256)); |
1024 | be_dws_cpu_to_le(req->context, sizeof(req->context)); |
1025 | |
1026 | be_cmd_page_addrs_prepare(pages: req->pages, ARRAY_SIZE(req->pages), mem: q_mem); |
1027 | |
1028 | status = be_mbox_notify_wait(adapter); |
1029 | if (!status) { |
1030 | struct be_cmd_resp_eq_create *resp = embedded_payload(wrb); |
1031 | |
1032 | eqo->q.id = le16_to_cpu(resp->eq_id); |
1033 | eqo->msix_idx = |
1034 | (ver == 2) ? le16_to_cpu(resp->msix_idx) : eqo->idx; |
1035 | eqo->q.created = true; |
1036 | } |
1037 | |
1038 | mutex_unlock(lock: &adapter->mbox_lock); |
1039 | return status; |
1040 | } |
1041 | |
1042 | /* Use MCC */ |
1043 | int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, |
1044 | bool permanent, u32 if_handle, u32 pmac_id) |
1045 | { |
1046 | struct be_mcc_wrb *wrb; |
1047 | struct be_cmd_req_mac_query *req; |
1048 | int status; |
1049 | |
1050 | mutex_lock(&adapter->mcc_lock); |
1051 | |
1052 | wrb = wrb_from_mccq(adapter); |
1053 | if (!wrb) { |
1054 | status = -EBUSY; |
1055 | goto err; |
1056 | } |
1057 | req = embedded_payload(wrb); |
1058 | |
1059 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1060 | OPCODE_COMMON_NTWK_MAC_QUERY, cmd_len: sizeof(*req), wrb, |
1061 | NULL); |
1062 | req->type = MAC_ADDRESS_TYPE_NETWORK; |
1063 | if (permanent) { |
1064 | req->permanent = 1; |
1065 | } else { |
1066 | req->if_id = cpu_to_le16((u16)if_handle); |
1067 | req->pmac_id = cpu_to_le32(pmac_id); |
1068 | req->permanent = 0; |
1069 | } |
1070 | |
1071 | status = be_mcc_notify_wait(adapter); |
1072 | if (!status) { |
1073 | struct be_cmd_resp_mac_query *resp = embedded_payload(wrb); |
1074 | |
1075 | memcpy(mac_addr, resp->mac.addr, ETH_ALEN); |
1076 | } |
1077 | |
1078 | err: |
1079 | mutex_unlock(lock: &adapter->mcc_lock); |
1080 | return status; |
1081 | } |
1082 | |
1083 | /* Uses synchronous MCCQ */ |
1084 | int be_cmd_pmac_add(struct be_adapter *adapter, const u8 *mac_addr, |
1085 | u32 if_id, u32 *pmac_id, u32 domain) |
1086 | { |
1087 | struct be_mcc_wrb *wrb; |
1088 | struct be_cmd_req_pmac_add *req; |
1089 | int status; |
1090 | |
1091 | mutex_lock(&adapter->mcc_lock); |
1092 | |
1093 | wrb = wrb_from_mccq(adapter); |
1094 | if (!wrb) { |
1095 | status = -EBUSY; |
1096 | goto err; |
1097 | } |
1098 | req = embedded_payload(wrb); |
1099 | |
1100 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1101 | OPCODE_COMMON_NTWK_PMAC_ADD, cmd_len: sizeof(*req), wrb, |
1102 | NULL); |
1103 | |
1104 | req->hdr.domain = domain; |
1105 | req->if_id = cpu_to_le32(if_id); |
1106 | memcpy(req->mac_address, mac_addr, ETH_ALEN); |
1107 | |
1108 | status = be_mcc_notify_wait(adapter); |
1109 | if (!status) { |
1110 | struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb); |
1111 | |
1112 | *pmac_id = le32_to_cpu(resp->pmac_id); |
1113 | } |
1114 | |
1115 | err: |
1116 | mutex_unlock(lock: &adapter->mcc_lock); |
1117 | |
1118 | if (base_status(status) == MCC_STATUS_UNAUTHORIZED_REQUEST) |
1119 | status = -EPERM; |
1120 | |
1121 | return status; |
1122 | } |
1123 | |
1124 | /* Uses synchronous MCCQ */ |
1125 | int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, int pmac_id, u32 dom) |
1126 | { |
1127 | struct be_mcc_wrb *wrb; |
1128 | struct be_cmd_req_pmac_del *req; |
1129 | int status; |
1130 | |
1131 | if (pmac_id == -1) |
1132 | return 0; |
1133 | |
1134 | mutex_lock(&adapter->mcc_lock); |
1135 | |
1136 | wrb = wrb_from_mccq(adapter); |
1137 | if (!wrb) { |
1138 | status = -EBUSY; |
1139 | goto err; |
1140 | } |
1141 | req = embedded_payload(wrb); |
1142 | |
1143 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1144 | OPCODE_COMMON_NTWK_PMAC_DEL, cmd_len: sizeof(*req), |
1145 | wrb, NULL); |
1146 | |
1147 | req->hdr.domain = dom; |
1148 | req->if_id = cpu_to_le32(if_id); |
1149 | req->pmac_id = cpu_to_le32(pmac_id); |
1150 | |
1151 | status = be_mcc_notify_wait(adapter); |
1152 | |
1153 | err: |
1154 | mutex_unlock(lock: &adapter->mcc_lock); |
1155 | return status; |
1156 | } |
1157 | |
1158 | /* Uses Mbox */ |
1159 | int be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq, |
1160 | struct be_queue_info *eq, bool no_delay, int coalesce_wm) |
1161 | { |
1162 | struct be_mcc_wrb *wrb; |
1163 | struct be_cmd_req_cq_create *req; |
1164 | struct be_dma_mem *q_mem = &cq->dma_mem; |
1165 | void *ctxt; |
1166 | int status; |
1167 | |
1168 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
1169 | return -1; |
1170 | |
1171 | wrb = wrb_from_mbox(adapter); |
1172 | req = embedded_payload(wrb); |
1173 | ctxt = &req->context; |
1174 | |
1175 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1176 | OPCODE_COMMON_CQ_CREATE, cmd_len: sizeof(*req), wrb, |
1177 | NULL); |
1178 | |
1179 | req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); |
1180 | |
1181 | if (BEx_chip(adapter)) { |
1182 | AMAP_SET_BITS(struct amap_cq_context_be, coalescwm, ctxt, |
1183 | coalesce_wm); |
1184 | AMAP_SET_BITS(struct amap_cq_context_be, nodelay, |
1185 | ctxt, no_delay); |
1186 | AMAP_SET_BITS(struct amap_cq_context_be, count, ctxt, |
1187 | __ilog2_u32(cq->len / 256)); |
1188 | AMAP_SET_BITS(struct amap_cq_context_be, valid, ctxt, 1); |
1189 | AMAP_SET_BITS(struct amap_cq_context_be, eventable, ctxt, 1); |
1190 | AMAP_SET_BITS(struct amap_cq_context_be, eqid, ctxt, eq->id); |
1191 | } else { |
1192 | req->hdr.version = 2; |
1193 | req->page_size = 1; /* 1 for 4K */ |
1194 | |
1195 | /* coalesce-wm field in this cmd is not relevant to Lancer. |
1196 | * Lancer uses COMMON_MODIFY_CQ to set this field |
1197 | */ |
1198 | if (!lancer_chip(adapter)) |
1199 | AMAP_SET_BITS(struct amap_cq_context_v2, coalescwm, |
1200 | ctxt, coalesce_wm); |
1201 | AMAP_SET_BITS(struct amap_cq_context_v2, nodelay, ctxt, |
1202 | no_delay); |
1203 | AMAP_SET_BITS(struct amap_cq_context_v2, count, ctxt, |
1204 | __ilog2_u32(cq->len / 256)); |
1205 | AMAP_SET_BITS(struct amap_cq_context_v2, valid, ctxt, 1); |
1206 | AMAP_SET_BITS(struct amap_cq_context_v2, eventable, ctxt, 1); |
1207 | AMAP_SET_BITS(struct amap_cq_context_v2, eqid, ctxt, eq->id); |
1208 | } |
1209 | |
1210 | be_dws_cpu_to_le(ctxt, sizeof(req->context)); |
1211 | |
1212 | be_cmd_page_addrs_prepare(pages: req->pages, ARRAY_SIZE(req->pages), mem: q_mem); |
1213 | |
1214 | status = be_mbox_notify_wait(adapter); |
1215 | if (!status) { |
1216 | struct be_cmd_resp_cq_create *resp = embedded_payload(wrb); |
1217 | |
1218 | cq->id = le16_to_cpu(resp->cq_id); |
1219 | cq->created = true; |
1220 | } |
1221 | |
1222 | mutex_unlock(lock: &adapter->mbox_lock); |
1223 | |
1224 | return status; |
1225 | } |
1226 | |
1227 | static u32 be_encoded_q_len(int q_len) |
1228 | { |
1229 | u32 len_encoded = fls(x: q_len); /* log2(len) + 1 */ |
1230 | |
1231 | if (len_encoded == 16) |
1232 | len_encoded = 0; |
1233 | return len_encoded; |
1234 | } |
1235 | |
1236 | static int be_cmd_mccq_ext_create(struct be_adapter *adapter, |
1237 | struct be_queue_info *mccq, |
1238 | struct be_queue_info *cq) |
1239 | { |
1240 | struct be_mcc_wrb *wrb; |
1241 | struct be_cmd_req_mcc_ext_create *req; |
1242 | struct be_dma_mem *q_mem = &mccq->dma_mem; |
1243 | void *ctxt; |
1244 | int status; |
1245 | |
1246 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
1247 | return -1; |
1248 | |
1249 | wrb = wrb_from_mbox(adapter); |
1250 | req = embedded_payload(wrb); |
1251 | ctxt = &req->context; |
1252 | |
1253 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1254 | OPCODE_COMMON_MCC_CREATE_EXT, cmd_len: sizeof(*req), wrb, |
1255 | NULL); |
1256 | |
1257 | req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); |
1258 | if (BEx_chip(adapter)) { |
1259 | AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); |
1260 | AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, |
1261 | be_encoded_q_len(mccq->len)); |
1262 | AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); |
1263 | } else { |
1264 | req->hdr.version = 1; |
1265 | req->cq_id = cpu_to_le16(cq->id); |
1266 | |
1267 | AMAP_SET_BITS(struct amap_mcc_context_v1, ring_size, ctxt, |
1268 | be_encoded_q_len(mccq->len)); |
1269 | AMAP_SET_BITS(struct amap_mcc_context_v1, valid, ctxt, 1); |
1270 | AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_id, |
1271 | ctxt, cq->id); |
1272 | AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_valid, |
1273 | ctxt, 1); |
1274 | } |
1275 | |
1276 | /* Subscribe to Link State, Sliport Event and Group 5 Events |
1277 | * (bits 1, 5 and 17 set) |
1278 | */ |
1279 | req->async_event_bitmap[0] = |
1280 | cpu_to_le32(BIT(ASYNC_EVENT_CODE_LINK_STATE) | |
1281 | BIT(ASYNC_EVENT_CODE_GRP_5) | |
1282 | BIT(ASYNC_EVENT_CODE_QNQ) | |
1283 | BIT(ASYNC_EVENT_CODE_SLIPORT)); |
1284 | |
1285 | be_dws_cpu_to_le(ctxt, sizeof(req->context)); |
1286 | |
1287 | be_cmd_page_addrs_prepare(pages: req->pages, ARRAY_SIZE(req->pages), mem: q_mem); |
1288 | |
1289 | status = be_mbox_notify_wait(adapter); |
1290 | if (!status) { |
1291 | struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); |
1292 | |
1293 | mccq->id = le16_to_cpu(resp->id); |
1294 | mccq->created = true; |
1295 | } |
1296 | mutex_unlock(lock: &adapter->mbox_lock); |
1297 | |
1298 | return status; |
1299 | } |
1300 | |
1301 | static int be_cmd_mccq_org_create(struct be_adapter *adapter, |
1302 | struct be_queue_info *mccq, |
1303 | struct be_queue_info *cq) |
1304 | { |
1305 | struct be_mcc_wrb *wrb; |
1306 | struct be_cmd_req_mcc_create *req; |
1307 | struct be_dma_mem *q_mem = &mccq->dma_mem; |
1308 | void *ctxt; |
1309 | int status; |
1310 | |
1311 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
1312 | return -1; |
1313 | |
1314 | wrb = wrb_from_mbox(adapter); |
1315 | req = embedded_payload(wrb); |
1316 | ctxt = &req->context; |
1317 | |
1318 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1319 | OPCODE_COMMON_MCC_CREATE, cmd_len: sizeof(*req), wrb, |
1320 | NULL); |
1321 | |
1322 | req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); |
1323 | |
1324 | AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); |
1325 | AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, |
1326 | be_encoded_q_len(mccq->len)); |
1327 | AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); |
1328 | |
1329 | be_dws_cpu_to_le(ctxt, sizeof(req->context)); |
1330 | |
1331 | be_cmd_page_addrs_prepare(pages: req->pages, ARRAY_SIZE(req->pages), mem: q_mem); |
1332 | |
1333 | status = be_mbox_notify_wait(adapter); |
1334 | if (!status) { |
1335 | struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); |
1336 | |
1337 | mccq->id = le16_to_cpu(resp->id); |
1338 | mccq->created = true; |
1339 | } |
1340 | |
1341 | mutex_unlock(lock: &adapter->mbox_lock); |
1342 | return status; |
1343 | } |
1344 | |
1345 | int be_cmd_mccq_create(struct be_adapter *adapter, |
1346 | struct be_queue_info *mccq, struct be_queue_info *cq) |
1347 | { |
1348 | int status; |
1349 | |
1350 | status = be_cmd_mccq_ext_create(adapter, mccq, cq); |
1351 | if (status && BEx_chip(adapter)) { |
1352 | dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 " |
1353 | "or newer to avoid conflicting priorities between NIC " |
1354 | "and FCoE traffic" ); |
1355 | status = be_cmd_mccq_org_create(adapter, mccq, cq); |
1356 | } |
1357 | return status; |
1358 | } |
1359 | |
1360 | int be_cmd_txq_create(struct be_adapter *adapter, struct be_tx_obj *txo) |
1361 | { |
1362 | struct be_mcc_wrb wrb = {0}; |
1363 | struct be_cmd_req_eth_tx_create *req; |
1364 | struct be_queue_info *txq = &txo->q; |
1365 | struct be_queue_info *cq = &txo->cq; |
1366 | struct be_dma_mem *q_mem = &txq->dma_mem; |
1367 | int status, ver = 0; |
1368 | |
1369 | req = embedded_payload(wrb: &wrb); |
1370 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ETH, |
1371 | OPCODE_ETH_TX_CREATE, cmd_len: sizeof(*req), wrb: &wrb, NULL); |
1372 | |
1373 | if (lancer_chip(adapter)) { |
1374 | req->hdr.version = 1; |
1375 | } else if (BEx_chip(adapter)) { |
1376 | if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) |
1377 | req->hdr.version = 2; |
1378 | } else { /* For SH */ |
1379 | req->hdr.version = 2; |
1380 | } |
1381 | |
1382 | if (req->hdr.version > 0) |
1383 | req->if_id = cpu_to_le16(adapter->if_handle); |
1384 | req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); |
1385 | req->ulp_num = BE_ULP1_NUM; |
1386 | req->type = BE_ETH_TX_RING_TYPE_STANDARD; |
1387 | req->cq_id = cpu_to_le16(cq->id); |
1388 | req->queue_size = be_encoded_q_len(q_len: txq->len); |
1389 | be_cmd_page_addrs_prepare(pages: req->pages, ARRAY_SIZE(req->pages), mem: q_mem); |
1390 | ver = req->hdr.version; |
1391 | |
1392 | status = be_cmd_notify_wait(adapter, wrb: &wrb); |
1393 | if (!status) { |
1394 | struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb: &wrb); |
1395 | |
1396 | txq->id = le16_to_cpu(resp->cid); |
1397 | if (ver == 2) |
1398 | txo->db_offset = le32_to_cpu(resp->db_offset); |
1399 | else |
1400 | txo->db_offset = DB_TXULP1_OFFSET; |
1401 | txq->created = true; |
1402 | } |
1403 | |
1404 | return status; |
1405 | } |
1406 | |
1407 | /* Uses MCC */ |
1408 | int be_cmd_rxq_create(struct be_adapter *adapter, |
1409 | struct be_queue_info *rxq, u16 cq_id, u16 frag_size, |
1410 | u32 if_id, u32 , u8 *) |
1411 | { |
1412 | struct be_mcc_wrb *wrb; |
1413 | struct be_cmd_req_eth_rx_create *req; |
1414 | struct be_dma_mem *q_mem = &rxq->dma_mem; |
1415 | int status; |
1416 | |
1417 | mutex_lock(&adapter->mcc_lock); |
1418 | |
1419 | wrb = wrb_from_mccq(adapter); |
1420 | if (!wrb) { |
1421 | status = -EBUSY; |
1422 | goto err; |
1423 | } |
1424 | req = embedded_payload(wrb); |
1425 | |
1426 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ETH, |
1427 | OPCODE_ETH_RX_CREATE, cmd_len: sizeof(*req), wrb, NULL); |
1428 | |
1429 | req->cq_id = cpu_to_le16(cq_id); |
1430 | req->frag_size = fls(x: frag_size) - 1; |
1431 | req->num_pages = 2; |
1432 | be_cmd_page_addrs_prepare(pages: req->pages, ARRAY_SIZE(req->pages), mem: q_mem); |
1433 | req->interface_id = cpu_to_le32(if_id); |
1434 | req->max_frame_size = cpu_to_le16(BE_MAX_JUMBO_FRAME_SIZE); |
1435 | req->rss_queue = cpu_to_le32(rss); |
1436 | |
1437 | status = be_mcc_notify_wait(adapter); |
1438 | if (!status) { |
1439 | struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb); |
1440 | |
1441 | rxq->id = le16_to_cpu(resp->id); |
1442 | rxq->created = true; |
1443 | *rss_id = resp->rss_id; |
1444 | } |
1445 | |
1446 | err: |
1447 | mutex_unlock(lock: &adapter->mcc_lock); |
1448 | return status; |
1449 | } |
1450 | |
1451 | /* Generic destroyer function for all types of queues |
1452 | * Uses Mbox |
1453 | */ |
1454 | int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, |
1455 | int queue_type) |
1456 | { |
1457 | struct be_mcc_wrb *wrb; |
1458 | struct be_cmd_req_q_destroy *req; |
1459 | u8 subsys = 0, opcode = 0; |
1460 | int status; |
1461 | |
1462 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
1463 | return -1; |
1464 | |
1465 | wrb = wrb_from_mbox(adapter); |
1466 | req = embedded_payload(wrb); |
1467 | |
1468 | switch (queue_type) { |
1469 | case QTYPE_EQ: |
1470 | subsys = CMD_SUBSYSTEM_COMMON; |
1471 | opcode = OPCODE_COMMON_EQ_DESTROY; |
1472 | break; |
1473 | case QTYPE_CQ: |
1474 | subsys = CMD_SUBSYSTEM_COMMON; |
1475 | opcode = OPCODE_COMMON_CQ_DESTROY; |
1476 | break; |
1477 | case QTYPE_TXQ: |
1478 | subsys = CMD_SUBSYSTEM_ETH; |
1479 | opcode = OPCODE_ETH_TX_DESTROY; |
1480 | break; |
1481 | case QTYPE_RXQ: |
1482 | subsys = CMD_SUBSYSTEM_ETH; |
1483 | opcode = OPCODE_ETH_RX_DESTROY; |
1484 | break; |
1485 | case QTYPE_MCCQ: |
1486 | subsys = CMD_SUBSYSTEM_COMMON; |
1487 | opcode = OPCODE_COMMON_MCC_DESTROY; |
1488 | break; |
1489 | default: |
1490 | BUG(); |
1491 | } |
1492 | |
1493 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, subsystem: subsys, opcode, cmd_len: sizeof(*req), wrb, |
1494 | NULL); |
1495 | req->id = cpu_to_le16(q->id); |
1496 | |
1497 | status = be_mbox_notify_wait(adapter); |
1498 | q->created = false; |
1499 | |
1500 | mutex_unlock(lock: &adapter->mbox_lock); |
1501 | return status; |
1502 | } |
1503 | |
1504 | /* Uses MCC */ |
1505 | int be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q) |
1506 | { |
1507 | struct be_mcc_wrb *wrb; |
1508 | struct be_cmd_req_q_destroy *req; |
1509 | int status; |
1510 | |
1511 | mutex_lock(&adapter->mcc_lock); |
1512 | |
1513 | wrb = wrb_from_mccq(adapter); |
1514 | if (!wrb) { |
1515 | status = -EBUSY; |
1516 | goto err; |
1517 | } |
1518 | req = embedded_payload(wrb); |
1519 | |
1520 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ETH, |
1521 | OPCODE_ETH_RX_DESTROY, cmd_len: sizeof(*req), wrb, NULL); |
1522 | req->id = cpu_to_le16(q->id); |
1523 | |
1524 | status = be_mcc_notify_wait(adapter); |
1525 | q->created = false; |
1526 | |
1527 | err: |
1528 | mutex_unlock(lock: &adapter->mcc_lock); |
1529 | return status; |
1530 | } |
1531 | |
1532 | /* Create an rx filtering policy configuration on an i/f |
1533 | * Will use MBOX only if MCCQ has not been created. |
1534 | */ |
1535 | int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, |
1536 | u32 *if_handle, u32 domain) |
1537 | { |
1538 | struct be_mcc_wrb wrb = {0}; |
1539 | struct be_cmd_req_if_create *req; |
1540 | int status; |
1541 | |
1542 | req = embedded_payload(wrb: &wrb); |
1543 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1544 | OPCODE_COMMON_NTWK_INTERFACE_CREATE, |
1545 | cmd_len: sizeof(*req), wrb: &wrb, NULL); |
1546 | req->hdr.domain = domain; |
1547 | req->capability_flags = cpu_to_le32(cap_flags); |
1548 | req->enable_flags = cpu_to_le32(en_flags); |
1549 | req->pmac_invalid = true; |
1550 | |
1551 | status = be_cmd_notify_wait(adapter, wrb: &wrb); |
1552 | if (!status) { |
1553 | struct be_cmd_resp_if_create *resp = embedded_payload(wrb: &wrb); |
1554 | |
1555 | *if_handle = le32_to_cpu(resp->interface_id); |
1556 | |
1557 | /* Hack to retrieve VF's pmac-id on BE3 */ |
1558 | if (BE3_chip(adapter) && be_virtfn(adapter)) |
1559 | adapter->pmac_id[0] = le32_to_cpu(resp->pmac_id); |
1560 | } |
1561 | return status; |
1562 | } |
1563 | |
1564 | /* Uses MCCQ if available else MBOX */ |
1565 | int be_cmd_if_destroy(struct be_adapter *adapter, int interface_id, u32 domain) |
1566 | { |
1567 | struct be_mcc_wrb wrb = {0}; |
1568 | struct be_cmd_req_if_destroy *req; |
1569 | int status; |
1570 | |
1571 | if (interface_id == -1) |
1572 | return 0; |
1573 | |
1574 | req = embedded_payload(wrb: &wrb); |
1575 | |
1576 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1577 | OPCODE_COMMON_NTWK_INTERFACE_DESTROY, |
1578 | cmd_len: sizeof(*req), wrb: &wrb, NULL); |
1579 | req->hdr.domain = domain; |
1580 | req->interface_id = cpu_to_le32(interface_id); |
1581 | |
1582 | status = be_cmd_notify_wait(adapter, wrb: &wrb); |
1583 | return status; |
1584 | } |
1585 | |
1586 | /* Get stats is a non embedded command: the request is not embedded inside |
1587 | * WRB but is a separate dma memory block |
1588 | * Uses asynchronous MCC |
1589 | */ |
1590 | int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) |
1591 | { |
1592 | struct be_mcc_wrb *wrb; |
1593 | struct be_cmd_req_hdr *hdr; |
1594 | int status = 0; |
1595 | |
1596 | mutex_lock(&adapter->mcc_lock); |
1597 | |
1598 | wrb = wrb_from_mccq(adapter); |
1599 | if (!wrb) { |
1600 | status = -EBUSY; |
1601 | goto err; |
1602 | } |
1603 | hdr = nonemb_cmd->va; |
1604 | |
1605 | be_wrb_cmd_hdr_prepare(req_hdr: hdr, CMD_SUBSYSTEM_ETH, |
1606 | OPCODE_ETH_GET_STATISTICS, cmd_len: nonemb_cmd->size, wrb, |
1607 | mem: nonemb_cmd); |
1608 | |
1609 | /* version 1 of the cmd is not supported only by BE2 */ |
1610 | if (BE2_chip(adapter)) |
1611 | hdr->version = 0; |
1612 | if (BE3_chip(adapter) || lancer_chip(adapter)) |
1613 | hdr->version = 1; |
1614 | else |
1615 | hdr->version = 2; |
1616 | |
1617 | status = be_mcc_notify(adapter); |
1618 | if (status) |
1619 | goto err; |
1620 | |
1621 | adapter->stats_cmd_sent = true; |
1622 | |
1623 | err: |
1624 | mutex_unlock(lock: &adapter->mcc_lock); |
1625 | return status; |
1626 | } |
1627 | |
1628 | /* Lancer Stats */ |
1629 | int lancer_cmd_get_pport_stats(struct be_adapter *adapter, |
1630 | struct be_dma_mem *nonemb_cmd) |
1631 | { |
1632 | struct be_mcc_wrb *wrb; |
1633 | struct lancer_cmd_req_pport_stats *req; |
1634 | int status = 0; |
1635 | |
1636 | if (!be_cmd_allowed(adapter, OPCODE_ETH_GET_PPORT_STATS, |
1637 | CMD_SUBSYSTEM_ETH)) |
1638 | return -EPERM; |
1639 | |
1640 | mutex_lock(&adapter->mcc_lock); |
1641 | |
1642 | wrb = wrb_from_mccq(adapter); |
1643 | if (!wrb) { |
1644 | status = -EBUSY; |
1645 | goto err; |
1646 | } |
1647 | req = nonemb_cmd->va; |
1648 | |
1649 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ETH, |
1650 | OPCODE_ETH_GET_PPORT_STATS, cmd_len: nonemb_cmd->size, |
1651 | wrb, mem: nonemb_cmd); |
1652 | |
1653 | req->cmd_params.params.pport_num = cpu_to_le16(adapter->hba_port_num); |
1654 | req->cmd_params.params.reset_stats = 0; |
1655 | |
1656 | status = be_mcc_notify(adapter); |
1657 | if (status) |
1658 | goto err; |
1659 | |
1660 | adapter->stats_cmd_sent = true; |
1661 | |
1662 | err: |
1663 | mutex_unlock(lock: &adapter->mcc_lock); |
1664 | return status; |
1665 | } |
1666 | |
1667 | static int be_mac_to_link_speed(int mac_speed) |
1668 | { |
1669 | switch (mac_speed) { |
1670 | case PHY_LINK_SPEED_ZERO: |
1671 | return 0; |
1672 | case PHY_LINK_SPEED_10MBPS: |
1673 | return 10; |
1674 | case PHY_LINK_SPEED_100MBPS: |
1675 | return 100; |
1676 | case PHY_LINK_SPEED_1GBPS: |
1677 | return 1000; |
1678 | case PHY_LINK_SPEED_10GBPS: |
1679 | return 10000; |
1680 | case PHY_LINK_SPEED_20GBPS: |
1681 | return 20000; |
1682 | case PHY_LINK_SPEED_25GBPS: |
1683 | return 25000; |
1684 | case PHY_LINK_SPEED_40GBPS: |
1685 | return 40000; |
1686 | } |
1687 | return 0; |
1688 | } |
1689 | |
1690 | /* Uses synchronous mcc |
1691 | * Returns link_speed in Mbps |
1692 | */ |
1693 | int be_cmd_link_status_query(struct be_adapter *adapter, u16 *link_speed, |
1694 | u8 *link_status, u32 dom) |
1695 | { |
1696 | struct be_mcc_wrb *wrb; |
1697 | struct be_cmd_req_link_status *req; |
1698 | int status; |
1699 | |
1700 | mutex_lock(&adapter->mcc_lock); |
1701 | |
1702 | if (link_status) |
1703 | *link_status = LINK_DOWN; |
1704 | |
1705 | wrb = wrb_from_mccq(adapter); |
1706 | if (!wrb) { |
1707 | status = -EBUSY; |
1708 | goto err; |
1709 | } |
1710 | req = embedded_payload(wrb); |
1711 | |
1712 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1713 | OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, |
1714 | cmd_len: sizeof(*req), wrb, NULL); |
1715 | |
1716 | /* version 1 of the cmd is not supported only by BE2 */ |
1717 | if (!BE2_chip(adapter)) |
1718 | req->hdr.version = 1; |
1719 | |
1720 | req->hdr.domain = dom; |
1721 | |
1722 | status = be_mcc_notify_wait(adapter); |
1723 | if (!status) { |
1724 | struct be_cmd_resp_link_status *resp = embedded_payload(wrb); |
1725 | |
1726 | if (link_speed) { |
1727 | *link_speed = resp->link_speed ? |
1728 | le16_to_cpu(resp->link_speed) * 10 : |
1729 | be_mac_to_link_speed(mac_speed: resp->mac_speed); |
1730 | |
1731 | if (!resp->logical_link_status) |
1732 | *link_speed = 0; |
1733 | } |
1734 | if (link_status) |
1735 | *link_status = resp->logical_link_status; |
1736 | } |
1737 | |
1738 | err: |
1739 | mutex_unlock(lock: &adapter->mcc_lock); |
1740 | return status; |
1741 | } |
1742 | |
1743 | /* Uses synchronous mcc */ |
1744 | int be_cmd_get_die_temperature(struct be_adapter *adapter) |
1745 | { |
1746 | struct be_mcc_wrb *wrb; |
1747 | struct be_cmd_req_get_cntl_addnl_attribs *req; |
1748 | int status = 0; |
1749 | |
1750 | mutex_lock(&adapter->mcc_lock); |
1751 | |
1752 | wrb = wrb_from_mccq(adapter); |
1753 | if (!wrb) { |
1754 | status = -EBUSY; |
1755 | goto err; |
1756 | } |
1757 | req = embedded_payload(wrb); |
1758 | |
1759 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1760 | OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, |
1761 | cmd_len: sizeof(*req), wrb, NULL); |
1762 | |
1763 | status = be_mcc_notify(adapter); |
1764 | err: |
1765 | mutex_unlock(lock: &adapter->mcc_lock); |
1766 | return status; |
1767 | } |
1768 | |
1769 | /* Uses synchronous mcc */ |
1770 | int be_cmd_get_fat_dump_len(struct be_adapter *adapter, u32 *dump_size) |
1771 | { |
1772 | struct be_mcc_wrb wrb = {0}; |
1773 | struct be_cmd_req_get_fat *req; |
1774 | int status; |
1775 | |
1776 | req = embedded_payload(wrb: &wrb); |
1777 | |
1778 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1779 | OPCODE_COMMON_MANAGE_FAT, cmd_len: sizeof(*req), |
1780 | wrb: &wrb, NULL); |
1781 | req->fat_operation = cpu_to_le32(QUERY_FAT); |
1782 | status = be_cmd_notify_wait(adapter, wrb: &wrb); |
1783 | if (!status) { |
1784 | struct be_cmd_resp_get_fat *resp = embedded_payload(wrb: &wrb); |
1785 | |
1786 | if (dump_size && resp->log_size) |
1787 | *dump_size = le32_to_cpu(resp->log_size) - |
1788 | sizeof(u32); |
1789 | } |
1790 | return status; |
1791 | } |
1792 | |
1793 | int be_cmd_get_fat_dump(struct be_adapter *adapter, u32 buf_len, void *buf) |
1794 | { |
1795 | struct be_dma_mem get_fat_cmd; |
1796 | struct be_mcc_wrb *wrb; |
1797 | struct be_cmd_req_get_fat *req; |
1798 | u32 offset = 0, total_size, buf_size, |
1799 | log_offset = sizeof(u32), payload_len; |
1800 | int status; |
1801 | |
1802 | if (buf_len == 0) |
1803 | return 0; |
1804 | |
1805 | total_size = buf_len; |
1806 | |
1807 | get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60 * 1024; |
1808 | get_fat_cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, |
1809 | size: get_fat_cmd.size, |
1810 | dma_handle: &get_fat_cmd.dma, GFP_ATOMIC); |
1811 | if (!get_fat_cmd.va) |
1812 | return -ENOMEM; |
1813 | |
1814 | mutex_lock(&adapter->mcc_lock); |
1815 | |
1816 | while (total_size) { |
1817 | buf_size = min(total_size, (u32)60 * 1024); |
1818 | total_size -= buf_size; |
1819 | |
1820 | wrb = wrb_from_mccq(adapter); |
1821 | if (!wrb) { |
1822 | status = -EBUSY; |
1823 | goto err; |
1824 | } |
1825 | req = get_fat_cmd.va; |
1826 | |
1827 | payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size; |
1828 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1829 | OPCODE_COMMON_MANAGE_FAT, cmd_len: payload_len, |
1830 | wrb, mem: &get_fat_cmd); |
1831 | |
1832 | req->fat_operation = cpu_to_le32(RETRIEVE_FAT); |
1833 | req->read_log_offset = cpu_to_le32(log_offset); |
1834 | req->read_log_length = cpu_to_le32(buf_size); |
1835 | req->data_buffer_size = cpu_to_le32(buf_size); |
1836 | |
1837 | status = be_mcc_notify_wait(adapter); |
1838 | if (!status) { |
1839 | struct be_cmd_resp_get_fat *resp = get_fat_cmd.va; |
1840 | |
1841 | memcpy(buf + offset, |
1842 | resp->data_buffer, |
1843 | le32_to_cpu(resp->read_log_length)); |
1844 | } else { |
1845 | dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n" ); |
1846 | goto err; |
1847 | } |
1848 | offset += buf_size; |
1849 | log_offset += buf_size; |
1850 | } |
1851 | err: |
1852 | dma_free_coherent(dev: &adapter->pdev->dev, size: get_fat_cmd.size, |
1853 | cpu_addr: get_fat_cmd.va, dma_handle: get_fat_cmd.dma); |
1854 | mutex_unlock(lock: &adapter->mcc_lock); |
1855 | return status; |
1856 | } |
1857 | |
1858 | /* Uses synchronous mcc */ |
1859 | int be_cmd_get_fw_ver(struct be_adapter *adapter) |
1860 | { |
1861 | struct be_mcc_wrb *wrb; |
1862 | struct be_cmd_req_get_fw_version *req; |
1863 | int status; |
1864 | |
1865 | mutex_lock(&adapter->mcc_lock); |
1866 | |
1867 | wrb = wrb_from_mccq(adapter); |
1868 | if (!wrb) { |
1869 | status = -EBUSY; |
1870 | goto err; |
1871 | } |
1872 | |
1873 | req = embedded_payload(wrb); |
1874 | |
1875 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1876 | OPCODE_COMMON_GET_FW_VERSION, cmd_len: sizeof(*req), wrb, |
1877 | NULL); |
1878 | status = be_mcc_notify_wait(adapter); |
1879 | if (!status) { |
1880 | struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); |
1881 | |
1882 | strscpy(adapter->fw_ver, resp->firmware_version_string, |
1883 | sizeof(adapter->fw_ver)); |
1884 | strscpy(adapter->fw_on_flash, resp->fw_on_flash_version_string, |
1885 | sizeof(adapter->fw_on_flash)); |
1886 | } |
1887 | err: |
1888 | mutex_unlock(lock: &adapter->mcc_lock); |
1889 | return status; |
1890 | } |
1891 | |
1892 | /* set the EQ delay interval of an EQ to specified value |
1893 | * Uses async mcc |
1894 | */ |
1895 | static int __be_cmd_modify_eqd(struct be_adapter *adapter, |
1896 | struct be_set_eqd *set_eqd, int num) |
1897 | { |
1898 | struct be_mcc_wrb *wrb; |
1899 | struct be_cmd_req_modify_eq_delay *req; |
1900 | int status = 0, i; |
1901 | |
1902 | mutex_lock(&adapter->mcc_lock); |
1903 | |
1904 | wrb = wrb_from_mccq(adapter); |
1905 | if (!wrb) { |
1906 | status = -EBUSY; |
1907 | goto err; |
1908 | } |
1909 | req = embedded_payload(wrb); |
1910 | |
1911 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1912 | OPCODE_COMMON_MODIFY_EQ_DELAY, cmd_len: sizeof(*req), wrb, |
1913 | NULL); |
1914 | |
1915 | req->num_eq = cpu_to_le32(num); |
1916 | for (i = 0; i < num; i++) { |
1917 | req->set_eqd[i].eq_id = cpu_to_le32(set_eqd[i].eq_id); |
1918 | req->set_eqd[i].phase = 0; |
1919 | req->set_eqd[i].delay_multiplier = |
1920 | cpu_to_le32(set_eqd[i].delay_multiplier); |
1921 | } |
1922 | |
1923 | status = be_mcc_notify(adapter); |
1924 | err: |
1925 | mutex_unlock(lock: &adapter->mcc_lock); |
1926 | return status; |
1927 | } |
1928 | |
1929 | int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd, |
1930 | int num) |
1931 | { |
1932 | int num_eqs, i = 0; |
1933 | |
1934 | while (num) { |
1935 | num_eqs = min(num, 8); |
1936 | __be_cmd_modify_eqd(adapter, set_eqd: &set_eqd[i], num: num_eqs); |
1937 | i += num_eqs; |
1938 | num -= num_eqs; |
1939 | } |
1940 | |
1941 | return 0; |
1942 | } |
1943 | |
1944 | /* Uses sycnhronous mcc */ |
1945 | int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, |
1946 | u32 num, u32 domain) |
1947 | { |
1948 | struct be_mcc_wrb *wrb; |
1949 | struct be_cmd_req_vlan_config *req; |
1950 | int status; |
1951 | |
1952 | mutex_lock(&adapter->mcc_lock); |
1953 | |
1954 | wrb = wrb_from_mccq(adapter); |
1955 | if (!wrb) { |
1956 | status = -EBUSY; |
1957 | goto err; |
1958 | } |
1959 | req = embedded_payload(wrb); |
1960 | |
1961 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1962 | OPCODE_COMMON_NTWK_VLAN_CONFIG, cmd_len: sizeof(*req), |
1963 | wrb, NULL); |
1964 | req->hdr.domain = domain; |
1965 | |
1966 | req->interface_id = if_id; |
1967 | req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0; |
1968 | req->num_vlan = num; |
1969 | memcpy(req->normal_vlan, vtag_array, |
1970 | req->num_vlan * sizeof(vtag_array[0])); |
1971 | |
1972 | status = be_mcc_notify_wait(adapter); |
1973 | err: |
1974 | mutex_unlock(lock: &adapter->mcc_lock); |
1975 | return status; |
1976 | } |
1977 | |
1978 | static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) |
1979 | { |
1980 | struct be_mcc_wrb *wrb; |
1981 | struct be_dma_mem *mem = &adapter->rx_filter; |
1982 | struct be_cmd_req_rx_filter *req = mem->va; |
1983 | int status; |
1984 | |
1985 | mutex_lock(&adapter->mcc_lock); |
1986 | |
1987 | wrb = wrb_from_mccq(adapter); |
1988 | if (!wrb) { |
1989 | status = -EBUSY; |
1990 | goto err; |
1991 | } |
1992 | memset(req, 0, sizeof(*req)); |
1993 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
1994 | OPCODE_COMMON_NTWK_RX_FILTER, cmd_len: sizeof(*req), |
1995 | wrb, mem); |
1996 | |
1997 | req->if_id = cpu_to_le32(adapter->if_handle); |
1998 | req->if_flags_mask = cpu_to_le32(flags); |
1999 | req->if_flags = (value == ON) ? req->if_flags_mask : 0; |
2000 | |
2001 | if (flags & BE_IF_FLAGS_MULTICAST) { |
2002 | int i; |
2003 | |
2004 | /* Reset mcast promisc mode if already set by setting mask |
2005 | * and not setting flags field |
2006 | */ |
2007 | req->if_flags_mask |= |
2008 | cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS & |
2009 | be_if_cap_flags(adapter)); |
2010 | req->mcast_num = cpu_to_le32(adapter->mc_count); |
2011 | for (i = 0; i < adapter->mc_count; i++) |
2012 | ether_addr_copy(dst: req->mcast_mac[i].byte, |
2013 | src: adapter->mc_list[i].mac); |
2014 | } |
2015 | |
2016 | status = be_mcc_notify_wait(adapter); |
2017 | err: |
2018 | mutex_unlock(lock: &adapter->mcc_lock); |
2019 | return status; |
2020 | } |
2021 | |
2022 | int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) |
2023 | { |
2024 | struct device *dev = &adapter->pdev->dev; |
2025 | |
2026 | if ((flags & be_if_cap_flags(adapter)) != flags) { |
2027 | dev_warn(dev, "Cannot set rx filter flags 0x%x\n" , flags); |
2028 | dev_warn(dev, "Interface is capable of 0x%x flags only\n" , |
2029 | be_if_cap_flags(adapter)); |
2030 | } |
2031 | flags &= be_if_cap_flags(adapter); |
2032 | if (!flags) |
2033 | return -ENOTSUPP; |
2034 | |
2035 | return __be_cmd_rx_filter(adapter, flags, value); |
2036 | } |
2037 | |
2038 | /* Uses synchrounous mcc */ |
2039 | int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) |
2040 | { |
2041 | struct be_mcc_wrb *wrb; |
2042 | struct be_cmd_req_set_flow_control *req; |
2043 | int status; |
2044 | |
2045 | if (!be_cmd_allowed(adapter, OPCODE_COMMON_SET_FLOW_CONTROL, |
2046 | CMD_SUBSYSTEM_COMMON)) |
2047 | return -EPERM; |
2048 | |
2049 | mutex_lock(&adapter->mcc_lock); |
2050 | |
2051 | wrb = wrb_from_mccq(adapter); |
2052 | if (!wrb) { |
2053 | status = -EBUSY; |
2054 | goto err; |
2055 | } |
2056 | req = embedded_payload(wrb); |
2057 | |
2058 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2059 | OPCODE_COMMON_SET_FLOW_CONTROL, cmd_len: sizeof(*req), |
2060 | wrb, NULL); |
2061 | |
2062 | req->hdr.version = 1; |
2063 | req->tx_flow_control = cpu_to_le16((u16)tx_fc); |
2064 | req->rx_flow_control = cpu_to_le16((u16)rx_fc); |
2065 | |
2066 | status = be_mcc_notify_wait(adapter); |
2067 | |
2068 | err: |
2069 | mutex_unlock(lock: &adapter->mcc_lock); |
2070 | |
2071 | if (base_status(status) == MCC_STATUS_FEATURE_NOT_SUPPORTED) |
2072 | return -EOPNOTSUPP; |
2073 | |
2074 | return status; |
2075 | } |
2076 | |
2077 | /* Uses sycn mcc */ |
2078 | int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) |
2079 | { |
2080 | struct be_mcc_wrb *wrb; |
2081 | struct be_cmd_req_get_flow_control *req; |
2082 | int status; |
2083 | |
2084 | if (!be_cmd_allowed(adapter, OPCODE_COMMON_GET_FLOW_CONTROL, |
2085 | CMD_SUBSYSTEM_COMMON)) |
2086 | return -EPERM; |
2087 | |
2088 | mutex_lock(&adapter->mcc_lock); |
2089 | |
2090 | wrb = wrb_from_mccq(adapter); |
2091 | if (!wrb) { |
2092 | status = -EBUSY; |
2093 | goto err; |
2094 | } |
2095 | req = embedded_payload(wrb); |
2096 | |
2097 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2098 | OPCODE_COMMON_GET_FLOW_CONTROL, cmd_len: sizeof(*req), |
2099 | wrb, NULL); |
2100 | |
2101 | status = be_mcc_notify_wait(adapter); |
2102 | if (!status) { |
2103 | struct be_cmd_resp_get_flow_control *resp = |
2104 | embedded_payload(wrb); |
2105 | |
2106 | *tx_fc = le16_to_cpu(resp->tx_flow_control); |
2107 | *rx_fc = le16_to_cpu(resp->rx_flow_control); |
2108 | } |
2109 | |
2110 | err: |
2111 | mutex_unlock(lock: &adapter->mcc_lock); |
2112 | return status; |
2113 | } |
2114 | |
2115 | /* Uses mbox */ |
2116 | int be_cmd_query_fw_cfg(struct be_adapter *adapter) |
2117 | { |
2118 | struct be_mcc_wrb *wrb; |
2119 | struct be_cmd_req_query_fw_cfg *req; |
2120 | int status; |
2121 | |
2122 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
2123 | return -1; |
2124 | |
2125 | wrb = wrb_from_mbox(adapter); |
2126 | req = embedded_payload(wrb); |
2127 | |
2128 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2129 | OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, |
2130 | cmd_len: sizeof(*req), wrb, NULL); |
2131 | |
2132 | status = be_mbox_notify_wait(adapter); |
2133 | if (!status) { |
2134 | struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); |
2135 | |
2136 | adapter->port_num = le32_to_cpu(resp->phys_port); |
2137 | adapter->function_mode = le32_to_cpu(resp->function_mode); |
2138 | adapter->function_caps = le32_to_cpu(resp->function_caps); |
2139 | adapter->asic_rev = le32_to_cpu(resp->asic_revision) & 0xFF; |
2140 | dev_info(&adapter->pdev->dev, |
2141 | "FW config: function_mode=0x%x, function_caps=0x%x\n" , |
2142 | adapter->function_mode, adapter->function_caps); |
2143 | } |
2144 | |
2145 | mutex_unlock(lock: &adapter->mbox_lock); |
2146 | return status; |
2147 | } |
2148 | |
2149 | /* Uses mbox */ |
2150 | int be_cmd_reset_function(struct be_adapter *adapter) |
2151 | { |
2152 | struct be_mcc_wrb *wrb; |
2153 | struct be_cmd_req_hdr *req; |
2154 | int status; |
2155 | |
2156 | if (lancer_chip(adapter)) { |
2157 | iowrite32(SLI_PORT_CONTROL_IP_MASK, |
2158 | adapter->db + SLIPORT_CONTROL_OFFSET); |
2159 | status = lancer_wait_ready(adapter); |
2160 | if (status) |
2161 | dev_err(&adapter->pdev->dev, |
2162 | "Adapter in non recoverable error\n" ); |
2163 | return status; |
2164 | } |
2165 | |
2166 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
2167 | return -1; |
2168 | |
2169 | wrb = wrb_from_mbox(adapter); |
2170 | req = embedded_payload(wrb); |
2171 | |
2172 | be_wrb_cmd_hdr_prepare(req_hdr: req, CMD_SUBSYSTEM_COMMON, |
2173 | OPCODE_COMMON_FUNCTION_RESET, cmd_len: sizeof(*req), wrb, |
2174 | NULL); |
2175 | |
2176 | status = be_mbox_notify_wait(adapter); |
2177 | |
2178 | mutex_unlock(lock: &adapter->mbox_lock); |
2179 | return status; |
2180 | } |
2181 | |
2182 | int (struct be_adapter *adapter, u8 *, |
2183 | u32 , u16 table_size, const u8 *) |
2184 | { |
2185 | struct be_mcc_wrb *wrb; |
2186 | struct be_cmd_req_rss_config *req; |
2187 | int status; |
2188 | |
2189 | if (!(be_if_cap_flags(adapter) & BE_IF_FLAGS_RSS)) |
2190 | return 0; |
2191 | |
2192 | mutex_lock(&adapter->mcc_lock); |
2193 | |
2194 | wrb = wrb_from_mccq(adapter); |
2195 | if (!wrb) { |
2196 | status = -EBUSY; |
2197 | goto err; |
2198 | } |
2199 | req = embedded_payload(wrb); |
2200 | |
2201 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ETH, |
2202 | OPCODE_ETH_RSS_CONFIG, cmd_len: sizeof(*req), wrb, NULL); |
2203 | |
2204 | req->if_id = cpu_to_le32(adapter->if_handle); |
2205 | req->enable_rss = cpu_to_le16(rss_hash_opts); |
2206 | req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1); |
2207 | |
2208 | if (!BEx_chip(adapter)) |
2209 | req->hdr.version = 1; |
2210 | |
2211 | memcpy(req->cpu_table, rsstable, table_size); |
2212 | memcpy(req->hash, rss_hkey, RSS_HASH_KEY_LEN); |
2213 | be_dws_cpu_to_le(req->hash, sizeof(req->hash)); |
2214 | |
2215 | status = be_mcc_notify_wait(adapter); |
2216 | err: |
2217 | mutex_unlock(lock: &adapter->mcc_lock); |
2218 | return status; |
2219 | } |
2220 | |
2221 | /* Uses sync mcc */ |
2222 | int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, |
2223 | u8 bcn, u8 sts, u8 state) |
2224 | { |
2225 | struct be_mcc_wrb *wrb; |
2226 | struct be_cmd_req_enable_disable_beacon *req; |
2227 | int status; |
2228 | |
2229 | mutex_lock(&adapter->mcc_lock); |
2230 | |
2231 | wrb = wrb_from_mccq(adapter); |
2232 | if (!wrb) { |
2233 | status = -EBUSY; |
2234 | goto err; |
2235 | } |
2236 | req = embedded_payload(wrb); |
2237 | |
2238 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2239 | OPCODE_COMMON_ENABLE_DISABLE_BEACON, |
2240 | cmd_len: sizeof(*req), wrb, NULL); |
2241 | |
2242 | req->port_num = port_num; |
2243 | req->beacon_state = state; |
2244 | req->beacon_duration = bcn; |
2245 | req->status_duration = sts; |
2246 | |
2247 | status = be_mcc_notify_wait(adapter); |
2248 | |
2249 | err: |
2250 | mutex_unlock(lock: &adapter->mcc_lock); |
2251 | return status; |
2252 | } |
2253 | |
2254 | /* Uses sync mcc */ |
2255 | int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state) |
2256 | { |
2257 | struct be_mcc_wrb *wrb; |
2258 | struct be_cmd_req_get_beacon_state *req; |
2259 | int status; |
2260 | |
2261 | mutex_lock(&adapter->mcc_lock); |
2262 | |
2263 | wrb = wrb_from_mccq(adapter); |
2264 | if (!wrb) { |
2265 | status = -EBUSY; |
2266 | goto err; |
2267 | } |
2268 | req = embedded_payload(wrb); |
2269 | |
2270 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2271 | OPCODE_COMMON_GET_BEACON_STATE, cmd_len: sizeof(*req), |
2272 | wrb, NULL); |
2273 | |
2274 | req->port_num = port_num; |
2275 | |
2276 | status = be_mcc_notify_wait(adapter); |
2277 | if (!status) { |
2278 | struct be_cmd_resp_get_beacon_state *resp = |
2279 | embedded_payload(wrb); |
2280 | |
2281 | *state = resp->beacon_state; |
2282 | } |
2283 | |
2284 | err: |
2285 | mutex_unlock(lock: &adapter->mcc_lock); |
2286 | return status; |
2287 | } |
2288 | |
2289 | /* Uses sync mcc */ |
2290 | int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, |
2291 | u8 page_num, u32 off, u32 len, u8 *data) |
2292 | { |
2293 | struct be_dma_mem cmd; |
2294 | struct be_mcc_wrb *wrb; |
2295 | struct be_cmd_req_port_type *req; |
2296 | int status; |
2297 | |
2298 | if (page_num > TR_PAGE_A2) |
2299 | return -EINVAL; |
2300 | |
2301 | cmd.size = sizeof(struct be_cmd_resp_port_type); |
2302 | cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, size: cmd.size, dma_handle: &cmd.dma, |
2303 | GFP_ATOMIC); |
2304 | if (!cmd.va) { |
2305 | dev_err(&adapter->pdev->dev, "Memory allocation failed\n" ); |
2306 | return -ENOMEM; |
2307 | } |
2308 | |
2309 | mutex_lock(&adapter->mcc_lock); |
2310 | |
2311 | wrb = wrb_from_mccq(adapter); |
2312 | if (!wrb) { |
2313 | status = -EBUSY; |
2314 | goto err; |
2315 | } |
2316 | req = cmd.va; |
2317 | |
2318 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2319 | OPCODE_COMMON_READ_TRANSRECV_DATA, |
2320 | cmd_len: cmd.size, wrb, mem: &cmd); |
2321 | |
2322 | req->port = cpu_to_le32(adapter->hba_port_num); |
2323 | req->page_num = cpu_to_le32(page_num); |
2324 | status = be_mcc_notify_wait(adapter); |
2325 | if (!status && len > 0) { |
2326 | struct be_cmd_resp_port_type *resp = cmd.va; |
2327 | |
2328 | memcpy(data, resp->page_data + off, len); |
2329 | } |
2330 | err: |
2331 | mutex_unlock(lock: &adapter->mcc_lock); |
2332 | dma_free_coherent(dev: &adapter->pdev->dev, size: cmd.size, cpu_addr: cmd.va, dma_handle: cmd.dma); |
2333 | return status; |
2334 | } |
2335 | |
2336 | static int lancer_cmd_write_object(struct be_adapter *adapter, |
2337 | struct be_dma_mem *cmd, u32 data_size, |
2338 | u32 data_offset, const char *obj_name, |
2339 | u32 *data_written, u8 *change_status, |
2340 | u8 *addn_status) |
2341 | { |
2342 | struct be_mcc_wrb *wrb; |
2343 | struct lancer_cmd_req_write_object *req; |
2344 | struct lancer_cmd_resp_write_object *resp; |
2345 | void *ctxt = NULL; |
2346 | int status; |
2347 | |
2348 | mutex_lock(&adapter->mcc_lock); |
2349 | adapter->flash_status = 0; |
2350 | |
2351 | wrb = wrb_from_mccq(adapter); |
2352 | if (!wrb) { |
2353 | status = -EBUSY; |
2354 | goto err_unlock; |
2355 | } |
2356 | |
2357 | req = embedded_payload(wrb); |
2358 | |
2359 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2360 | OPCODE_COMMON_WRITE_OBJECT, |
2361 | cmd_len: sizeof(struct lancer_cmd_req_write_object), wrb, |
2362 | NULL); |
2363 | |
2364 | ctxt = &req->context; |
2365 | AMAP_SET_BITS(struct amap_lancer_write_obj_context, |
2366 | write_length, ctxt, data_size); |
2367 | |
2368 | if (data_size == 0) |
2369 | AMAP_SET_BITS(struct amap_lancer_write_obj_context, |
2370 | eof, ctxt, 1); |
2371 | else |
2372 | AMAP_SET_BITS(struct amap_lancer_write_obj_context, |
2373 | eof, ctxt, 0); |
2374 | |
2375 | be_dws_cpu_to_le(ctxt, sizeof(req->context)); |
2376 | req->write_offset = cpu_to_le32(data_offset); |
2377 | strscpy(req->object_name, obj_name, sizeof(req->object_name)); |
2378 | req->descriptor_count = cpu_to_le32(1); |
2379 | req->buf_len = cpu_to_le32(data_size); |
2380 | req->addr_low = cpu_to_le32((cmd->dma + |
2381 | sizeof(struct lancer_cmd_req_write_object)) |
2382 | & 0xFFFFFFFF); |
2383 | req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma + |
2384 | sizeof(struct lancer_cmd_req_write_object))); |
2385 | |
2386 | status = be_mcc_notify(adapter); |
2387 | if (status) |
2388 | goto err_unlock; |
2389 | |
2390 | mutex_unlock(lock: &adapter->mcc_lock); |
2391 | |
2392 | if (!wait_for_completion_timeout(x: &adapter->et_cmd_compl, |
2393 | timeout: msecs_to_jiffies(m: 60000))) |
2394 | status = -ETIMEDOUT; |
2395 | else |
2396 | status = adapter->flash_status; |
2397 | |
2398 | resp = embedded_payload(wrb); |
2399 | if (!status) { |
2400 | *data_written = le32_to_cpu(resp->actual_write_len); |
2401 | *change_status = resp->change_status; |
2402 | } else { |
2403 | *addn_status = resp->additional_status; |
2404 | } |
2405 | |
2406 | return status; |
2407 | |
2408 | err_unlock: |
2409 | mutex_unlock(lock: &adapter->mcc_lock); |
2410 | return status; |
2411 | } |
2412 | |
2413 | int be_cmd_query_cable_type(struct be_adapter *adapter) |
2414 | { |
2415 | u8 page_data[PAGE_DATA_LEN]; |
2416 | int status; |
2417 | |
2418 | status = be_cmd_read_port_transceiver_data(adapter, page_num: TR_PAGE_A0, |
2419 | off: 0, PAGE_DATA_LEN, data: page_data); |
2420 | if (!status) { |
2421 | switch (adapter->phy.interface_type) { |
2422 | case PHY_TYPE_QSFP: |
2423 | adapter->phy.cable_type = |
2424 | page_data[QSFP_PLUS_CABLE_TYPE_OFFSET]; |
2425 | break; |
2426 | case PHY_TYPE_SFP_PLUS_10GB: |
2427 | adapter->phy.cable_type = |
2428 | page_data[SFP_PLUS_CABLE_TYPE_OFFSET]; |
2429 | break; |
2430 | default: |
2431 | adapter->phy.cable_type = 0; |
2432 | break; |
2433 | } |
2434 | } |
2435 | return status; |
2436 | } |
2437 | |
2438 | int be_cmd_query_sfp_info(struct be_adapter *adapter) |
2439 | { |
2440 | u8 page_data[PAGE_DATA_LEN]; |
2441 | int status; |
2442 | |
2443 | status = be_cmd_read_port_transceiver_data(adapter, page_num: TR_PAGE_A0, |
2444 | off: 0, PAGE_DATA_LEN, data: page_data); |
2445 | if (!status) { |
2446 | strscpy(adapter->phy.vendor_name, page_data + |
2447 | SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1); |
2448 | strscpy(adapter->phy.vendor_pn, |
2449 | page_data + SFP_VENDOR_PN_OFFSET, |
2450 | SFP_VENDOR_NAME_LEN - 1); |
2451 | } |
2452 | |
2453 | return status; |
2454 | } |
2455 | |
2456 | static int lancer_cmd_delete_object(struct be_adapter *adapter, |
2457 | const char *obj_name) |
2458 | { |
2459 | struct lancer_cmd_req_delete_object *req; |
2460 | struct be_mcc_wrb *wrb; |
2461 | int status; |
2462 | |
2463 | mutex_lock(&adapter->mcc_lock); |
2464 | |
2465 | wrb = wrb_from_mccq(adapter); |
2466 | if (!wrb) { |
2467 | status = -EBUSY; |
2468 | goto err; |
2469 | } |
2470 | |
2471 | req = embedded_payload(wrb); |
2472 | |
2473 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2474 | OPCODE_COMMON_DELETE_OBJECT, |
2475 | cmd_len: sizeof(*req), wrb, NULL); |
2476 | |
2477 | strscpy(req->object_name, obj_name, sizeof(req->object_name)); |
2478 | |
2479 | status = be_mcc_notify_wait(adapter); |
2480 | err: |
2481 | mutex_unlock(lock: &adapter->mcc_lock); |
2482 | return status; |
2483 | } |
2484 | |
2485 | int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, |
2486 | u32 data_size, u32 data_offset, const char *obj_name, |
2487 | u32 *data_read, u32 *eof, u8 *addn_status) |
2488 | { |
2489 | struct be_mcc_wrb *wrb; |
2490 | struct lancer_cmd_req_read_object *req; |
2491 | struct lancer_cmd_resp_read_object *resp; |
2492 | int status; |
2493 | |
2494 | mutex_lock(&adapter->mcc_lock); |
2495 | |
2496 | wrb = wrb_from_mccq(adapter); |
2497 | if (!wrb) { |
2498 | status = -EBUSY; |
2499 | goto err_unlock; |
2500 | } |
2501 | |
2502 | req = embedded_payload(wrb); |
2503 | |
2504 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2505 | OPCODE_COMMON_READ_OBJECT, |
2506 | cmd_len: sizeof(struct lancer_cmd_req_read_object), wrb, |
2507 | NULL); |
2508 | |
2509 | req->desired_read_len = cpu_to_le32(data_size); |
2510 | req->read_offset = cpu_to_le32(data_offset); |
2511 | strcpy(p: req->object_name, q: obj_name); |
2512 | req->descriptor_count = cpu_to_le32(1); |
2513 | req->buf_len = cpu_to_le32(data_size); |
2514 | req->addr_low = cpu_to_le32((cmd->dma & 0xFFFFFFFF)); |
2515 | req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma)); |
2516 | |
2517 | status = be_mcc_notify_wait(adapter); |
2518 | |
2519 | resp = embedded_payload(wrb); |
2520 | if (!status) { |
2521 | *data_read = le32_to_cpu(resp->actual_read_len); |
2522 | *eof = le32_to_cpu(resp->eof); |
2523 | } else { |
2524 | *addn_status = resp->additional_status; |
2525 | } |
2526 | |
2527 | err_unlock: |
2528 | mutex_unlock(lock: &adapter->mcc_lock); |
2529 | return status; |
2530 | } |
2531 | |
2532 | static int be_cmd_write_flashrom(struct be_adapter *adapter, |
2533 | struct be_dma_mem *cmd, u32 flash_type, |
2534 | u32 flash_opcode, u32 img_offset, u32 buf_size) |
2535 | { |
2536 | struct be_mcc_wrb *wrb; |
2537 | struct be_cmd_write_flashrom *req; |
2538 | int status; |
2539 | |
2540 | mutex_lock(&adapter->mcc_lock); |
2541 | adapter->flash_status = 0; |
2542 | |
2543 | wrb = wrb_from_mccq(adapter); |
2544 | if (!wrb) { |
2545 | status = -EBUSY; |
2546 | goto err_unlock; |
2547 | } |
2548 | req = cmd->va; |
2549 | |
2550 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2551 | OPCODE_COMMON_WRITE_FLASHROM, cmd_len: cmd->size, wrb, |
2552 | mem: cmd); |
2553 | |
2554 | req->params.op_type = cpu_to_le32(flash_type); |
2555 | if (flash_type == OPTYPE_OFFSET_SPECIFIED) |
2556 | req->params.offset = cpu_to_le32(img_offset); |
2557 | |
2558 | req->params.op_code = cpu_to_le32(flash_opcode); |
2559 | req->params.data_buf_size = cpu_to_le32(buf_size); |
2560 | |
2561 | status = be_mcc_notify(adapter); |
2562 | if (status) |
2563 | goto err_unlock; |
2564 | |
2565 | mutex_unlock(lock: &adapter->mcc_lock); |
2566 | |
2567 | if (!wait_for_completion_timeout(x: &adapter->et_cmd_compl, |
2568 | timeout: msecs_to_jiffies(m: 40000))) |
2569 | status = -ETIMEDOUT; |
2570 | else |
2571 | status = adapter->flash_status; |
2572 | |
2573 | return status; |
2574 | |
2575 | err_unlock: |
2576 | mutex_unlock(lock: &adapter->mcc_lock); |
2577 | return status; |
2578 | } |
2579 | |
2580 | static int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, |
2581 | u16 img_optype, u32 img_offset, u32 crc_offset) |
2582 | { |
2583 | struct be_cmd_read_flash_crc *req; |
2584 | struct be_mcc_wrb *wrb; |
2585 | int status; |
2586 | |
2587 | mutex_lock(&adapter->mcc_lock); |
2588 | |
2589 | wrb = wrb_from_mccq(adapter); |
2590 | if (!wrb) { |
2591 | status = -EBUSY; |
2592 | goto err; |
2593 | } |
2594 | req = embedded_payload(wrb); |
2595 | |
2596 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
2597 | OPCODE_COMMON_READ_FLASHROM, cmd_len: sizeof(*req), |
2598 | wrb, NULL); |
2599 | |
2600 | req->params.op_type = cpu_to_le32(img_optype); |
2601 | if (img_optype == OPTYPE_OFFSET_SPECIFIED) |
2602 | req->params.offset = cpu_to_le32(img_offset + crc_offset); |
2603 | else |
2604 | req->params.offset = cpu_to_le32(crc_offset); |
2605 | |
2606 | req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); |
2607 | req->params.data_buf_size = cpu_to_le32(0x4); |
2608 | |
2609 | status = be_mcc_notify_wait(adapter); |
2610 | if (!status) |
2611 | memcpy(flashed_crc, req->crc, 4); |
2612 | |
2613 | err: |
2614 | mutex_unlock(lock: &adapter->mcc_lock); |
2615 | return status; |
2616 | } |
2617 | |
2618 | static char flash_cookie[2][16] = {"*** SE FLAS" , "H DIRECTORY *** " }; |
2619 | |
2620 | static bool phy_flashing_required(struct be_adapter *adapter) |
2621 | { |
2622 | return (adapter->phy.phy_type == PHY_TYPE_TN_8022 && |
2623 | adapter->phy.interface_type == PHY_TYPE_BASET_10GB); |
2624 | } |
2625 | |
2626 | static bool is_comp_in_ufi(struct be_adapter *adapter, |
2627 | struct flash_section_info *fsec, int type) |
2628 | { |
2629 | int i = 0, img_type = 0; |
2630 | struct flash_section_info_g2 *fsec_g2 = NULL; |
2631 | |
2632 | if (BE2_chip(adapter)) |
2633 | fsec_g2 = (struct flash_section_info_g2 *)fsec; |
2634 | |
2635 | for (i = 0; i < MAX_FLASH_COMP; i++) { |
2636 | if (fsec_g2) |
2637 | img_type = le32_to_cpu(fsec_g2->fsec_entry[i].type); |
2638 | else |
2639 | img_type = le32_to_cpu(fsec->fsec_entry[i].type); |
2640 | |
2641 | if (img_type == type) |
2642 | return true; |
2643 | } |
2644 | return false; |
2645 | } |
2646 | |
2647 | static struct flash_section_info *get_fsec_info(struct be_adapter *adapter, |
2648 | int , |
2649 | const struct firmware *fw) |
2650 | { |
2651 | struct flash_section_info *fsec = NULL; |
2652 | const u8 *p = fw->data; |
2653 | |
2654 | p += header_size; |
2655 | while (p < (fw->data + fw->size)) { |
2656 | fsec = (struct flash_section_info *)p; |
2657 | if (!memcmp(p: flash_cookie, q: fsec->cookie, size: sizeof(flash_cookie))) |
2658 | return fsec; |
2659 | p += 32; |
2660 | } |
2661 | return NULL; |
2662 | } |
2663 | |
2664 | static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p, |
2665 | u32 img_offset, u32 img_size, int hdr_size, |
2666 | u16 img_optype, bool *crc_match) |
2667 | { |
2668 | u32 crc_offset; |
2669 | int status; |
2670 | u8 crc[4]; |
2671 | |
2672 | status = be_cmd_get_flash_crc(adapter, flashed_crc: crc, img_optype, img_offset, |
2673 | crc_offset: img_size - 4); |
2674 | if (status) |
2675 | return status; |
2676 | |
2677 | crc_offset = hdr_size + img_offset + img_size - 4; |
2678 | |
2679 | /* Skip flashing, if crc of flashed region matches */ |
2680 | if (!memcmp(p: crc, q: p + crc_offset, size: 4)) |
2681 | *crc_match = true; |
2682 | else |
2683 | *crc_match = false; |
2684 | |
2685 | return status; |
2686 | } |
2687 | |
2688 | static int be_flash(struct be_adapter *adapter, const u8 *img, |
2689 | struct be_dma_mem *flash_cmd, int optype, int img_size, |
2690 | u32 img_offset) |
2691 | { |
2692 | u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0; |
2693 | struct be_cmd_write_flashrom *req = flash_cmd->va; |
2694 | int status; |
2695 | |
2696 | while (total_bytes) { |
2697 | num_bytes = min_t(u32, 32 * 1024, total_bytes); |
2698 | |
2699 | total_bytes -= num_bytes; |
2700 | |
2701 | if (!total_bytes) { |
2702 | if (optype == OPTYPE_PHY_FW) |
2703 | flash_op = FLASHROM_OPER_PHY_FLASH; |
2704 | else |
2705 | flash_op = FLASHROM_OPER_FLASH; |
2706 | } else { |
2707 | if (optype == OPTYPE_PHY_FW) |
2708 | flash_op = FLASHROM_OPER_PHY_SAVE; |
2709 | else |
2710 | flash_op = FLASHROM_OPER_SAVE; |
2711 | } |
2712 | |
2713 | memcpy(req->data_buf, img, num_bytes); |
2714 | img += num_bytes; |
2715 | status = be_cmd_write_flashrom(adapter, cmd: flash_cmd, flash_type: optype, |
2716 | flash_opcode: flash_op, img_offset: img_offset + |
2717 | bytes_sent, buf_size: num_bytes); |
2718 | if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST && |
2719 | optype == OPTYPE_PHY_FW) |
2720 | break; |
2721 | else if (status) |
2722 | return status; |
2723 | |
2724 | bytes_sent += num_bytes; |
2725 | } |
2726 | return 0; |
2727 | } |
2728 | |
2729 | #define NCSI_UPDATE_LOG "NCSI section update is not supported in FW ver %s\n" |
2730 | static bool be_fw_ncsi_supported(char *ver) |
2731 | { |
2732 | int v1[4] = {3, 102, 148, 0}; /* Min ver that supports NCSI FW */ |
2733 | int v2[4]; |
2734 | int i; |
2735 | |
2736 | if (sscanf(ver, "%d.%d.%d.%d" , &v2[0], &v2[1], &v2[2], &v2[3]) != 4) |
2737 | return false; |
2738 | |
2739 | for (i = 0; i < 4; i++) { |
2740 | if (v1[i] < v2[i]) |
2741 | return true; |
2742 | else if (v1[i] > v2[i]) |
2743 | return false; |
2744 | } |
2745 | |
2746 | return true; |
2747 | } |
2748 | |
2749 | /* For BE2, BE3 and BE3-R */ |
2750 | static int be_flash_BEx(struct be_adapter *adapter, |
2751 | const struct firmware *fw, |
2752 | struct be_dma_mem *flash_cmd, int num_of_images) |
2753 | { |
2754 | int img_hdrs_size = (num_of_images * sizeof(struct image_hdr)); |
2755 | struct device *dev = &adapter->pdev->dev; |
2756 | struct flash_section_info *fsec = NULL; |
2757 | int status, i, filehdr_size, num_comp; |
2758 | const struct flash_comp *pflashcomp; |
2759 | bool crc_match; |
2760 | const u8 *p; |
2761 | |
2762 | static const struct flash_comp gen3_flash_types[] = { |
2763 | { BE3_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, |
2764 | BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, |
2765 | { BE3_REDBOOT_START, OPTYPE_REDBOOT, |
2766 | BE3_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, |
2767 | { BE3_ISCSI_BIOS_START, OPTYPE_BIOS, |
2768 | BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, |
2769 | { BE3_PXE_BIOS_START, OPTYPE_PXE_BIOS, |
2770 | BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, |
2771 | { BE3_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, |
2772 | BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, |
2773 | { BE3_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, |
2774 | BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, |
2775 | { BE3_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, |
2776 | BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, |
2777 | { BE3_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, |
2778 | BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE}, |
2779 | { BE3_NCSI_START, OPTYPE_NCSI_FW, |
2780 | BE3_NCSI_COMP_MAX_SIZE, IMAGE_NCSI}, |
2781 | { BE3_PHY_FW_START, OPTYPE_PHY_FW, |
2782 | BE3_PHY_FW_COMP_MAX_SIZE, IMAGE_FIRMWARE_PHY} |
2783 | }; |
2784 | |
2785 | static const struct flash_comp gen2_flash_types[] = { |
2786 | { BE2_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, |
2787 | BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, |
2788 | { BE2_REDBOOT_START, OPTYPE_REDBOOT, |
2789 | BE2_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, |
2790 | { BE2_ISCSI_BIOS_START, OPTYPE_BIOS, |
2791 | BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, |
2792 | { BE2_PXE_BIOS_START, OPTYPE_PXE_BIOS, |
2793 | BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, |
2794 | { BE2_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, |
2795 | BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, |
2796 | { BE2_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, |
2797 | BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, |
2798 | { BE2_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, |
2799 | BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, |
2800 | { BE2_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, |
2801 | BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE} |
2802 | }; |
2803 | |
2804 | if (BE3_chip(adapter)) { |
2805 | pflashcomp = gen3_flash_types; |
2806 | filehdr_size = sizeof(struct flash_file_hdr_g3); |
2807 | num_comp = ARRAY_SIZE(gen3_flash_types); |
2808 | } else { |
2809 | pflashcomp = gen2_flash_types; |
2810 | filehdr_size = sizeof(struct flash_file_hdr_g2); |
2811 | num_comp = ARRAY_SIZE(gen2_flash_types); |
2812 | img_hdrs_size = 0; |
2813 | } |
2814 | |
2815 | /* Get flash section info*/ |
2816 | fsec = get_fsec_info(adapter, header_size: filehdr_size + img_hdrs_size, fw); |
2817 | if (!fsec) { |
2818 | dev_err(dev, "Invalid Cookie. FW image may be corrupted\n" ); |
2819 | return -1; |
2820 | } |
2821 | for (i = 0; i < num_comp; i++) { |
2822 | if (!is_comp_in_ufi(adapter, fsec, type: pflashcomp[i].img_type)) |
2823 | continue; |
2824 | |
2825 | if ((pflashcomp[i].optype == OPTYPE_NCSI_FW) && |
2826 | !be_fw_ncsi_supported(ver: adapter->fw_ver)) { |
2827 | dev_info(dev, NCSI_UPDATE_LOG, adapter->fw_ver); |
2828 | continue; |
2829 | } |
2830 | |
2831 | if (pflashcomp[i].optype == OPTYPE_PHY_FW && |
2832 | !phy_flashing_required(adapter)) |
2833 | continue; |
2834 | |
2835 | if (pflashcomp[i].optype == OPTYPE_REDBOOT) { |
2836 | status = be_check_flash_crc(adapter, p: fw->data, |
2837 | img_offset: pflashcomp[i].offset, |
2838 | img_size: pflashcomp[i].size, |
2839 | hdr_size: filehdr_size + |
2840 | img_hdrs_size, |
2841 | img_optype: OPTYPE_REDBOOT, crc_match: &crc_match); |
2842 | if (status) { |
2843 | dev_err(dev, |
2844 | "Could not get CRC for 0x%x region\n" , |
2845 | pflashcomp[i].optype); |
2846 | continue; |
2847 | } |
2848 | |
2849 | if (crc_match) |
2850 | continue; |
2851 | } |
2852 | |
2853 | p = fw->data + filehdr_size + pflashcomp[i].offset + |
2854 | img_hdrs_size; |
2855 | if (p + pflashcomp[i].size > fw->data + fw->size) |
2856 | return -1; |
2857 | |
2858 | status = be_flash(adapter, img: p, flash_cmd, optype: pflashcomp[i].optype, |
2859 | img_size: pflashcomp[i].size, img_offset: 0); |
2860 | if (status) { |
2861 | dev_err(dev, "Flashing section type 0x%x failed\n" , |
2862 | pflashcomp[i].img_type); |
2863 | return status; |
2864 | } |
2865 | } |
2866 | return 0; |
2867 | } |
2868 | |
2869 | static u16 be_get_img_optype(struct flash_section_entry fsec_entry) |
2870 | { |
2871 | u32 img_type = le32_to_cpu(fsec_entry.type); |
2872 | u16 img_optype = le16_to_cpu(fsec_entry.optype); |
2873 | |
2874 | if (img_optype != 0xFFFF) |
2875 | return img_optype; |
2876 | |
2877 | switch (img_type) { |
2878 | case IMAGE_FIRMWARE_ISCSI: |
2879 | img_optype = OPTYPE_ISCSI_ACTIVE; |
2880 | break; |
2881 | case IMAGE_BOOT_CODE: |
2882 | img_optype = OPTYPE_REDBOOT; |
2883 | break; |
2884 | case IMAGE_OPTION_ROM_ISCSI: |
2885 | img_optype = OPTYPE_BIOS; |
2886 | break; |
2887 | case IMAGE_OPTION_ROM_PXE: |
2888 | img_optype = OPTYPE_PXE_BIOS; |
2889 | break; |
2890 | case IMAGE_OPTION_ROM_FCOE: |
2891 | img_optype = OPTYPE_FCOE_BIOS; |
2892 | break; |
2893 | case IMAGE_FIRMWARE_BACKUP_ISCSI: |
2894 | img_optype = OPTYPE_ISCSI_BACKUP; |
2895 | break; |
2896 | case IMAGE_NCSI: |
2897 | img_optype = OPTYPE_NCSI_FW; |
2898 | break; |
2899 | case IMAGE_FLASHISM_JUMPVECTOR: |
2900 | img_optype = OPTYPE_FLASHISM_JUMPVECTOR; |
2901 | break; |
2902 | case IMAGE_FIRMWARE_PHY: |
2903 | img_optype = OPTYPE_SH_PHY_FW; |
2904 | break; |
2905 | case IMAGE_REDBOOT_DIR: |
2906 | img_optype = OPTYPE_REDBOOT_DIR; |
2907 | break; |
2908 | case IMAGE_REDBOOT_CONFIG: |
2909 | img_optype = OPTYPE_REDBOOT_CONFIG; |
2910 | break; |
2911 | case IMAGE_UFI_DIR: |
2912 | img_optype = OPTYPE_UFI_DIR; |
2913 | break; |
2914 | default: |
2915 | break; |
2916 | } |
2917 | |
2918 | return img_optype; |
2919 | } |
2920 | |
2921 | static int be_flash_skyhawk(struct be_adapter *adapter, |
2922 | const struct firmware *fw, |
2923 | struct be_dma_mem *flash_cmd, int num_of_images) |
2924 | { |
2925 | int img_hdrs_size = num_of_images * sizeof(struct image_hdr); |
2926 | bool crc_match, old_fw_img, flash_offset_support = true; |
2927 | struct device *dev = &adapter->pdev->dev; |
2928 | struct flash_section_info *fsec = NULL; |
2929 | u32 img_offset, img_size, img_type; |
2930 | u16 img_optype, flash_optype; |
2931 | int status, i, filehdr_size; |
2932 | const u8 *p; |
2933 | |
2934 | filehdr_size = sizeof(struct flash_file_hdr_g3); |
2935 | fsec = get_fsec_info(adapter, header_size: filehdr_size + img_hdrs_size, fw); |
2936 | if (!fsec) { |
2937 | dev_err(dev, "Invalid Cookie. FW image may be corrupted\n" ); |
2938 | return -EINVAL; |
2939 | } |
2940 | |
2941 | retry_flash: |
2942 | for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) { |
2943 | img_offset = le32_to_cpu(fsec->fsec_entry[i].offset); |
2944 | img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size); |
2945 | img_type = le32_to_cpu(fsec->fsec_entry[i].type); |
2946 | img_optype = be_get_img_optype(fsec_entry: fsec->fsec_entry[i]); |
2947 | old_fw_img = fsec->fsec_entry[i].optype == 0xFFFF; |
2948 | |
2949 | if (img_optype == 0xFFFF) |
2950 | continue; |
2951 | |
2952 | if (flash_offset_support) |
2953 | flash_optype = OPTYPE_OFFSET_SPECIFIED; |
2954 | else |
2955 | flash_optype = img_optype; |
2956 | |
2957 | /* Don't bother verifying CRC if an old FW image is being |
2958 | * flashed |
2959 | */ |
2960 | if (old_fw_img) |
2961 | goto flash; |
2962 | |
2963 | status = be_check_flash_crc(adapter, p: fw->data, img_offset, |
2964 | img_size, hdr_size: filehdr_size + |
2965 | img_hdrs_size, img_optype: flash_optype, |
2966 | crc_match: &crc_match); |
2967 | if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST || |
2968 | base_status(status) == MCC_STATUS_ILLEGAL_FIELD) { |
2969 | /* The current FW image on the card does not support |
2970 | * OFFSET based flashing. Retry using older mechanism |
2971 | * of OPTYPE based flashing |
2972 | */ |
2973 | if (flash_optype == OPTYPE_OFFSET_SPECIFIED) { |
2974 | flash_offset_support = false; |
2975 | goto retry_flash; |
2976 | } |
2977 | |
2978 | /* The current FW image on the card does not recognize |
2979 | * the new FLASH op_type. The FW download is partially |
2980 | * complete. Reboot the server now to enable FW image |
2981 | * to recognize the new FLASH op_type. To complete the |
2982 | * remaining process, download the same FW again after |
2983 | * the reboot. |
2984 | */ |
2985 | dev_err(dev, "Flash incomplete. Reset the server\n" ); |
2986 | dev_err(dev, "Download FW image again after reset\n" ); |
2987 | return -EAGAIN; |
2988 | } else if (status) { |
2989 | dev_err(dev, "Could not get CRC for 0x%x region\n" , |
2990 | img_optype); |
2991 | return -EFAULT; |
2992 | } |
2993 | |
2994 | if (crc_match) |
2995 | continue; |
2996 | |
2997 | flash: |
2998 | p = fw->data + filehdr_size + img_offset + img_hdrs_size; |
2999 | if (p + img_size > fw->data + fw->size) |
3000 | return -1; |
3001 | |
3002 | status = be_flash(adapter, img: p, flash_cmd, optype: flash_optype, img_size, |
3003 | img_offset); |
3004 | |
3005 | /* The current FW image on the card does not support OFFSET |
3006 | * based flashing. Retry using older mechanism of OPTYPE based |
3007 | * flashing |
3008 | */ |
3009 | if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD && |
3010 | flash_optype == OPTYPE_OFFSET_SPECIFIED) { |
3011 | flash_offset_support = false; |
3012 | goto retry_flash; |
3013 | } |
3014 | |
3015 | /* For old FW images ignore ILLEGAL_FIELD error or errors on |
3016 | * UFI_DIR region |
3017 | */ |
3018 | if (old_fw_img && |
3019 | (base_status(status) == MCC_STATUS_ILLEGAL_FIELD || |
3020 | (img_optype == OPTYPE_UFI_DIR && |
3021 | base_status(status) == MCC_STATUS_FAILED))) { |
3022 | continue; |
3023 | } else if (status) { |
3024 | dev_err(dev, "Flashing section type 0x%x failed\n" , |
3025 | img_type); |
3026 | |
3027 | switch (addl_status(status)) { |
3028 | case MCC_ADDL_STATUS_MISSING_SIGNATURE: |
3029 | dev_err(dev, |
3030 | "Digital signature missing in FW\n" ); |
3031 | return -EINVAL; |
3032 | case MCC_ADDL_STATUS_INVALID_SIGNATURE: |
3033 | dev_err(dev, |
3034 | "Invalid digital signature in FW\n" ); |
3035 | return -EINVAL; |
3036 | default: |
3037 | return -EFAULT; |
3038 | } |
3039 | } |
3040 | } |
3041 | return 0; |
3042 | } |
3043 | |
3044 | int lancer_fw_download(struct be_adapter *adapter, |
3045 | const struct firmware *fw) |
3046 | { |
3047 | struct device *dev = &adapter->pdev->dev; |
3048 | struct be_dma_mem flash_cmd; |
3049 | const u8 *data_ptr = NULL; |
3050 | u8 *dest_image_ptr = NULL; |
3051 | size_t image_size = 0; |
3052 | u32 chunk_size = 0; |
3053 | u32 data_written = 0; |
3054 | u32 offset = 0; |
3055 | int status = 0; |
3056 | u8 add_status = 0; |
3057 | u8 change_status; |
3058 | |
3059 | if (!IS_ALIGNED(fw->size, sizeof(u32))) { |
3060 | dev_err(dev, "FW image size should be multiple of 4\n" ); |
3061 | return -EINVAL; |
3062 | } |
3063 | |
3064 | flash_cmd.size = sizeof(struct lancer_cmd_req_write_object) |
3065 | + LANCER_FW_DOWNLOAD_CHUNK; |
3066 | flash_cmd.va = dma_alloc_coherent(dev, size: flash_cmd.size, dma_handle: &flash_cmd.dma, |
3067 | GFP_KERNEL); |
3068 | if (!flash_cmd.va) |
3069 | return -ENOMEM; |
3070 | |
3071 | dest_image_ptr = flash_cmd.va + |
3072 | sizeof(struct lancer_cmd_req_write_object); |
3073 | image_size = fw->size; |
3074 | data_ptr = fw->data; |
3075 | |
3076 | while (image_size) { |
3077 | chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK); |
3078 | |
3079 | /* Copy the image chunk content. */ |
3080 | memcpy(dest_image_ptr, data_ptr, chunk_size); |
3081 | |
3082 | status = lancer_cmd_write_object(adapter, cmd: &flash_cmd, |
3083 | data_size: chunk_size, data_offset: offset, |
3084 | LANCER_FW_DOWNLOAD_LOCATION, |
3085 | data_written: &data_written, change_status: &change_status, |
3086 | addn_status: &add_status); |
3087 | if (status) |
3088 | break; |
3089 | |
3090 | offset += data_written; |
3091 | data_ptr += data_written; |
3092 | image_size -= data_written; |
3093 | } |
3094 | |
3095 | if (!status) { |
3096 | /* Commit the FW written */ |
3097 | status = lancer_cmd_write_object(adapter, cmd: &flash_cmd, |
3098 | data_size: 0, data_offset: offset, |
3099 | LANCER_FW_DOWNLOAD_LOCATION, |
3100 | data_written: &data_written, change_status: &change_status, |
3101 | addn_status: &add_status); |
3102 | } |
3103 | |
3104 | dma_free_coherent(dev, size: flash_cmd.size, cpu_addr: flash_cmd.va, dma_handle: flash_cmd.dma); |
3105 | if (status) { |
3106 | dev_err(dev, "Firmware load error\n" ); |
3107 | return be_cmd_status(status); |
3108 | } |
3109 | |
3110 | dev_info(dev, "Firmware flashed successfully\n" ); |
3111 | |
3112 | if (change_status == LANCER_FW_RESET_NEEDED) { |
3113 | dev_info(dev, "Resetting adapter to activate new FW\n" ); |
3114 | status = lancer_physdev_ctrl(adapter, |
3115 | PHYSDEV_CONTROL_FW_RESET_MASK); |
3116 | if (status) { |
3117 | dev_err(dev, "Adapter busy, could not reset FW\n" ); |
3118 | dev_err(dev, "Reboot server to activate new FW\n" ); |
3119 | } |
3120 | } else if (change_status != LANCER_NO_RESET_NEEDED) { |
3121 | dev_info(dev, "Reboot server to activate new FW\n" ); |
3122 | } |
3123 | |
3124 | return 0; |
3125 | } |
3126 | |
3127 | /* Check if the flash image file is compatible with the adapter that |
3128 | * is being flashed. |
3129 | */ |
3130 | static bool be_check_ufi_compatibility(struct be_adapter *adapter, |
3131 | struct flash_file_hdr_g3 *fhdr) |
3132 | { |
3133 | if (!fhdr) { |
3134 | dev_err(&adapter->pdev->dev, "Invalid FW UFI file" ); |
3135 | return false; |
3136 | } |
3137 | |
3138 | /* First letter of the build version is used to identify |
3139 | * which chip this image file is meant for. |
3140 | */ |
3141 | switch (fhdr->build[0]) { |
3142 | case BLD_STR_UFI_TYPE_SH: |
3143 | if (!skyhawk_chip(adapter)) |
3144 | return false; |
3145 | break; |
3146 | case BLD_STR_UFI_TYPE_BE3: |
3147 | if (!BE3_chip(adapter)) |
3148 | return false; |
3149 | break; |
3150 | case BLD_STR_UFI_TYPE_BE2: |
3151 | if (!BE2_chip(adapter)) |
3152 | return false; |
3153 | break; |
3154 | default: |
3155 | return false; |
3156 | } |
3157 | |
3158 | /* In BE3 FW images the "asic_type_rev" field doesn't track the |
3159 | * asic_rev of the chips it is compatible with. |
3160 | * When asic_type_rev is 0 the image is compatible only with |
3161 | * pre-BE3-R chips (asic_rev < 0x10) |
3162 | */ |
3163 | if (BEx_chip(adapter) && fhdr->asic_type_rev == 0) |
3164 | return adapter->asic_rev < 0x10; |
3165 | else |
3166 | return (fhdr->asic_type_rev >= adapter->asic_rev); |
3167 | } |
3168 | |
3169 | int be_fw_download(struct be_adapter *adapter, const struct firmware *fw) |
3170 | { |
3171 | struct device *dev = &adapter->pdev->dev; |
3172 | struct flash_file_hdr_g3 *fhdr3; |
3173 | struct image_hdr *img_hdr_ptr; |
3174 | int status = 0, i, num_imgs; |
3175 | struct be_dma_mem flash_cmd; |
3176 | |
3177 | fhdr3 = (struct flash_file_hdr_g3 *)fw->data; |
3178 | if (!be_check_ufi_compatibility(adapter, fhdr: fhdr3)) { |
3179 | dev_err(dev, "Flash image is not compatible with adapter\n" ); |
3180 | return -EINVAL; |
3181 | } |
3182 | |
3183 | flash_cmd.size = sizeof(struct be_cmd_write_flashrom); |
3184 | flash_cmd.va = dma_alloc_coherent(dev, size: flash_cmd.size, dma_handle: &flash_cmd.dma, |
3185 | GFP_KERNEL); |
3186 | if (!flash_cmd.va) |
3187 | return -ENOMEM; |
3188 | |
3189 | num_imgs = le32_to_cpu(fhdr3->num_imgs); |
3190 | for (i = 0; i < num_imgs; i++) { |
3191 | img_hdr_ptr = (struct image_hdr *)(fw->data + |
3192 | (sizeof(struct flash_file_hdr_g3) + |
3193 | i * sizeof(struct image_hdr))); |
3194 | if (!BE2_chip(adapter) && |
3195 | le32_to_cpu(img_hdr_ptr->imageid) != 1) |
3196 | continue; |
3197 | |
3198 | if (skyhawk_chip(adapter)) |
3199 | status = be_flash_skyhawk(adapter, fw, flash_cmd: &flash_cmd, |
3200 | num_of_images: num_imgs); |
3201 | else |
3202 | status = be_flash_BEx(adapter, fw, flash_cmd: &flash_cmd, |
3203 | num_of_images: num_imgs); |
3204 | } |
3205 | |
3206 | dma_free_coherent(dev, size: flash_cmd.size, cpu_addr: flash_cmd.va, dma_handle: flash_cmd.dma); |
3207 | if (!status) |
3208 | dev_info(dev, "Firmware flashed successfully\n" ); |
3209 | |
3210 | return status; |
3211 | } |
3212 | |
3213 | int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, |
3214 | struct be_dma_mem *nonemb_cmd) |
3215 | { |
3216 | struct be_mcc_wrb *wrb; |
3217 | struct be_cmd_req_acpi_wol_magic_config *req; |
3218 | int status; |
3219 | |
3220 | mutex_lock(&adapter->mcc_lock); |
3221 | |
3222 | wrb = wrb_from_mccq(adapter); |
3223 | if (!wrb) { |
3224 | status = -EBUSY; |
3225 | goto err; |
3226 | } |
3227 | req = nonemb_cmd->va; |
3228 | |
3229 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ETH, |
3230 | OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, cmd_len: sizeof(*req), |
3231 | wrb, mem: nonemb_cmd); |
3232 | memcpy(req->magic_mac, mac, ETH_ALEN); |
3233 | |
3234 | status = be_mcc_notify_wait(adapter); |
3235 | |
3236 | err: |
3237 | mutex_unlock(lock: &adapter->mcc_lock); |
3238 | return status; |
3239 | } |
3240 | |
3241 | int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, |
3242 | u8 loopback_type, u8 enable) |
3243 | { |
3244 | struct be_mcc_wrb *wrb; |
3245 | struct be_cmd_req_set_lmode *req; |
3246 | int status; |
3247 | |
3248 | if (!be_cmd_allowed(adapter, OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, |
3249 | CMD_SUBSYSTEM_LOWLEVEL)) |
3250 | return -EPERM; |
3251 | |
3252 | mutex_lock(&adapter->mcc_lock); |
3253 | |
3254 | wrb = wrb_from_mccq(adapter); |
3255 | if (!wrb) { |
3256 | status = -EBUSY; |
3257 | goto err_unlock; |
3258 | } |
3259 | |
3260 | req = embedded_payload(wrb); |
3261 | |
3262 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_LOWLEVEL, |
3263 | OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, cmd_len: sizeof(*req), |
3264 | wrb, NULL); |
3265 | |
3266 | req->src_port = port_num; |
3267 | req->dest_port = port_num; |
3268 | req->loopback_type = loopback_type; |
3269 | req->loopback_state = enable; |
3270 | |
3271 | status = be_mcc_notify(adapter); |
3272 | if (status) |
3273 | goto err_unlock; |
3274 | |
3275 | mutex_unlock(lock: &adapter->mcc_lock); |
3276 | |
3277 | if (!wait_for_completion_timeout(x: &adapter->et_cmd_compl, |
3278 | timeout: msecs_to_jiffies(SET_LB_MODE_TIMEOUT))) |
3279 | status = -ETIMEDOUT; |
3280 | |
3281 | return status; |
3282 | |
3283 | err_unlock: |
3284 | mutex_unlock(lock: &adapter->mcc_lock); |
3285 | return status; |
3286 | } |
3287 | |
3288 | int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, |
3289 | u32 loopback_type, u32 pkt_size, u32 num_pkts, |
3290 | u64 pattern) |
3291 | { |
3292 | struct be_mcc_wrb *wrb; |
3293 | struct be_cmd_req_loopback_test *req; |
3294 | struct be_cmd_resp_loopback_test *resp; |
3295 | int status; |
3296 | |
3297 | if (!be_cmd_allowed(adapter, OPCODE_LOWLEVEL_LOOPBACK_TEST, |
3298 | CMD_SUBSYSTEM_LOWLEVEL)) |
3299 | return -EPERM; |
3300 | |
3301 | mutex_lock(&adapter->mcc_lock); |
3302 | |
3303 | wrb = wrb_from_mccq(adapter); |
3304 | if (!wrb) { |
3305 | status = -EBUSY; |
3306 | goto err; |
3307 | } |
3308 | |
3309 | req = embedded_payload(wrb); |
3310 | |
3311 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_LOWLEVEL, |
3312 | OPCODE_LOWLEVEL_LOOPBACK_TEST, cmd_len: sizeof(*req), wrb, |
3313 | NULL); |
3314 | |
3315 | req->hdr.timeout = cpu_to_le32(15); |
3316 | req->pattern = cpu_to_le64(pattern); |
3317 | req->src_port = cpu_to_le32(port_num); |
3318 | req->dest_port = cpu_to_le32(port_num); |
3319 | req->pkt_size = cpu_to_le32(pkt_size); |
3320 | req->num_pkts = cpu_to_le32(num_pkts); |
3321 | req->loopback_type = cpu_to_le32(loopback_type); |
3322 | |
3323 | status = be_mcc_notify(adapter); |
3324 | if (status) |
3325 | goto err; |
3326 | |
3327 | mutex_unlock(lock: &adapter->mcc_lock); |
3328 | |
3329 | wait_for_completion(&adapter->et_cmd_compl); |
3330 | resp = embedded_payload(wrb); |
3331 | status = le32_to_cpu(resp->status); |
3332 | |
3333 | return status; |
3334 | err: |
3335 | mutex_unlock(lock: &adapter->mcc_lock); |
3336 | return status; |
3337 | } |
3338 | |
3339 | int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, |
3340 | u32 byte_cnt, struct be_dma_mem *cmd) |
3341 | { |
3342 | struct be_mcc_wrb *wrb; |
3343 | struct be_cmd_req_ddrdma_test *req; |
3344 | int status; |
3345 | int i, j = 0; |
3346 | |
3347 | if (!be_cmd_allowed(adapter, OPCODE_LOWLEVEL_HOST_DDR_DMA, |
3348 | CMD_SUBSYSTEM_LOWLEVEL)) |
3349 | return -EPERM; |
3350 | |
3351 | mutex_lock(&adapter->mcc_lock); |
3352 | |
3353 | wrb = wrb_from_mccq(adapter); |
3354 | if (!wrb) { |
3355 | status = -EBUSY; |
3356 | goto err; |
3357 | } |
3358 | req = cmd->va; |
3359 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_LOWLEVEL, |
3360 | OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd_len: cmd->size, wrb, |
3361 | mem: cmd); |
3362 | |
3363 | req->pattern = cpu_to_le64(pattern); |
3364 | req->byte_count = cpu_to_le32(byte_cnt); |
3365 | for (i = 0; i < byte_cnt; i++) { |
3366 | req->snd_buff[i] = (u8)(pattern >> (j * 8)); |
3367 | j++; |
3368 | if (j > 7) |
3369 | j = 0; |
3370 | } |
3371 | |
3372 | status = be_mcc_notify_wait(adapter); |
3373 | |
3374 | if (!status) { |
3375 | struct be_cmd_resp_ddrdma_test *resp; |
3376 | |
3377 | resp = cmd->va; |
3378 | if ((memcmp(p: resp->rcv_buff, q: req->snd_buff, size: byte_cnt) != 0) || |
3379 | resp->snd_err) { |
3380 | status = -1; |
3381 | } |
3382 | } |
3383 | |
3384 | err: |
3385 | mutex_unlock(lock: &adapter->mcc_lock); |
3386 | return status; |
3387 | } |
3388 | |
3389 | int be_cmd_get_seeprom_data(struct be_adapter *adapter, |
3390 | struct be_dma_mem *nonemb_cmd) |
3391 | { |
3392 | struct be_mcc_wrb *wrb; |
3393 | struct be_cmd_req_seeprom_read *req; |
3394 | int status; |
3395 | |
3396 | mutex_lock(&adapter->mcc_lock); |
3397 | |
3398 | wrb = wrb_from_mccq(adapter); |
3399 | if (!wrb) { |
3400 | status = -EBUSY; |
3401 | goto err; |
3402 | } |
3403 | req = nonemb_cmd->va; |
3404 | |
3405 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3406 | OPCODE_COMMON_SEEPROM_READ, cmd_len: sizeof(*req), wrb, |
3407 | mem: nonemb_cmd); |
3408 | |
3409 | status = be_mcc_notify_wait(adapter); |
3410 | |
3411 | err: |
3412 | mutex_unlock(lock: &adapter->mcc_lock); |
3413 | return status; |
3414 | } |
3415 | |
3416 | int be_cmd_get_phy_info(struct be_adapter *adapter) |
3417 | { |
3418 | struct be_mcc_wrb *wrb; |
3419 | struct be_cmd_req_get_phy_info *req; |
3420 | struct be_dma_mem cmd; |
3421 | int status; |
3422 | |
3423 | if (!be_cmd_allowed(adapter, OPCODE_COMMON_GET_PHY_DETAILS, |
3424 | CMD_SUBSYSTEM_COMMON)) |
3425 | return -EPERM; |
3426 | |
3427 | mutex_lock(&adapter->mcc_lock); |
3428 | |
3429 | wrb = wrb_from_mccq(adapter); |
3430 | if (!wrb) { |
3431 | status = -EBUSY; |
3432 | goto err; |
3433 | } |
3434 | cmd.size = sizeof(struct be_cmd_req_get_phy_info); |
3435 | cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, size: cmd.size, dma_handle: &cmd.dma, |
3436 | GFP_ATOMIC); |
3437 | if (!cmd.va) { |
3438 | dev_err(&adapter->pdev->dev, "Memory alloc failure\n" ); |
3439 | status = -ENOMEM; |
3440 | goto err; |
3441 | } |
3442 | |
3443 | req = cmd.va; |
3444 | |
3445 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3446 | OPCODE_COMMON_GET_PHY_DETAILS, cmd_len: sizeof(*req), |
3447 | wrb, mem: &cmd); |
3448 | |
3449 | status = be_mcc_notify_wait(adapter); |
3450 | if (!status) { |
3451 | struct be_phy_info *resp_phy_info = |
3452 | cmd.va + sizeof(struct be_cmd_req_hdr); |
3453 | |
3454 | adapter->phy.phy_type = le16_to_cpu(resp_phy_info->phy_type); |
3455 | adapter->phy.interface_type = |
3456 | le16_to_cpu(resp_phy_info->interface_type); |
3457 | adapter->phy.auto_speeds_supported = |
3458 | le16_to_cpu(resp_phy_info->auto_speeds_supported); |
3459 | adapter->phy.fixed_speeds_supported = |
3460 | le16_to_cpu(resp_phy_info->fixed_speeds_supported); |
3461 | adapter->phy.misc_params = |
3462 | le32_to_cpu(resp_phy_info->misc_params); |
3463 | |
3464 | if (BE2_chip(adapter)) { |
3465 | adapter->phy.fixed_speeds_supported = |
3466 | BE_SUPPORTED_SPEED_10GBPS | |
3467 | BE_SUPPORTED_SPEED_1GBPS; |
3468 | } |
3469 | } |
3470 | dma_free_coherent(dev: &adapter->pdev->dev, size: cmd.size, cpu_addr: cmd.va, dma_handle: cmd.dma); |
3471 | err: |
3472 | mutex_unlock(lock: &adapter->mcc_lock); |
3473 | return status; |
3474 | } |
3475 | |
3476 | static int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain) |
3477 | { |
3478 | struct be_mcc_wrb *wrb; |
3479 | struct be_cmd_req_set_qos *req; |
3480 | int status; |
3481 | |
3482 | mutex_lock(&adapter->mcc_lock); |
3483 | |
3484 | wrb = wrb_from_mccq(adapter); |
3485 | if (!wrb) { |
3486 | status = -EBUSY; |
3487 | goto err; |
3488 | } |
3489 | |
3490 | req = embedded_payload(wrb); |
3491 | |
3492 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3493 | OPCODE_COMMON_SET_QOS, cmd_len: sizeof(*req), wrb, NULL); |
3494 | |
3495 | req->hdr.domain = domain; |
3496 | req->valid_bits = cpu_to_le32(BE_QOS_BITS_NIC); |
3497 | req->max_bps_nic = cpu_to_le32(bps); |
3498 | |
3499 | status = be_mcc_notify_wait(adapter); |
3500 | |
3501 | err: |
3502 | mutex_unlock(lock: &adapter->mcc_lock); |
3503 | return status; |
3504 | } |
3505 | |
3506 | int be_cmd_get_cntl_attributes(struct be_adapter *adapter) |
3507 | { |
3508 | struct be_mcc_wrb *wrb; |
3509 | struct be_cmd_req_cntl_attribs *req; |
3510 | struct be_cmd_resp_cntl_attribs *resp; |
3511 | int status, i; |
3512 | int payload_len = max(sizeof(*req), sizeof(*resp)); |
3513 | struct mgmt_controller_attrib *attribs; |
3514 | struct be_dma_mem attribs_cmd; |
3515 | u32 *serial_num; |
3516 | |
3517 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
3518 | return -1; |
3519 | |
3520 | memset(&attribs_cmd, 0, sizeof(struct be_dma_mem)); |
3521 | attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs); |
3522 | attribs_cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, |
3523 | size: attribs_cmd.size, |
3524 | dma_handle: &attribs_cmd.dma, GFP_ATOMIC); |
3525 | if (!attribs_cmd.va) { |
3526 | dev_err(&adapter->pdev->dev, "Memory allocation failure\n" ); |
3527 | status = -ENOMEM; |
3528 | goto err; |
3529 | } |
3530 | |
3531 | wrb = wrb_from_mbox(adapter); |
3532 | if (!wrb) { |
3533 | status = -EBUSY; |
3534 | goto err; |
3535 | } |
3536 | req = attribs_cmd.va; |
3537 | |
3538 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3539 | OPCODE_COMMON_GET_CNTL_ATTRIBUTES, cmd_len: payload_len, |
3540 | wrb, mem: &attribs_cmd); |
3541 | |
3542 | status = be_mbox_notify_wait(adapter); |
3543 | if (!status) { |
3544 | attribs = attribs_cmd.va + sizeof(struct be_cmd_resp_hdr); |
3545 | adapter->hba_port_num = attribs->hba_attribs.phy_port; |
3546 | serial_num = attribs->hba_attribs.controller_serial_number; |
3547 | for (i = 0; i < CNTL_SERIAL_NUM_WORDS; i++) |
3548 | adapter->serial_num[i] = le32_to_cpu(serial_num[i]) & |
3549 | (BIT_MASK(16) - 1); |
3550 | /* For BEx, since GET_FUNC_CONFIG command is not |
3551 | * supported, we read funcnum here as a workaround. |
3552 | */ |
3553 | if (BEx_chip(adapter)) |
3554 | adapter->pf_num = attribs->hba_attribs.pci_funcnum; |
3555 | } |
3556 | |
3557 | err: |
3558 | mutex_unlock(lock: &adapter->mbox_lock); |
3559 | if (attribs_cmd.va) |
3560 | dma_free_coherent(dev: &adapter->pdev->dev, size: attribs_cmd.size, |
3561 | cpu_addr: attribs_cmd.va, dma_handle: attribs_cmd.dma); |
3562 | return status; |
3563 | } |
3564 | |
3565 | /* Uses mbox */ |
3566 | int be_cmd_req_native_mode(struct be_adapter *adapter) |
3567 | { |
3568 | struct be_mcc_wrb *wrb; |
3569 | struct be_cmd_req_set_func_cap *req; |
3570 | int status; |
3571 | |
3572 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
3573 | return -1; |
3574 | |
3575 | wrb = wrb_from_mbox(adapter); |
3576 | if (!wrb) { |
3577 | status = -EBUSY; |
3578 | goto err; |
3579 | } |
3580 | |
3581 | req = embedded_payload(wrb); |
3582 | |
3583 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3584 | OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP, |
3585 | cmd_len: sizeof(*req), wrb, NULL); |
3586 | |
3587 | req->valid_cap_flags = cpu_to_le32(CAPABILITY_SW_TIMESTAMPS | |
3588 | CAPABILITY_BE3_NATIVE_ERX_API); |
3589 | req->cap_flags = cpu_to_le32(CAPABILITY_BE3_NATIVE_ERX_API); |
3590 | |
3591 | status = be_mbox_notify_wait(adapter); |
3592 | if (!status) { |
3593 | struct be_cmd_resp_set_func_cap *resp = embedded_payload(wrb); |
3594 | |
3595 | adapter->be3_native = le32_to_cpu(resp->cap_flags) & |
3596 | CAPABILITY_BE3_NATIVE_ERX_API; |
3597 | if (!adapter->be3_native) |
3598 | dev_warn(&adapter->pdev->dev, |
3599 | "adapter not in advanced mode\n" ); |
3600 | } |
3601 | err: |
3602 | mutex_unlock(lock: &adapter->mbox_lock); |
3603 | return status; |
3604 | } |
3605 | |
3606 | /* Get privilege(s) for a function */ |
3607 | int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege, |
3608 | u32 domain) |
3609 | { |
3610 | struct be_mcc_wrb *wrb; |
3611 | struct be_cmd_req_get_fn_privileges *req; |
3612 | int status; |
3613 | |
3614 | mutex_lock(&adapter->mcc_lock); |
3615 | |
3616 | wrb = wrb_from_mccq(adapter); |
3617 | if (!wrb) { |
3618 | status = -EBUSY; |
3619 | goto err; |
3620 | } |
3621 | |
3622 | req = embedded_payload(wrb); |
3623 | |
3624 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3625 | OPCODE_COMMON_GET_FN_PRIVILEGES, cmd_len: sizeof(*req), |
3626 | wrb, NULL); |
3627 | |
3628 | req->hdr.domain = domain; |
3629 | |
3630 | status = be_mcc_notify_wait(adapter); |
3631 | if (!status) { |
3632 | struct be_cmd_resp_get_fn_privileges *resp = |
3633 | embedded_payload(wrb); |
3634 | |
3635 | *privilege = le32_to_cpu(resp->privilege_mask); |
3636 | |
3637 | /* In UMC mode FW does not return right privileges. |
3638 | * Override with correct privilege equivalent to PF. |
3639 | */ |
3640 | if (BEx_chip(adapter) && be_is_mc(adapter) && |
3641 | be_physfn(adapter)) |
3642 | *privilege = MAX_PRIVILEGES; |
3643 | } |
3644 | |
3645 | err: |
3646 | mutex_unlock(lock: &adapter->mcc_lock); |
3647 | return status; |
3648 | } |
3649 | |
3650 | /* Set privilege(s) for a function */ |
3651 | int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges, |
3652 | u32 domain) |
3653 | { |
3654 | struct be_mcc_wrb *wrb; |
3655 | struct be_cmd_req_set_fn_privileges *req; |
3656 | int status; |
3657 | |
3658 | mutex_lock(&adapter->mcc_lock); |
3659 | |
3660 | wrb = wrb_from_mccq(adapter); |
3661 | if (!wrb) { |
3662 | status = -EBUSY; |
3663 | goto err; |
3664 | } |
3665 | |
3666 | req = embedded_payload(wrb); |
3667 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3668 | OPCODE_COMMON_SET_FN_PRIVILEGES, cmd_len: sizeof(*req), |
3669 | wrb, NULL); |
3670 | req->hdr.domain = domain; |
3671 | if (lancer_chip(adapter)) |
3672 | req->privileges_lancer = cpu_to_le32(privileges); |
3673 | else |
3674 | req->privileges = cpu_to_le32(privileges); |
3675 | |
3676 | status = be_mcc_notify_wait(adapter); |
3677 | err: |
3678 | mutex_unlock(lock: &adapter->mcc_lock); |
3679 | return status; |
3680 | } |
3681 | |
3682 | /* pmac_id_valid: true => pmac_id is supplied and MAC address is requested. |
3683 | * pmac_id_valid: false => pmac_id or MAC address is requested. |
3684 | * If pmac_id is returned, pmac_id_valid is returned as true |
3685 | */ |
3686 | int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, |
3687 | bool *pmac_id_valid, u32 *pmac_id, u32 if_handle, |
3688 | u8 domain) |
3689 | { |
3690 | struct be_mcc_wrb *wrb; |
3691 | struct be_cmd_req_get_mac_list *req; |
3692 | int status; |
3693 | int mac_count; |
3694 | struct be_dma_mem get_mac_list_cmd; |
3695 | int i; |
3696 | |
3697 | memset(&get_mac_list_cmd, 0, sizeof(struct be_dma_mem)); |
3698 | get_mac_list_cmd.size = sizeof(struct be_cmd_resp_get_mac_list); |
3699 | get_mac_list_cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, |
3700 | size: get_mac_list_cmd.size, |
3701 | dma_handle: &get_mac_list_cmd.dma, |
3702 | GFP_ATOMIC); |
3703 | |
3704 | if (!get_mac_list_cmd.va) { |
3705 | dev_err(&adapter->pdev->dev, |
3706 | "Memory allocation failure during GET_MAC_LIST\n" ); |
3707 | return -ENOMEM; |
3708 | } |
3709 | |
3710 | mutex_lock(&adapter->mcc_lock); |
3711 | |
3712 | wrb = wrb_from_mccq(adapter); |
3713 | if (!wrb) { |
3714 | status = -EBUSY; |
3715 | goto out; |
3716 | } |
3717 | |
3718 | req = get_mac_list_cmd.va; |
3719 | |
3720 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3721 | OPCODE_COMMON_GET_MAC_LIST, |
3722 | cmd_len: get_mac_list_cmd.size, wrb, mem: &get_mac_list_cmd); |
3723 | req->hdr.domain = domain; |
3724 | req->mac_type = MAC_ADDRESS_TYPE_NETWORK; |
3725 | if (*pmac_id_valid) { |
3726 | req->mac_id = cpu_to_le32(*pmac_id); |
3727 | req->iface_id = cpu_to_le16(if_handle); |
3728 | req->perm_override = 0; |
3729 | } else { |
3730 | req->perm_override = 1; |
3731 | } |
3732 | |
3733 | status = be_mcc_notify_wait(adapter); |
3734 | if (!status) { |
3735 | struct be_cmd_resp_get_mac_list *resp = |
3736 | get_mac_list_cmd.va; |
3737 | |
3738 | if (*pmac_id_valid) { |
3739 | memcpy(mac, resp->macid_macaddr.mac_addr_id.macaddr, |
3740 | ETH_ALEN); |
3741 | goto out; |
3742 | } |
3743 | |
3744 | mac_count = resp->true_mac_count + resp->pseudo_mac_count; |
3745 | /* Mac list returned could contain one or more active mac_ids |
3746 | * or one or more true or pseudo permanent mac addresses. |
3747 | * If an active mac_id is present, return first active mac_id |
3748 | * found. |
3749 | */ |
3750 | for (i = 0; i < mac_count; i++) { |
3751 | struct get_list_macaddr *mac_entry; |
3752 | u16 mac_addr_size; |
3753 | u32 mac_id; |
3754 | |
3755 | mac_entry = &resp->macaddr_list[i]; |
3756 | mac_addr_size = le16_to_cpu(mac_entry->mac_addr_size); |
3757 | /* mac_id is a 32 bit value and mac_addr size |
3758 | * is 6 bytes |
3759 | */ |
3760 | if (mac_addr_size == sizeof(u32)) { |
3761 | *pmac_id_valid = true; |
3762 | mac_id = mac_entry->mac_addr_id.s_mac_id.mac_id; |
3763 | *pmac_id = le32_to_cpu(mac_id); |
3764 | goto out; |
3765 | } |
3766 | } |
3767 | /* If no active mac_id found, return first mac addr */ |
3768 | *pmac_id_valid = false; |
3769 | memcpy(mac, resp->macaddr_list[0].mac_addr_id.macaddr, |
3770 | ETH_ALEN); |
3771 | } |
3772 | |
3773 | out: |
3774 | mutex_unlock(lock: &adapter->mcc_lock); |
3775 | dma_free_coherent(dev: &adapter->pdev->dev, size: get_mac_list_cmd.size, |
3776 | cpu_addr: get_mac_list_cmd.va, dma_handle: get_mac_list_cmd.dma); |
3777 | return status; |
3778 | } |
3779 | |
3780 | int be_cmd_get_active_mac(struct be_adapter *adapter, u32 curr_pmac_id, |
3781 | u8 *mac, u32 if_handle, bool active, u32 domain) |
3782 | { |
3783 | if (!active) |
3784 | be_cmd_get_mac_from_list(adapter, mac, pmac_id_valid: &active, pmac_id: &curr_pmac_id, |
3785 | if_handle, domain); |
3786 | if (BEx_chip(adapter)) |
3787 | return be_cmd_mac_addr_query(adapter, mac_addr: mac, permanent: false, |
3788 | if_handle, pmac_id: curr_pmac_id); |
3789 | else |
3790 | /* Fetch the MAC address using pmac_id */ |
3791 | return be_cmd_get_mac_from_list(adapter, mac, pmac_id_valid: &active, |
3792 | pmac_id: &curr_pmac_id, |
3793 | if_handle, domain); |
3794 | } |
3795 | |
3796 | int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac) |
3797 | { |
3798 | int status; |
3799 | bool pmac_valid = false; |
3800 | |
3801 | eth_zero_addr(addr: mac); |
3802 | |
3803 | if (BEx_chip(adapter)) { |
3804 | if (be_physfn(adapter)) |
3805 | status = be_cmd_mac_addr_query(adapter, mac_addr: mac, permanent: true, if_handle: 0, |
3806 | pmac_id: 0); |
3807 | else |
3808 | status = be_cmd_mac_addr_query(adapter, mac_addr: mac, permanent: false, |
3809 | if_handle: adapter->if_handle, pmac_id: 0); |
3810 | } else { |
3811 | status = be_cmd_get_mac_from_list(adapter, mac, pmac_id_valid: &pmac_valid, |
3812 | NULL, if_handle: adapter->if_handle, domain: 0); |
3813 | } |
3814 | |
3815 | return status; |
3816 | } |
3817 | |
3818 | /* Uses synchronous MCCQ */ |
3819 | int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, |
3820 | u8 mac_count, u32 domain) |
3821 | { |
3822 | struct be_mcc_wrb *wrb; |
3823 | struct be_cmd_req_set_mac_list *req; |
3824 | int status; |
3825 | struct be_dma_mem cmd; |
3826 | |
3827 | memset(&cmd, 0, sizeof(struct be_dma_mem)); |
3828 | cmd.size = sizeof(struct be_cmd_req_set_mac_list); |
3829 | cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, size: cmd.size, dma_handle: &cmd.dma, |
3830 | GFP_KERNEL); |
3831 | if (!cmd.va) |
3832 | return -ENOMEM; |
3833 | |
3834 | mutex_lock(&adapter->mcc_lock); |
3835 | |
3836 | wrb = wrb_from_mccq(adapter); |
3837 | if (!wrb) { |
3838 | status = -EBUSY; |
3839 | goto err; |
3840 | } |
3841 | |
3842 | req = cmd.va; |
3843 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3844 | OPCODE_COMMON_SET_MAC_LIST, cmd_len: sizeof(*req), |
3845 | wrb, mem: &cmd); |
3846 | |
3847 | req->hdr.domain = domain; |
3848 | req->mac_count = mac_count; |
3849 | if (mac_count) |
3850 | memcpy(req->mac, mac_array, ETH_ALEN * mac_count); |
3851 | |
3852 | status = be_mcc_notify_wait(adapter); |
3853 | |
3854 | err: |
3855 | dma_free_coherent(dev: &adapter->pdev->dev, size: cmd.size, cpu_addr: cmd.va, dma_handle: cmd.dma); |
3856 | mutex_unlock(lock: &adapter->mcc_lock); |
3857 | return status; |
3858 | } |
3859 | |
3860 | /* Wrapper to delete any active MACs and provision the new mac. |
3861 | * Changes to MAC_LIST are allowed iff none of the MAC addresses in the |
3862 | * current list are active. |
3863 | */ |
3864 | int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom) |
3865 | { |
3866 | bool active_mac = false; |
3867 | u8 old_mac[ETH_ALEN]; |
3868 | u32 pmac_id; |
3869 | int status; |
3870 | |
3871 | status = be_cmd_get_mac_from_list(adapter, mac: old_mac, pmac_id_valid: &active_mac, |
3872 | pmac_id: &pmac_id, if_handle: if_id, domain: dom); |
3873 | |
3874 | if (!status && active_mac) |
3875 | be_cmd_pmac_del(adapter, if_id, pmac_id, dom); |
3876 | |
3877 | return be_cmd_set_mac_list(adapter, mac_array: mac, mac_count: mac ? 1 : 0, domain: dom); |
3878 | } |
3879 | |
3880 | int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, |
3881 | u32 domain, u16 intf_id, u16 hsw_mode, u8 spoofchk) |
3882 | { |
3883 | struct be_mcc_wrb *wrb; |
3884 | struct be_cmd_req_set_hsw_config *req; |
3885 | void *ctxt; |
3886 | int status; |
3887 | |
3888 | if (!be_cmd_allowed(adapter, OPCODE_COMMON_SET_HSW_CONFIG, |
3889 | CMD_SUBSYSTEM_COMMON)) |
3890 | return -EPERM; |
3891 | |
3892 | mutex_lock(&adapter->mcc_lock); |
3893 | |
3894 | wrb = wrb_from_mccq(adapter); |
3895 | if (!wrb) { |
3896 | status = -EBUSY; |
3897 | goto err; |
3898 | } |
3899 | |
3900 | req = embedded_payload(wrb); |
3901 | ctxt = &req->context; |
3902 | |
3903 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3904 | OPCODE_COMMON_SET_HSW_CONFIG, cmd_len: sizeof(*req), wrb, |
3905 | NULL); |
3906 | |
3907 | req->hdr.domain = domain; |
3908 | AMAP_SET_BITS(struct amap_set_hsw_context, interface_id, ctxt, intf_id); |
3909 | if (pvid) { |
3910 | AMAP_SET_BITS(struct amap_set_hsw_context, pvid_valid, ctxt, 1); |
3911 | AMAP_SET_BITS(struct amap_set_hsw_context, pvid, ctxt, pvid); |
3912 | } |
3913 | if (hsw_mode) { |
3914 | AMAP_SET_BITS(struct amap_set_hsw_context, interface_id, |
3915 | ctxt, adapter->hba_port_num); |
3916 | AMAP_SET_BITS(struct amap_set_hsw_context, pport, ctxt, 1); |
3917 | AMAP_SET_BITS(struct amap_set_hsw_context, port_fwd_type, |
3918 | ctxt, hsw_mode); |
3919 | } |
3920 | |
3921 | /* Enable/disable both mac and vlan spoof checking */ |
3922 | if (!BEx_chip(adapter) && spoofchk) { |
3923 | AMAP_SET_BITS(struct amap_set_hsw_context, mac_spoofchk, |
3924 | ctxt, spoofchk); |
3925 | AMAP_SET_BITS(struct amap_set_hsw_context, vlan_spoofchk, |
3926 | ctxt, spoofchk); |
3927 | } |
3928 | |
3929 | be_dws_cpu_to_le(req->context, sizeof(req->context)); |
3930 | status = be_mcc_notify_wait(adapter); |
3931 | |
3932 | err: |
3933 | mutex_unlock(lock: &adapter->mcc_lock); |
3934 | return status; |
3935 | } |
3936 | |
3937 | /* Get Hyper switch config */ |
3938 | int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, |
3939 | u32 domain, u16 intf_id, u8 *mode, bool *spoofchk) |
3940 | { |
3941 | struct be_mcc_wrb *wrb; |
3942 | struct be_cmd_req_get_hsw_config *req; |
3943 | void *ctxt; |
3944 | int status; |
3945 | u16 vid; |
3946 | |
3947 | mutex_lock(&adapter->mcc_lock); |
3948 | |
3949 | wrb = wrb_from_mccq(adapter); |
3950 | if (!wrb) { |
3951 | status = -EBUSY; |
3952 | goto err; |
3953 | } |
3954 | |
3955 | req = embedded_payload(wrb); |
3956 | ctxt = &req->context; |
3957 | |
3958 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
3959 | OPCODE_COMMON_GET_HSW_CONFIG, cmd_len: sizeof(*req), wrb, |
3960 | NULL); |
3961 | |
3962 | req->hdr.domain = domain; |
3963 | AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, |
3964 | ctxt, intf_id); |
3965 | AMAP_SET_BITS(struct amap_get_hsw_req_context, pvid_valid, ctxt, 1); |
3966 | |
3967 | if (!BEx_chip(adapter) && mode) { |
3968 | AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, |
3969 | ctxt, adapter->hba_port_num); |
3970 | AMAP_SET_BITS(struct amap_get_hsw_req_context, pport, ctxt, 1); |
3971 | } |
3972 | be_dws_cpu_to_le(req->context, sizeof(req->context)); |
3973 | |
3974 | status = be_mcc_notify_wait(adapter); |
3975 | if (!status) { |
3976 | struct be_cmd_resp_get_hsw_config *resp = |
3977 | embedded_payload(wrb); |
3978 | |
3979 | be_dws_le_to_cpu(&resp->context, sizeof(resp->context)); |
3980 | vid = AMAP_GET_BITS(struct amap_get_hsw_resp_context, |
3981 | pvid, &resp->context); |
3982 | if (pvid) |
3983 | *pvid = le16_to_cpu(vid); |
3984 | if (mode) |
3985 | *mode = AMAP_GET_BITS(struct amap_get_hsw_resp_context, |
3986 | port_fwd_type, &resp->context); |
3987 | if (spoofchk) |
3988 | *spoofchk = |
3989 | AMAP_GET_BITS(struct amap_get_hsw_resp_context, |
3990 | spoofchk, &resp->context); |
3991 | } |
3992 | |
3993 | err: |
3994 | mutex_unlock(lock: &adapter->mcc_lock); |
3995 | return status; |
3996 | } |
3997 | |
3998 | static bool be_is_wol_excluded(struct be_adapter *adapter) |
3999 | { |
4000 | struct pci_dev *pdev = adapter->pdev; |
4001 | |
4002 | if (be_virtfn(adapter)) |
4003 | return true; |
4004 | |
4005 | switch (pdev->subsystem_device) { |
4006 | case OC_SUBSYS_DEVICE_ID1: |
4007 | case OC_SUBSYS_DEVICE_ID2: |
4008 | case OC_SUBSYS_DEVICE_ID3: |
4009 | case OC_SUBSYS_DEVICE_ID4: |
4010 | return true; |
4011 | default: |
4012 | return false; |
4013 | } |
4014 | } |
4015 | |
4016 | int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) |
4017 | { |
4018 | struct be_mcc_wrb *wrb; |
4019 | struct be_cmd_req_acpi_wol_magic_config_v1 *req; |
4020 | int status = 0; |
4021 | struct be_dma_mem cmd; |
4022 | |
4023 | if (!be_cmd_allowed(adapter, OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, |
4024 | CMD_SUBSYSTEM_ETH)) |
4025 | return -EPERM; |
4026 | |
4027 | if (be_is_wol_excluded(adapter)) |
4028 | return status; |
4029 | |
4030 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
4031 | return -1; |
4032 | |
4033 | memset(&cmd, 0, sizeof(struct be_dma_mem)); |
4034 | cmd.size = sizeof(struct be_cmd_resp_acpi_wol_magic_config_v1); |
4035 | cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, size: cmd.size, dma_handle: &cmd.dma, |
4036 | GFP_ATOMIC); |
4037 | if (!cmd.va) { |
4038 | dev_err(&adapter->pdev->dev, "Memory allocation failure\n" ); |
4039 | status = -ENOMEM; |
4040 | goto err; |
4041 | } |
4042 | |
4043 | wrb = wrb_from_mbox(adapter); |
4044 | if (!wrb) { |
4045 | status = -EBUSY; |
4046 | goto err; |
4047 | } |
4048 | |
4049 | req = cmd.va; |
4050 | |
4051 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ETH, |
4052 | OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, |
4053 | cmd_len: sizeof(*req), wrb, mem: &cmd); |
4054 | |
4055 | req->hdr.version = 1; |
4056 | req->query_options = BE_GET_WOL_CAP; |
4057 | |
4058 | status = be_mbox_notify_wait(adapter); |
4059 | if (!status) { |
4060 | struct be_cmd_resp_acpi_wol_magic_config_v1 *resp; |
4061 | |
4062 | resp = (struct be_cmd_resp_acpi_wol_magic_config_v1 *)cmd.va; |
4063 | |
4064 | adapter->wol_cap = resp->wol_settings; |
4065 | |
4066 | /* Non-zero macaddr indicates WOL is enabled */ |
4067 | if (adapter->wol_cap & BE_WOL_CAP && |
4068 | !is_zero_ether_addr(addr: resp->magic_mac)) |
4069 | adapter->wol_en = true; |
4070 | } |
4071 | err: |
4072 | mutex_unlock(lock: &adapter->mbox_lock); |
4073 | if (cmd.va) |
4074 | dma_free_coherent(dev: &adapter->pdev->dev, size: cmd.size, cpu_addr: cmd.va, |
4075 | dma_handle: cmd.dma); |
4076 | return status; |
4077 | |
4078 | } |
4079 | |
4080 | int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level) |
4081 | { |
4082 | struct be_dma_mem extfat_cmd; |
4083 | struct be_fat_conf_params *cfgs; |
4084 | int status; |
4085 | int i, j; |
4086 | |
4087 | memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); |
4088 | extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); |
4089 | extfat_cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, |
4090 | size: extfat_cmd.size, dma_handle: &extfat_cmd.dma, |
4091 | GFP_ATOMIC); |
4092 | if (!extfat_cmd.va) |
4093 | return -ENOMEM; |
4094 | |
4095 | status = be_cmd_get_ext_fat_capabilites(adapter, cmd: &extfat_cmd); |
4096 | if (status) |
4097 | goto err; |
4098 | |
4099 | cfgs = (struct be_fat_conf_params *) |
4100 | (extfat_cmd.va + sizeof(struct be_cmd_resp_hdr)); |
4101 | for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) { |
4102 | u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes); |
4103 | |
4104 | for (j = 0; j < num_modes; j++) { |
4105 | if (cfgs->module[i].trace_lvl[j].mode == MODE_UART) |
4106 | cfgs->module[i].trace_lvl[j].dbg_lvl = |
4107 | cpu_to_le32(level); |
4108 | } |
4109 | } |
4110 | |
4111 | status = be_cmd_set_ext_fat_capabilites(adapter, cmd: &extfat_cmd, cfgs); |
4112 | err: |
4113 | dma_free_coherent(dev: &adapter->pdev->dev, size: extfat_cmd.size, cpu_addr: extfat_cmd.va, |
4114 | dma_handle: extfat_cmd.dma); |
4115 | return status; |
4116 | } |
4117 | |
4118 | int be_cmd_get_fw_log_level(struct be_adapter *adapter) |
4119 | { |
4120 | struct be_dma_mem extfat_cmd; |
4121 | struct be_fat_conf_params *cfgs; |
4122 | int status, j; |
4123 | int level = 0; |
4124 | |
4125 | memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); |
4126 | extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); |
4127 | extfat_cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, |
4128 | size: extfat_cmd.size, dma_handle: &extfat_cmd.dma, |
4129 | GFP_ATOMIC); |
4130 | |
4131 | if (!extfat_cmd.va) { |
4132 | dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n" , |
4133 | __func__); |
4134 | goto err; |
4135 | } |
4136 | |
4137 | status = be_cmd_get_ext_fat_capabilites(adapter, cmd: &extfat_cmd); |
4138 | if (!status) { |
4139 | cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + |
4140 | sizeof(struct be_cmd_resp_hdr)); |
4141 | |
4142 | for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) { |
4143 | if (cfgs->module[0].trace_lvl[j].mode == MODE_UART) |
4144 | level = cfgs->module[0].trace_lvl[j].dbg_lvl; |
4145 | } |
4146 | } |
4147 | dma_free_coherent(dev: &adapter->pdev->dev, size: extfat_cmd.size, cpu_addr: extfat_cmd.va, |
4148 | dma_handle: extfat_cmd.dma); |
4149 | err: |
4150 | return level; |
4151 | } |
4152 | |
4153 | int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter, |
4154 | struct be_dma_mem *cmd) |
4155 | { |
4156 | struct be_mcc_wrb *wrb; |
4157 | struct be_cmd_req_get_ext_fat_caps *req; |
4158 | int status; |
4159 | |
4160 | if (!be_cmd_allowed(adapter, OPCODE_COMMON_GET_EXT_FAT_CAPABILITIES, |
4161 | CMD_SUBSYSTEM_COMMON)) |
4162 | return -EPERM; |
4163 | |
4164 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
4165 | return -1; |
4166 | |
4167 | wrb = wrb_from_mbox(adapter); |
4168 | if (!wrb) { |
4169 | status = -EBUSY; |
4170 | goto err; |
4171 | } |
4172 | |
4173 | req = cmd->va; |
4174 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4175 | OPCODE_COMMON_GET_EXT_FAT_CAPABILITIES, |
4176 | cmd_len: cmd->size, wrb, mem: cmd); |
4177 | req->parameter_type = cpu_to_le32(1); |
4178 | |
4179 | status = be_mbox_notify_wait(adapter); |
4180 | err: |
4181 | mutex_unlock(lock: &adapter->mbox_lock); |
4182 | return status; |
4183 | } |
4184 | |
4185 | int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter, |
4186 | struct be_dma_mem *cmd, |
4187 | struct be_fat_conf_params *configs) |
4188 | { |
4189 | struct be_mcc_wrb *wrb; |
4190 | struct be_cmd_req_set_ext_fat_caps *req; |
4191 | int status; |
4192 | |
4193 | mutex_lock(&adapter->mcc_lock); |
4194 | |
4195 | wrb = wrb_from_mccq(adapter); |
4196 | if (!wrb) { |
4197 | status = -EBUSY; |
4198 | goto err; |
4199 | } |
4200 | |
4201 | req = cmd->va; |
4202 | memcpy(&req->set_params, configs, sizeof(struct be_fat_conf_params)); |
4203 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4204 | OPCODE_COMMON_SET_EXT_FAT_CAPABILITIES, |
4205 | cmd_len: cmd->size, wrb, mem: cmd); |
4206 | |
4207 | status = be_mcc_notify_wait(adapter); |
4208 | err: |
4209 | mutex_unlock(lock: &adapter->mcc_lock); |
4210 | return status; |
4211 | } |
4212 | |
4213 | int be_cmd_query_port_name(struct be_adapter *adapter) |
4214 | { |
4215 | struct be_cmd_req_get_port_name *req; |
4216 | struct be_mcc_wrb *wrb; |
4217 | int status; |
4218 | |
4219 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
4220 | return -1; |
4221 | |
4222 | wrb = wrb_from_mbox(adapter); |
4223 | req = embedded_payload(wrb); |
4224 | |
4225 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4226 | OPCODE_COMMON_GET_PORT_NAME, cmd_len: sizeof(*req), wrb, |
4227 | NULL); |
4228 | if (!BEx_chip(adapter)) |
4229 | req->hdr.version = 1; |
4230 | |
4231 | status = be_mbox_notify_wait(adapter); |
4232 | if (!status) { |
4233 | struct be_cmd_resp_get_port_name *resp = embedded_payload(wrb); |
4234 | |
4235 | adapter->port_name = resp->port_name[adapter->hba_port_num]; |
4236 | } else { |
4237 | adapter->port_name = adapter->hba_port_num + '0'; |
4238 | } |
4239 | |
4240 | mutex_unlock(lock: &adapter->mbox_lock); |
4241 | return status; |
4242 | } |
4243 | |
4244 | /* When more than 1 NIC descriptor is present in the descriptor list, |
4245 | * the caller must specify the pf_num to obtain the NIC descriptor |
4246 | * corresponding to its pci function. |
4247 | * get_vft must be true when the caller wants the VF-template desc of the |
4248 | * PF-pool. |
4249 | * The pf_num should be set to PF_NUM_IGNORE when the caller knows |
4250 | * that only it's NIC descriptor is present in the descriptor list. |
4251 | */ |
4252 | static struct be_nic_res_desc *be_get_nic_desc(u8 *buf, u32 desc_count, |
4253 | bool get_vft, u8 pf_num) |
4254 | { |
4255 | struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; |
4256 | struct be_nic_res_desc *nic; |
4257 | int i; |
4258 | |
4259 | for (i = 0; i < desc_count; i++) { |
4260 | if (hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V0 || |
4261 | hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V1) { |
4262 | nic = (struct be_nic_res_desc *)hdr; |
4263 | |
4264 | if ((pf_num == PF_NUM_IGNORE || |
4265 | nic->pf_num == pf_num) && |
4266 | (!get_vft || nic->flags & BIT(VFT_SHIFT))) |
4267 | return nic; |
4268 | } |
4269 | hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; |
4270 | hdr = (void *)hdr + hdr->desc_len; |
4271 | } |
4272 | return NULL; |
4273 | } |
4274 | |
4275 | static struct be_nic_res_desc *be_get_vft_desc(u8 *buf, u32 desc_count, |
4276 | u8 pf_num) |
4277 | { |
4278 | return be_get_nic_desc(buf, desc_count, get_vft: true, pf_num); |
4279 | } |
4280 | |
4281 | static struct be_nic_res_desc *be_get_func_nic_desc(u8 *buf, u32 desc_count, |
4282 | u8 pf_num) |
4283 | { |
4284 | return be_get_nic_desc(buf, desc_count, get_vft: false, pf_num); |
4285 | } |
4286 | |
4287 | static struct be_pcie_res_desc *be_get_pcie_desc(u8 *buf, u32 desc_count, |
4288 | u8 pf_num) |
4289 | { |
4290 | struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; |
4291 | struct be_pcie_res_desc *pcie; |
4292 | int i; |
4293 | |
4294 | for (i = 0; i < desc_count; i++) { |
4295 | if (hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V0 || |
4296 | hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V1) { |
4297 | pcie = (struct be_pcie_res_desc *)hdr; |
4298 | if (pcie->pf_num == pf_num) |
4299 | return pcie; |
4300 | } |
4301 | |
4302 | hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; |
4303 | hdr = (void *)hdr + hdr->desc_len; |
4304 | } |
4305 | return NULL; |
4306 | } |
4307 | |
4308 | static struct be_port_res_desc *be_get_port_desc(u8 *buf, u32 desc_count) |
4309 | { |
4310 | struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; |
4311 | int i; |
4312 | |
4313 | for (i = 0; i < desc_count; i++) { |
4314 | if (hdr->desc_type == PORT_RESOURCE_DESC_TYPE_V1) |
4315 | return (struct be_port_res_desc *)hdr; |
4316 | |
4317 | hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; |
4318 | hdr = (void *)hdr + hdr->desc_len; |
4319 | } |
4320 | return NULL; |
4321 | } |
4322 | |
4323 | static void be_copy_nic_desc(struct be_resources *res, |
4324 | struct be_nic_res_desc *desc) |
4325 | { |
4326 | res->max_uc_mac = le16_to_cpu(desc->unicast_mac_count); |
4327 | res->max_vlans = le16_to_cpu(desc->vlan_count); |
4328 | res->max_mcast_mac = le16_to_cpu(desc->mcast_mac_count); |
4329 | res->max_tx_qs = le16_to_cpu(desc->txq_count); |
4330 | res->max_rss_qs = le16_to_cpu(desc->rssq_count); |
4331 | res->max_rx_qs = le16_to_cpu(desc->rq_count); |
4332 | res->max_evt_qs = le16_to_cpu(desc->eq_count); |
4333 | res->max_cq_count = le16_to_cpu(desc->cq_count); |
4334 | res->max_iface_count = le16_to_cpu(desc->iface_count); |
4335 | res->max_mcc_count = le16_to_cpu(desc->mcc_count); |
4336 | /* Clear flags that driver is not interested in */ |
4337 | res->if_cap_flags = le32_to_cpu(desc->cap_flags) & |
4338 | BE_IF_CAP_FLAGS_WANT; |
4339 | } |
4340 | |
4341 | /* Uses Mbox */ |
4342 | int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res) |
4343 | { |
4344 | struct be_mcc_wrb *wrb; |
4345 | struct be_cmd_req_get_func_config *req; |
4346 | int status; |
4347 | struct be_dma_mem cmd; |
4348 | |
4349 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
4350 | return -1; |
4351 | |
4352 | memset(&cmd, 0, sizeof(struct be_dma_mem)); |
4353 | cmd.size = sizeof(struct be_cmd_resp_get_func_config); |
4354 | cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, size: cmd.size, dma_handle: &cmd.dma, |
4355 | GFP_ATOMIC); |
4356 | if (!cmd.va) { |
4357 | dev_err(&adapter->pdev->dev, "Memory alloc failure\n" ); |
4358 | status = -ENOMEM; |
4359 | goto err; |
4360 | } |
4361 | |
4362 | wrb = wrb_from_mbox(adapter); |
4363 | if (!wrb) { |
4364 | status = -EBUSY; |
4365 | goto err; |
4366 | } |
4367 | |
4368 | req = cmd.va; |
4369 | |
4370 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4371 | OPCODE_COMMON_GET_FUNC_CONFIG, |
4372 | cmd_len: cmd.size, wrb, mem: &cmd); |
4373 | |
4374 | if (skyhawk_chip(adapter)) |
4375 | req->hdr.version = 1; |
4376 | |
4377 | status = be_mbox_notify_wait(adapter); |
4378 | if (!status) { |
4379 | struct be_cmd_resp_get_func_config *resp = cmd.va; |
4380 | u32 desc_count = le32_to_cpu(resp->desc_count); |
4381 | struct be_nic_res_desc *desc; |
4382 | |
4383 | /* GET_FUNC_CONFIG returns resource descriptors of the |
4384 | * current function only. So, pf_num should be set to |
4385 | * PF_NUM_IGNORE. |
4386 | */ |
4387 | desc = be_get_func_nic_desc(buf: resp->func_param, desc_count, |
4388 | PF_NUM_IGNORE); |
4389 | if (!desc) { |
4390 | status = -EINVAL; |
4391 | goto err; |
4392 | } |
4393 | |
4394 | /* Store pf_num & vf_num for later use in GET_PROFILE_CONFIG */ |
4395 | adapter->pf_num = desc->pf_num; |
4396 | adapter->vf_num = desc->vf_num; |
4397 | |
4398 | if (res) |
4399 | be_copy_nic_desc(res, desc); |
4400 | } |
4401 | err: |
4402 | mutex_unlock(lock: &adapter->mbox_lock); |
4403 | if (cmd.va) |
4404 | dma_free_coherent(dev: &adapter->pdev->dev, size: cmd.size, cpu_addr: cmd.va, |
4405 | dma_handle: cmd.dma); |
4406 | return status; |
4407 | } |
4408 | |
4409 | /* This routine returns a list of all the NIC PF_nums in the adapter */ |
4410 | static u16 be_get_nic_pf_num_list(u8 *buf, u32 desc_count, u16 *nic_pf_nums) |
4411 | { |
4412 | struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; |
4413 | struct be_pcie_res_desc *pcie = NULL; |
4414 | int i; |
4415 | u16 nic_pf_count = 0; |
4416 | |
4417 | for (i = 0; i < desc_count; i++) { |
4418 | if (hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V0 || |
4419 | hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V1) { |
4420 | pcie = (struct be_pcie_res_desc *)hdr; |
4421 | if (pcie->pf_state && (pcie->pf_type == MISSION_NIC || |
4422 | pcie->pf_type == MISSION_RDMA)) { |
4423 | nic_pf_nums[nic_pf_count++] = pcie->pf_num; |
4424 | } |
4425 | } |
4426 | |
4427 | hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; |
4428 | hdr = (void *)hdr + hdr->desc_len; |
4429 | } |
4430 | return nic_pf_count; |
4431 | } |
4432 | |
4433 | /* Will use MBOX only if MCCQ has not been created */ |
4434 | int be_cmd_get_profile_config(struct be_adapter *adapter, |
4435 | struct be_resources *res, |
4436 | struct be_port_resources *port_res, |
4437 | u8 profile_type, u8 query, u8 domain) |
4438 | { |
4439 | struct be_cmd_resp_get_profile_config *resp; |
4440 | struct be_cmd_req_get_profile_config *req; |
4441 | struct be_nic_res_desc *vf_res; |
4442 | struct be_pcie_res_desc *pcie; |
4443 | struct be_port_res_desc *port; |
4444 | struct be_nic_res_desc *nic; |
4445 | struct be_mcc_wrb wrb = {0}; |
4446 | struct be_dma_mem cmd; |
4447 | u16 desc_count; |
4448 | int status; |
4449 | |
4450 | memset(&cmd, 0, sizeof(struct be_dma_mem)); |
4451 | cmd.size = sizeof(struct be_cmd_resp_get_profile_config); |
4452 | cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, size: cmd.size, dma_handle: &cmd.dma, |
4453 | GFP_ATOMIC); |
4454 | if (!cmd.va) |
4455 | return -ENOMEM; |
4456 | |
4457 | req = cmd.va; |
4458 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4459 | OPCODE_COMMON_GET_PROFILE_CONFIG, |
4460 | cmd_len: cmd.size, wrb: &wrb, mem: &cmd); |
4461 | |
4462 | if (!lancer_chip(adapter)) |
4463 | req->hdr.version = 1; |
4464 | req->type = profile_type; |
4465 | req->hdr.domain = domain; |
4466 | |
4467 | /* When QUERY_MODIFIABLE_FIELDS_TYPE bit is set, cmd returns the |
4468 | * descriptors with all bits set to "1" for the fields which can be |
4469 | * modified using SET_PROFILE_CONFIG cmd. |
4470 | */ |
4471 | if (query == RESOURCE_MODIFIABLE) |
4472 | req->type |= QUERY_MODIFIABLE_FIELDS_TYPE; |
4473 | |
4474 | status = be_cmd_notify_wait(adapter, wrb: &wrb); |
4475 | if (status) |
4476 | goto err; |
4477 | |
4478 | resp = cmd.va; |
4479 | desc_count = le16_to_cpu(resp->desc_count); |
4480 | |
4481 | if (port_res) { |
4482 | u16 nic_pf_cnt = 0, i; |
4483 | u16 nic_pf_num_list[MAX_NIC_FUNCS]; |
4484 | |
4485 | nic_pf_cnt = be_get_nic_pf_num_list(buf: resp->func_param, |
4486 | desc_count, |
4487 | nic_pf_nums: nic_pf_num_list); |
4488 | |
4489 | for (i = 0; i < nic_pf_cnt; i++) { |
4490 | nic = be_get_func_nic_desc(buf: resp->func_param, desc_count, |
4491 | pf_num: nic_pf_num_list[i]); |
4492 | if (nic->link_param == adapter->port_num) { |
4493 | port_res->nic_pfs++; |
4494 | pcie = be_get_pcie_desc(buf: resp->func_param, |
4495 | desc_count, |
4496 | pf_num: nic_pf_num_list[i]); |
4497 | port_res->max_vfs += le16_to_cpu(pcie->num_vfs); |
4498 | } |
4499 | } |
4500 | goto err; |
4501 | } |
4502 | |
4503 | pcie = be_get_pcie_desc(buf: resp->func_param, desc_count, |
4504 | pf_num: adapter->pf_num); |
4505 | if (pcie) |
4506 | res->max_vfs = le16_to_cpu(pcie->num_vfs); |
4507 | |
4508 | port = be_get_port_desc(buf: resp->func_param, desc_count); |
4509 | if (port) |
4510 | adapter->mc_type = port->mc_type; |
4511 | |
4512 | nic = be_get_func_nic_desc(buf: resp->func_param, desc_count, |
4513 | pf_num: adapter->pf_num); |
4514 | if (nic) |
4515 | be_copy_nic_desc(res, desc: nic); |
4516 | |
4517 | vf_res = be_get_vft_desc(buf: resp->func_param, desc_count, |
4518 | pf_num: adapter->pf_num); |
4519 | if (vf_res) |
4520 | res->vf_if_cap_flags = vf_res->cap_flags; |
4521 | err: |
4522 | if (cmd.va) |
4523 | dma_free_coherent(dev: &adapter->pdev->dev, size: cmd.size, cpu_addr: cmd.va, |
4524 | dma_handle: cmd.dma); |
4525 | return status; |
4526 | } |
4527 | |
4528 | /* Will use MBOX only if MCCQ has not been created */ |
4529 | static int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc, |
4530 | int size, int count, u8 version, u8 domain) |
4531 | { |
4532 | struct be_cmd_req_set_profile_config *req; |
4533 | struct be_mcc_wrb wrb = {0}; |
4534 | struct be_dma_mem cmd; |
4535 | int status; |
4536 | |
4537 | memset(&cmd, 0, sizeof(struct be_dma_mem)); |
4538 | cmd.size = sizeof(struct be_cmd_req_set_profile_config); |
4539 | cmd.va = dma_alloc_coherent(dev: &adapter->pdev->dev, size: cmd.size, dma_handle: &cmd.dma, |
4540 | GFP_ATOMIC); |
4541 | if (!cmd.va) |
4542 | return -ENOMEM; |
4543 | |
4544 | req = cmd.va; |
4545 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4546 | OPCODE_COMMON_SET_PROFILE_CONFIG, cmd_len: cmd.size, |
4547 | wrb: &wrb, mem: &cmd); |
4548 | req->hdr.version = version; |
4549 | req->hdr.domain = domain; |
4550 | req->desc_count = cpu_to_le32(count); |
4551 | memcpy(req->desc, desc, size); |
4552 | |
4553 | status = be_cmd_notify_wait(adapter, wrb: &wrb); |
4554 | |
4555 | if (cmd.va) |
4556 | dma_free_coherent(dev: &adapter->pdev->dev, size: cmd.size, cpu_addr: cmd.va, |
4557 | dma_handle: cmd.dma); |
4558 | return status; |
4559 | } |
4560 | |
4561 | /* Mark all fields invalid */ |
4562 | static void be_reset_nic_desc(struct be_nic_res_desc *nic) |
4563 | { |
4564 | memset(nic, 0, sizeof(*nic)); |
4565 | nic->unicast_mac_count = 0xFFFF; |
4566 | nic->mcc_count = 0xFFFF; |
4567 | nic->vlan_count = 0xFFFF; |
4568 | nic->mcast_mac_count = 0xFFFF; |
4569 | nic->txq_count = 0xFFFF; |
4570 | nic->rq_count = 0xFFFF; |
4571 | nic->rssq_count = 0xFFFF; |
4572 | nic->lro_count = 0xFFFF; |
4573 | nic->cq_count = 0xFFFF; |
4574 | nic->toe_conn_count = 0xFFFF; |
4575 | nic->eq_count = 0xFFFF; |
4576 | nic->iface_count = 0xFFFF; |
4577 | nic->link_param = 0xFF; |
4578 | nic->channel_id_param = cpu_to_le16(0xF000); |
4579 | nic->acpi_params = 0xFF; |
4580 | nic->wol_param = 0x0F; |
4581 | nic->tunnel_iface_count = 0xFFFF; |
4582 | nic->direct_tenant_iface_count = 0xFFFF; |
4583 | nic->bw_min = 0xFFFFFFFF; |
4584 | nic->bw_max = 0xFFFFFFFF; |
4585 | } |
4586 | |
4587 | /* Mark all fields invalid */ |
4588 | static void be_reset_pcie_desc(struct be_pcie_res_desc *pcie) |
4589 | { |
4590 | memset(pcie, 0, sizeof(*pcie)); |
4591 | pcie->sriov_state = 0xFF; |
4592 | pcie->pf_state = 0xFF; |
4593 | pcie->pf_type = 0xFF; |
4594 | pcie->num_vfs = 0xFFFF; |
4595 | } |
4596 | |
4597 | int be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed, |
4598 | u8 domain) |
4599 | { |
4600 | struct be_nic_res_desc nic_desc; |
4601 | u32 bw_percent; |
4602 | u16 version = 0; |
4603 | |
4604 | if (BE3_chip(adapter)) |
4605 | return be_cmd_set_qos(adapter, bps: max_rate / 10, domain); |
4606 | |
4607 | be_reset_nic_desc(nic: &nic_desc); |
4608 | nic_desc.pf_num = adapter->pf_num; |
4609 | nic_desc.vf_num = domain; |
4610 | nic_desc.bw_min = 0; |
4611 | if (lancer_chip(adapter)) { |
4612 | nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V0; |
4613 | nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V0; |
4614 | nic_desc.flags = (1 << QUN_SHIFT) | (1 << IMM_SHIFT) | |
4615 | (1 << NOSV_SHIFT); |
4616 | nic_desc.bw_max = cpu_to_le32(max_rate / 10); |
4617 | } else { |
4618 | version = 1; |
4619 | nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V1; |
4620 | nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V1; |
4621 | nic_desc.flags = (1 << IMM_SHIFT) | (1 << NOSV_SHIFT); |
4622 | bw_percent = max_rate ? (max_rate * 100) / link_speed : 100; |
4623 | nic_desc.bw_max = cpu_to_le32(bw_percent); |
4624 | } |
4625 | |
4626 | return be_cmd_set_profile_config(adapter, desc: &nic_desc, |
4627 | size: nic_desc.hdr.desc_len, |
4628 | count: 1, version, domain); |
4629 | } |
4630 | |
4631 | int be_cmd_set_sriov_config(struct be_adapter *adapter, |
4632 | struct be_resources pool_res, u16 num_vfs, |
4633 | struct be_resources *vft_res) |
4634 | { |
4635 | struct { |
4636 | struct be_pcie_res_desc pcie; |
4637 | struct be_nic_res_desc nic_vft; |
4638 | } __packed desc; |
4639 | |
4640 | /* PF PCIE descriptor */ |
4641 | be_reset_pcie_desc(pcie: &desc.pcie); |
4642 | desc.pcie.hdr.desc_type = PCIE_RESOURCE_DESC_TYPE_V1; |
4643 | desc.pcie.hdr.desc_len = RESOURCE_DESC_SIZE_V1; |
4644 | desc.pcie.flags = BIT(IMM_SHIFT) | BIT(NOSV_SHIFT); |
4645 | desc.pcie.pf_num = adapter->pdev->devfn; |
4646 | desc.pcie.sriov_state = num_vfs ? 1 : 0; |
4647 | desc.pcie.num_vfs = cpu_to_le16(num_vfs); |
4648 | |
4649 | /* VF NIC Template descriptor */ |
4650 | be_reset_nic_desc(nic: &desc.nic_vft); |
4651 | desc.nic_vft.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V1; |
4652 | desc.nic_vft.hdr.desc_len = RESOURCE_DESC_SIZE_V1; |
4653 | desc.nic_vft.flags = vft_res->flags | BIT(VFT_SHIFT) | |
4654 | BIT(IMM_SHIFT) | BIT(NOSV_SHIFT); |
4655 | desc.nic_vft.pf_num = adapter->pdev->devfn; |
4656 | desc.nic_vft.vf_num = 0; |
4657 | desc.nic_vft.cap_flags = cpu_to_le32(vft_res->vf_if_cap_flags); |
4658 | desc.nic_vft.rq_count = cpu_to_le16(vft_res->max_rx_qs); |
4659 | desc.nic_vft.txq_count = cpu_to_le16(vft_res->max_tx_qs); |
4660 | desc.nic_vft.rssq_count = cpu_to_le16(vft_res->max_rss_qs); |
4661 | desc.nic_vft.cq_count = cpu_to_le16(vft_res->max_cq_count); |
4662 | |
4663 | if (vft_res->max_uc_mac) |
4664 | desc.nic_vft.unicast_mac_count = |
4665 | cpu_to_le16(vft_res->max_uc_mac); |
4666 | if (vft_res->max_vlans) |
4667 | desc.nic_vft.vlan_count = cpu_to_le16(vft_res->max_vlans); |
4668 | if (vft_res->max_iface_count) |
4669 | desc.nic_vft.iface_count = |
4670 | cpu_to_le16(vft_res->max_iface_count); |
4671 | if (vft_res->max_mcc_count) |
4672 | desc.nic_vft.mcc_count = cpu_to_le16(vft_res->max_mcc_count); |
4673 | |
4674 | return be_cmd_set_profile_config(adapter, desc: &desc, |
4675 | size: 2 * RESOURCE_DESC_SIZE_V1, count: 2, version: 1, domain: 0); |
4676 | } |
4677 | |
4678 | int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op) |
4679 | { |
4680 | struct be_mcc_wrb *wrb; |
4681 | struct be_cmd_req_manage_iface_filters *req; |
4682 | int status; |
4683 | |
4684 | if (iface == 0xFFFFFFFF) |
4685 | return -1; |
4686 | |
4687 | mutex_lock(&adapter->mcc_lock); |
4688 | |
4689 | wrb = wrb_from_mccq(adapter); |
4690 | if (!wrb) { |
4691 | status = -EBUSY; |
4692 | goto err; |
4693 | } |
4694 | req = embedded_payload(wrb); |
4695 | |
4696 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4697 | OPCODE_COMMON_MANAGE_IFACE_FILTERS, cmd_len: sizeof(*req), |
4698 | wrb, NULL); |
4699 | req->op = op; |
4700 | req->target_iface_id = cpu_to_le32(iface); |
4701 | |
4702 | status = be_mcc_notify_wait(adapter); |
4703 | err: |
4704 | mutex_unlock(lock: &adapter->mcc_lock); |
4705 | return status; |
4706 | } |
4707 | |
4708 | int be_cmd_set_vxlan_port(struct be_adapter *adapter, __be16 port) |
4709 | { |
4710 | struct be_port_res_desc port_desc; |
4711 | |
4712 | memset(&port_desc, 0, sizeof(port_desc)); |
4713 | port_desc.hdr.desc_type = PORT_RESOURCE_DESC_TYPE_V1; |
4714 | port_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V1; |
4715 | port_desc.flags = (1 << IMM_SHIFT) | (1 << NOSV_SHIFT); |
4716 | port_desc.link_num = adapter->hba_port_num; |
4717 | if (port) { |
4718 | port_desc.nv_flags = NV_TYPE_VXLAN | (1 << SOCVID_SHIFT) | |
4719 | (1 << RCVID_SHIFT); |
4720 | port_desc.nv_port = swab16(port); |
4721 | } else { |
4722 | port_desc.nv_flags = NV_TYPE_DISABLED; |
4723 | port_desc.nv_port = 0; |
4724 | } |
4725 | |
4726 | return be_cmd_set_profile_config(adapter, desc: &port_desc, |
4727 | RESOURCE_DESC_SIZE_V1, count: 1, version: 1, domain: 0); |
4728 | } |
4729 | |
4730 | int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg, |
4731 | int vf_num) |
4732 | { |
4733 | struct be_mcc_wrb *wrb; |
4734 | struct be_cmd_req_get_iface_list *req; |
4735 | struct be_cmd_resp_get_iface_list *resp; |
4736 | int status; |
4737 | |
4738 | mutex_lock(&adapter->mcc_lock); |
4739 | |
4740 | wrb = wrb_from_mccq(adapter); |
4741 | if (!wrb) { |
4742 | status = -EBUSY; |
4743 | goto err; |
4744 | } |
4745 | req = embedded_payload(wrb); |
4746 | |
4747 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4748 | OPCODE_COMMON_GET_IFACE_LIST, cmd_len: sizeof(*resp), |
4749 | wrb, NULL); |
4750 | req->hdr.domain = vf_num + 1; |
4751 | |
4752 | status = be_mcc_notify_wait(adapter); |
4753 | if (!status) { |
4754 | resp = (struct be_cmd_resp_get_iface_list *)req; |
4755 | vf_cfg->if_handle = le32_to_cpu(resp->if_desc.if_id); |
4756 | } |
4757 | |
4758 | err: |
4759 | mutex_unlock(lock: &adapter->mcc_lock); |
4760 | return status; |
4761 | } |
4762 | |
4763 | static int lancer_wait_idle(struct be_adapter *adapter) |
4764 | { |
4765 | #define SLIPORT_IDLE_TIMEOUT 30 |
4766 | u32 reg_val; |
4767 | int status = 0, i; |
4768 | |
4769 | for (i = 0; i < SLIPORT_IDLE_TIMEOUT; i++) { |
4770 | reg_val = ioread32(adapter->db + PHYSDEV_CONTROL_OFFSET); |
4771 | if ((reg_val & PHYSDEV_CONTROL_INP_MASK) == 0) |
4772 | break; |
4773 | |
4774 | ssleep(seconds: 1); |
4775 | } |
4776 | |
4777 | if (i == SLIPORT_IDLE_TIMEOUT) |
4778 | status = -1; |
4779 | |
4780 | return status; |
4781 | } |
4782 | |
4783 | int lancer_physdev_ctrl(struct be_adapter *adapter, u32 mask) |
4784 | { |
4785 | int status = 0; |
4786 | |
4787 | status = lancer_wait_idle(adapter); |
4788 | if (status) |
4789 | return status; |
4790 | |
4791 | iowrite32(mask, adapter->db + PHYSDEV_CONTROL_OFFSET); |
4792 | |
4793 | return status; |
4794 | } |
4795 | |
4796 | /* Routine to check whether dump image is present or not */ |
4797 | bool dump_present(struct be_adapter *adapter) |
4798 | { |
4799 | u32 sliport_status = 0; |
4800 | |
4801 | sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); |
4802 | return !!(sliport_status & SLIPORT_STATUS_DIP_MASK); |
4803 | } |
4804 | |
4805 | int lancer_initiate_dump(struct be_adapter *adapter) |
4806 | { |
4807 | struct device *dev = &adapter->pdev->dev; |
4808 | int status; |
4809 | |
4810 | if (dump_present(adapter)) { |
4811 | dev_info(dev, "Previous dump not cleared, not forcing dump\n" ); |
4812 | return -EEXIST; |
4813 | } |
4814 | |
4815 | /* give firmware reset and diagnostic dump */ |
4816 | status = lancer_physdev_ctrl(adapter, PHYSDEV_CONTROL_FW_RESET_MASK | |
4817 | PHYSDEV_CONTROL_DD_MASK); |
4818 | if (status < 0) { |
4819 | dev_err(dev, "FW reset failed\n" ); |
4820 | return status; |
4821 | } |
4822 | |
4823 | status = lancer_wait_idle(adapter); |
4824 | if (status) |
4825 | return status; |
4826 | |
4827 | if (!dump_present(adapter)) { |
4828 | dev_err(dev, "FW dump not generated\n" ); |
4829 | return -EIO; |
4830 | } |
4831 | |
4832 | return 0; |
4833 | } |
4834 | |
4835 | int lancer_delete_dump(struct be_adapter *adapter) |
4836 | { |
4837 | int status; |
4838 | |
4839 | status = lancer_cmd_delete_object(adapter, LANCER_FW_DUMP_FILE); |
4840 | return be_cmd_status(status); |
4841 | } |
4842 | |
4843 | /* Uses sync mcc */ |
4844 | int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain) |
4845 | { |
4846 | struct be_mcc_wrb *wrb; |
4847 | struct be_cmd_enable_disable_vf *req; |
4848 | int status; |
4849 | |
4850 | if (BEx_chip(adapter)) |
4851 | return 0; |
4852 | |
4853 | mutex_lock(&adapter->mcc_lock); |
4854 | |
4855 | wrb = wrb_from_mccq(adapter); |
4856 | if (!wrb) { |
4857 | status = -EBUSY; |
4858 | goto err; |
4859 | } |
4860 | |
4861 | req = embedded_payload(wrb); |
4862 | |
4863 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4864 | OPCODE_COMMON_ENABLE_DISABLE_VF, cmd_len: sizeof(*req), |
4865 | wrb, NULL); |
4866 | |
4867 | req->hdr.domain = domain; |
4868 | req->enable = 1; |
4869 | status = be_mcc_notify_wait(adapter); |
4870 | err: |
4871 | mutex_unlock(lock: &adapter->mcc_lock); |
4872 | return status; |
4873 | } |
4874 | |
4875 | int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable) |
4876 | { |
4877 | struct be_mcc_wrb *wrb; |
4878 | struct be_cmd_req_intr_set *req; |
4879 | int status; |
4880 | |
4881 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
4882 | return -1; |
4883 | |
4884 | wrb = wrb_from_mbox(adapter); |
4885 | |
4886 | req = embedded_payload(wrb); |
4887 | |
4888 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4889 | OPCODE_COMMON_SET_INTERRUPT_ENABLE, cmd_len: sizeof(*req), |
4890 | wrb, NULL); |
4891 | |
4892 | req->intr_enabled = intr_enable; |
4893 | |
4894 | status = be_mbox_notify_wait(adapter); |
4895 | |
4896 | mutex_unlock(lock: &adapter->mbox_lock); |
4897 | return status; |
4898 | } |
4899 | |
4900 | /* Uses MBOX */ |
4901 | int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile_id) |
4902 | { |
4903 | struct be_cmd_req_get_active_profile *req; |
4904 | struct be_mcc_wrb *wrb; |
4905 | int status; |
4906 | |
4907 | if (mutex_lock_interruptible(&adapter->mbox_lock)) |
4908 | return -1; |
4909 | |
4910 | wrb = wrb_from_mbox(adapter); |
4911 | if (!wrb) { |
4912 | status = -EBUSY; |
4913 | goto err; |
4914 | } |
4915 | |
4916 | req = embedded_payload(wrb); |
4917 | |
4918 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4919 | OPCODE_COMMON_GET_ACTIVE_PROFILE, cmd_len: sizeof(*req), |
4920 | wrb, NULL); |
4921 | |
4922 | status = be_mbox_notify_wait(adapter); |
4923 | if (!status) { |
4924 | struct be_cmd_resp_get_active_profile *resp = |
4925 | embedded_payload(wrb); |
4926 | |
4927 | *profile_id = le16_to_cpu(resp->active_profile_id); |
4928 | } |
4929 | |
4930 | err: |
4931 | mutex_unlock(lock: &adapter->mbox_lock); |
4932 | return status; |
4933 | } |
4934 | |
4935 | static int |
4936 | __be_cmd_set_logical_link_config(struct be_adapter *adapter, |
4937 | int link_state, int version, u8 domain) |
4938 | { |
4939 | struct be_cmd_req_set_ll_link *req; |
4940 | struct be_mcc_wrb *wrb; |
4941 | u32 link_config = 0; |
4942 | int status; |
4943 | |
4944 | mutex_lock(&adapter->mcc_lock); |
4945 | |
4946 | wrb = wrb_from_mccq(adapter); |
4947 | if (!wrb) { |
4948 | status = -EBUSY; |
4949 | goto err; |
4950 | } |
4951 | |
4952 | req = embedded_payload(wrb); |
4953 | |
4954 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
4955 | OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG, |
4956 | cmd_len: sizeof(*req), wrb, NULL); |
4957 | |
4958 | req->hdr.version = version; |
4959 | req->hdr.domain = domain; |
4960 | |
4961 | if (link_state == IFLA_VF_LINK_STATE_ENABLE || |
4962 | link_state == IFLA_VF_LINK_STATE_AUTO) |
4963 | link_config |= PLINK_ENABLE; |
4964 | |
4965 | if (link_state == IFLA_VF_LINK_STATE_AUTO) |
4966 | link_config |= PLINK_TRACK; |
4967 | |
4968 | req->link_config = cpu_to_le32(link_config); |
4969 | |
4970 | status = be_mcc_notify_wait(adapter); |
4971 | err: |
4972 | mutex_unlock(lock: &adapter->mcc_lock); |
4973 | return status; |
4974 | } |
4975 | |
4976 | int be_cmd_set_logical_link_config(struct be_adapter *adapter, |
4977 | int link_state, u8 domain) |
4978 | { |
4979 | int status; |
4980 | |
4981 | if (BE2_chip(adapter)) |
4982 | return -EOPNOTSUPP; |
4983 | |
4984 | status = __be_cmd_set_logical_link_config(adapter, link_state, |
4985 | version: 2, domain); |
4986 | |
4987 | /* Version 2 of the command will not be recognized by older FW. |
4988 | * On such a failure issue version 1 of the command. |
4989 | */ |
4990 | if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST) |
4991 | status = __be_cmd_set_logical_link_config(adapter, link_state, |
4992 | version: 1, domain); |
4993 | return status; |
4994 | } |
4995 | |
4996 | int be_cmd_set_features(struct be_adapter *adapter) |
4997 | { |
4998 | struct be_cmd_resp_set_features *resp; |
4999 | struct be_cmd_req_set_features *req; |
5000 | struct be_mcc_wrb *wrb; |
5001 | int status; |
5002 | |
5003 | if (mutex_lock_interruptible(&adapter->mcc_lock)) |
5004 | return -1; |
5005 | |
5006 | wrb = wrb_from_mccq(adapter); |
5007 | if (!wrb) { |
5008 | status = -EBUSY; |
5009 | goto err; |
5010 | } |
5011 | |
5012 | req = embedded_payload(wrb); |
5013 | |
5014 | be_wrb_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_COMMON, |
5015 | OPCODE_COMMON_SET_FEATURES, |
5016 | cmd_len: sizeof(*req), wrb, NULL); |
5017 | |
5018 | req->features = cpu_to_le32(BE_FEATURE_UE_RECOVERY); |
5019 | req->parameter_len = cpu_to_le32(sizeof(struct be_req_ue_recovery)); |
5020 | req->parameter.req.uer = cpu_to_le32(BE_UE_RECOVERY_UER_MASK); |
5021 | |
5022 | status = be_mcc_notify_wait(adapter); |
5023 | if (status) |
5024 | goto err; |
5025 | |
5026 | resp = embedded_payload(wrb); |
5027 | |
5028 | adapter->error_recovery.ue_to_poll_time = |
5029 | le16_to_cpu(resp->parameter.resp.ue2rp); |
5030 | adapter->error_recovery.ue_to_reset_time = |
5031 | le16_to_cpu(resp->parameter.resp.ue2sr); |
5032 | adapter->error_recovery.recovery_supported = true; |
5033 | err: |
5034 | /* Checking "MCC_STATUS_INVALID_LENGTH" for SKH as FW |
5035 | * returns this error in older firmware versions |
5036 | */ |
5037 | if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST || |
5038 | base_status(status) == MCC_STATUS_INVALID_LENGTH) |
5039 | dev_info(&adapter->pdev->dev, |
5040 | "Adapter does not support HW error recovery\n" ); |
5041 | |
5042 | mutex_unlock(lock: &adapter->mcc_lock); |
5043 | return status; |
5044 | } |
5045 | |
5046 | int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload, |
5047 | int wrb_payload_size, u16 *cmd_status, u16 *ext_status) |
5048 | { |
5049 | struct be_adapter *adapter = netdev_priv(dev: netdev_handle); |
5050 | struct be_mcc_wrb *wrb; |
5051 | struct be_cmd_req_hdr *hdr = (struct be_cmd_req_hdr *)wrb_payload; |
5052 | struct be_cmd_req_hdr *req; |
5053 | struct be_cmd_resp_hdr *resp; |
5054 | int status; |
5055 | |
5056 | mutex_lock(&adapter->mcc_lock); |
5057 | |
5058 | wrb = wrb_from_mccq(adapter); |
5059 | if (!wrb) { |
5060 | status = -EBUSY; |
5061 | goto err; |
5062 | } |
5063 | req = embedded_payload(wrb); |
5064 | resp = embedded_payload(wrb); |
5065 | |
5066 | be_wrb_cmd_hdr_prepare(req_hdr: req, subsystem: hdr->subsystem, |
5067 | opcode: hdr->opcode, cmd_len: wrb_payload_size, wrb, NULL); |
5068 | memcpy(req, wrb_payload, wrb_payload_size); |
5069 | be_dws_cpu_to_le(req, wrb_payload_size); |
5070 | |
5071 | status = be_mcc_notify_wait(adapter); |
5072 | if (cmd_status) |
5073 | *cmd_status = (status & 0xffff); |
5074 | if (ext_status) |
5075 | *ext_status = 0; |
5076 | memcpy(wrb_payload, resp, sizeof(*resp) + resp->response_length); |
5077 | be_dws_le_to_cpu(wrb_payload, sizeof(*resp) + resp->response_length); |
5078 | err: |
5079 | mutex_unlock(lock: &adapter->mcc_lock); |
5080 | return status; |
5081 | } |
5082 | EXPORT_SYMBOL(be_roce_mcc_cmd); |
5083 | |