xref: /freebsd/sys/dev/bnxt/bnxt_hwrm.c (revision 6419bb52)
1 /*-
2  * Broadcom NetXtreme-C/E network driver.
3  *
4  * Copyright (c) 2016 Broadcom, All Rights Reserved.
5  * The term Broadcom refers to Broadcom Limited and/or its subsidiaries
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/endian.h>
33 #include <sys/bitstring.h>
34 
35 #include "bnxt.h"
36 #include "bnxt_hwrm.h"
37 #include "hsi_struct_def.h"
38 
39 static int bnxt_hwrm_err_map(uint16_t err);
40 static inline int _is_valid_ether_addr(uint8_t *);
41 static inline void get_random_ether_addr(uint8_t *);
42 static void	bnxt_hwrm_set_link_common(struct bnxt_softc *softc,
43 		    struct hwrm_port_phy_cfg_input *req);
44 static void	bnxt_hwrm_set_pause_common(struct bnxt_softc *softc,
45 		    struct hwrm_port_phy_cfg_input *req);
46 static void	bnxt_hwrm_set_eee(struct bnxt_softc *softc,
47 		    struct hwrm_port_phy_cfg_input *req);
48 static int	_hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
49 static int	hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
50 static void bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *, void *, uint16_t);
51 
52 /* NVRam stuff has a five minute timeout */
53 #define BNXT_NVM_TIMEO	(5 * 60 * 1000)
54 
55 static int
56 bnxt_hwrm_err_map(uint16_t err)
57 {
58 	int rc;
59 
60 	switch (err) {
61 	case HWRM_ERR_CODE_SUCCESS:
62 		return 0;
63 	case HWRM_ERR_CODE_INVALID_PARAMS:
64 	case HWRM_ERR_CODE_INVALID_FLAGS:
65 	case HWRM_ERR_CODE_INVALID_ENABLES:
66 		return EINVAL;
67 	case HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED:
68 		return EACCES;
69 	case HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR:
70 		return ENOMEM;
71 	case HWRM_ERR_CODE_CMD_NOT_SUPPORTED:
72 		return ENOSYS;
73 	case HWRM_ERR_CODE_FAIL:
74 		return EIO;
75 	case HWRM_ERR_CODE_HWRM_ERROR:
76 	case HWRM_ERR_CODE_UNKNOWN_ERR:
77 	default:
78 		return EDOOFUS;
79 	}
80 
81 	return rc;
82 }
83 
84 int
85 bnxt_alloc_hwrm_dma_mem(struct bnxt_softc *softc)
86 {
87 	int rc;
88 
89 	rc = iflib_dma_alloc(softc->ctx, PAGE_SIZE, &softc->hwrm_cmd_resp,
90 	    BUS_DMA_NOWAIT);
91 	return rc;
92 }
93 
94 void
95 bnxt_free_hwrm_dma_mem(struct bnxt_softc *softc)
96 {
97 	if (softc->hwrm_cmd_resp.idi_vaddr)
98 		iflib_dma_free(&softc->hwrm_cmd_resp);
99 	softc->hwrm_cmd_resp.idi_vaddr = NULL;
100 	return;
101 }
102 
103 static void
104 bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *softc, void *request,
105     uint16_t req_type)
106 {
107 	struct input *req = request;
108 
109 	req->req_type = htole16(req_type);
110 	req->cmpl_ring = 0xffff;
111 	req->target_id = 0xffff;
112 	req->resp_addr = htole64(softc->hwrm_cmd_resp.idi_paddr);
113 }
114 
115 static int
116 _hwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len)
117 {
118 	struct input *req = msg;
119 	struct hwrm_err_output *resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
120 	uint32_t *data = msg;
121 	int i;
122 	uint16_t cp_ring_id;
123 	uint8_t *valid;
124 	uint16_t err;
125 	uint16_t max_req_len = HWRM_MAX_REQ_LEN;
126 	struct hwrm_short_input short_input = {0};
127 
128 	/* TODO: DMASYNC in here. */
129 	req->seq_id = htole16(softc->hwrm_cmd_seq++);
130 	memset(resp, 0, PAGE_SIZE);
131 	cp_ring_id = le16toh(req->cmpl_ring);
132 
133 	if (softc->flags & BNXT_FLAG_SHORT_CMD) {
134 		void *short_cmd_req = softc->hwrm_short_cmd_req_addr.idi_vaddr;
135 
136 		memcpy(short_cmd_req, req, msg_len);
137 		memset((uint8_t *) short_cmd_req + msg_len, 0, softc->hwrm_max_req_len-
138 		    msg_len);
139 
140 		short_input.req_type = req->req_type;
141 		short_input.signature =
142 		    htole16(HWRM_SHORT_INPUT_SIGNATURE_SHORT_CMD);
143 		short_input.size = htole16(msg_len);
144 		short_input.req_addr =
145 		    htole64(softc->hwrm_short_cmd_req_addr.idi_paddr);
146 
147 		data = (uint32_t *)&short_input;
148 		msg_len = sizeof(short_input);
149 
150 		/* Sync memory write before updating doorbell */
151 		wmb();
152 
153 		max_req_len = BNXT_HWRM_SHORT_REQ_LEN;
154 	}
155 
156 	/* Write request msg to hwrm channel */
157 	for (i = 0; i < msg_len; i += 4) {
158 		bus_space_write_4(softc->hwrm_bar.tag,
159 				  softc->hwrm_bar.handle,
160 				  i, *data);
161 		data++;
162 	}
163 
164 	/* Clear to the end of the request buffer */
165 	for (i = msg_len; i < max_req_len; i += 4)
166 		bus_space_write_4(softc->hwrm_bar.tag, softc->hwrm_bar.handle,
167 		    i, 0);
168 
169 	/* Ring channel doorbell */
170 	bus_space_write_4(softc->hwrm_bar.tag,
171 			  softc->hwrm_bar.handle,
172 			  0x100, htole32(1));
173 
174 	/* Check if response len is updated */
175 	for (i = 0; i < softc->hwrm_cmd_timeo; i++) {
176 		if (resp->resp_len && resp->resp_len <= 4096)
177 			break;
178 		DELAY(1000);
179 	}
180 	if (i >= softc->hwrm_cmd_timeo) {
181 		device_printf(softc->dev,
182 		    "Timeout sending %s: (timeout: %u) seq: %d\n",
183 		    GET_HWRM_REQ_TYPE(req->req_type), softc->hwrm_cmd_timeo,
184 		    le16toh(req->seq_id));
185 		return ETIMEDOUT;
186 	}
187 	/* Last byte of resp contains the valid key */
188 	valid = (uint8_t *)resp + resp->resp_len - 1;
189 	for (i = 0; i < softc->hwrm_cmd_timeo; i++) {
190 		if (*valid == HWRM_RESP_VALID_KEY)
191 			break;
192 		DELAY(1000);
193 	}
194 	if (i >= softc->hwrm_cmd_timeo) {
195 		device_printf(softc->dev, "Timeout sending %s: "
196 		    "(timeout: %u) msg {0x%x 0x%x} len:%d v: %d\n",
197 		    GET_HWRM_REQ_TYPE(req->req_type),
198 		    softc->hwrm_cmd_timeo, le16toh(req->req_type),
199 		    le16toh(req->seq_id), msg_len,
200 		    *valid);
201 		return ETIMEDOUT;
202 	}
203 
204 	err = le16toh(resp->error_code);
205 	if (err) {
206 		/* HWRM_ERR_CODE_FAIL is a "normal" error, don't log */
207 		if (err != HWRM_ERR_CODE_FAIL) {
208 			device_printf(softc->dev,
209 			    "%s command returned %s error.\n",
210 			    GET_HWRM_REQ_TYPE(req->req_type),
211 			    GET_HWRM_ERROR_CODE(err));
212 		}
213 		return bnxt_hwrm_err_map(err);
214 	}
215 
216 	return 0;
217 }
218 
219 static int
220 hwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len)
221 {
222 	int rc;
223 
224 	BNXT_HWRM_LOCK(softc);
225 	rc = _hwrm_send_message(softc, msg, msg_len);
226 	BNXT_HWRM_UNLOCK(softc);
227 	return rc;
228 }
229 
230 int
231 bnxt_hwrm_queue_qportcfg(struct bnxt_softc *softc)
232 {
233 	struct hwrm_queue_qportcfg_input req = {0};
234 	struct hwrm_queue_qportcfg_output *resp =
235 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
236 
237 	int	rc = 0;
238 	uint8_t	*qptr;
239 
240 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_QPORTCFG);
241 
242 	BNXT_HWRM_LOCK(softc);
243 	rc = _hwrm_send_message(softc, &req, sizeof(req));
244 	if (rc)
245 		goto qportcfg_exit;
246 
247 	if (!resp->max_configurable_queues) {
248 		rc = -EINVAL;
249 		goto qportcfg_exit;
250 	}
251 	softc->max_tc = resp->max_configurable_queues;
252 	if (softc->max_tc > BNXT_MAX_QUEUE)
253 		softc->max_tc = BNXT_MAX_QUEUE;
254 
255 	qptr = &resp->queue_id0;
256 	for (int i = 0; i < softc->max_tc; i++) {
257 		softc->q_info[i].id = *qptr++;
258 		softc->q_info[i].profile = *qptr++;
259 	}
260 
261 qportcfg_exit:
262 	BNXT_HWRM_UNLOCK(softc);
263 	return (rc);
264 }
265 
266 
267 int
268 bnxt_hwrm_ver_get(struct bnxt_softc *softc)
269 {
270 	struct hwrm_ver_get_input	req = {0};
271 	struct hwrm_ver_get_output	*resp =
272 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
273 	int				rc;
274 	const char nastr[] = "<not installed>";
275 	const char naver[] = "<N/A>";
276 	uint32_t dev_caps_cfg;
277 
278 	softc->hwrm_max_req_len = HWRM_MAX_REQ_LEN;
279 	softc->hwrm_cmd_timeo = 1000;
280 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VER_GET);
281 
282 	req.hwrm_intf_maj = HWRM_VERSION_MAJOR;
283 	req.hwrm_intf_min = HWRM_VERSION_MINOR;
284 	req.hwrm_intf_upd = HWRM_VERSION_UPDATE;
285 
286 	BNXT_HWRM_LOCK(softc);
287 	rc = _hwrm_send_message(softc, &req, sizeof(req));
288 	if (rc)
289 		goto fail;
290 
291 	snprintf(softc->ver_info->hwrm_if_ver, BNXT_VERSTR_SIZE, "%d.%d.%d",
292 	    resp->hwrm_intf_maj, resp->hwrm_intf_min, resp->hwrm_intf_upd);
293 	softc->ver_info->hwrm_if_major = resp->hwrm_intf_maj;
294 	softc->ver_info->hwrm_if_minor = resp->hwrm_intf_min;
295 	softc->ver_info->hwrm_if_update = resp->hwrm_intf_upd;
296 	snprintf(softc->ver_info->hwrm_fw_ver, BNXT_VERSTR_SIZE, "%d.%d.%d",
297 	    resp->hwrm_fw_maj, resp->hwrm_fw_min, resp->hwrm_fw_bld);
298 	strlcpy(softc->ver_info->driver_hwrm_if_ver, HWRM_VERSION_STR,
299 	    BNXT_VERSTR_SIZE);
300 	strlcpy(softc->ver_info->hwrm_fw_name, resp->hwrm_fw_name,
301 	    BNXT_NAME_SIZE);
302 
303 	if (resp->mgmt_fw_maj == 0 && resp->mgmt_fw_min == 0 &&
304 	    resp->mgmt_fw_bld == 0) {
305 		strlcpy(softc->ver_info->mgmt_fw_ver, naver, BNXT_VERSTR_SIZE);
306 		strlcpy(softc->ver_info->mgmt_fw_name, nastr, BNXT_NAME_SIZE);
307 	}
308 	else {
309 		snprintf(softc->ver_info->mgmt_fw_ver, BNXT_VERSTR_SIZE,
310 		    "%d.%d.%d", resp->mgmt_fw_maj, resp->mgmt_fw_min,
311 		    resp->mgmt_fw_bld);
312 		strlcpy(softc->ver_info->mgmt_fw_name, resp->mgmt_fw_name,
313 		    BNXT_NAME_SIZE);
314 	}
315 	if (resp->netctrl_fw_maj == 0 && resp->netctrl_fw_min == 0 &&
316 	    resp->netctrl_fw_bld == 0) {
317 		strlcpy(softc->ver_info->netctrl_fw_ver, naver,
318 		    BNXT_VERSTR_SIZE);
319 		strlcpy(softc->ver_info->netctrl_fw_name, nastr,
320 		    BNXT_NAME_SIZE);
321 	}
322 	else {
323 		snprintf(softc->ver_info->netctrl_fw_ver, BNXT_VERSTR_SIZE,
324 		    "%d.%d.%d", resp->netctrl_fw_maj, resp->netctrl_fw_min,
325 		    resp->netctrl_fw_bld);
326 		strlcpy(softc->ver_info->netctrl_fw_name, resp->netctrl_fw_name,
327 		    BNXT_NAME_SIZE);
328 	}
329 	if (resp->roce_fw_maj == 0 && resp->roce_fw_min == 0 &&
330 	    resp->roce_fw_bld == 0) {
331 		strlcpy(softc->ver_info->roce_fw_ver, naver, BNXT_VERSTR_SIZE);
332 		strlcpy(softc->ver_info->roce_fw_name, nastr, BNXT_NAME_SIZE);
333 	}
334 	else {
335 		snprintf(softc->ver_info->roce_fw_ver, BNXT_VERSTR_SIZE,
336 		    "%d.%d.%d", resp->roce_fw_maj, resp->roce_fw_min,
337 		    resp->roce_fw_bld);
338 		strlcpy(softc->ver_info->roce_fw_name, resp->roce_fw_name,
339 		    BNXT_NAME_SIZE);
340 	}
341 	softc->ver_info->chip_num = le16toh(resp->chip_num);
342 	softc->ver_info->chip_rev = resp->chip_rev;
343 	softc->ver_info->chip_metal = resp->chip_metal;
344 	softc->ver_info->chip_bond_id = resp->chip_bond_id;
345 	softc->ver_info->chip_type = resp->chip_platform_type;
346 
347 	if (resp->max_req_win_len)
348 		softc->hwrm_max_req_len = le16toh(resp->max_req_win_len);
349 	if (resp->def_req_timeout)
350 		softc->hwrm_cmd_timeo = le16toh(resp->def_req_timeout);
351 
352 	dev_caps_cfg = le32toh(resp->dev_caps_cfg);
353 	if ((dev_caps_cfg & HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED) &&
354 	    (dev_caps_cfg & HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_REQUIRED))
355 		softc->flags |= BNXT_FLAG_SHORT_CMD;
356 
357 fail:
358 	BNXT_HWRM_UNLOCK(softc);
359 	return rc;
360 }
361 
362 int
363 bnxt_hwrm_func_drv_rgtr(struct bnxt_softc *softc)
364 {
365 	struct hwrm_func_drv_rgtr_input req = {0};
366 
367 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR);
368 
369 	req.enables = htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_VER |
370 	    HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_OS_TYPE);
371 	req.os_type = htole16(HWRM_FUNC_DRV_RGTR_INPUT_OS_TYPE_FREEBSD);
372 
373 	req.ver_maj = __FreeBSD_version / 100000;
374 	req.ver_min = (__FreeBSD_version / 1000) % 100;
375 	req.ver_upd = (__FreeBSD_version / 100) % 10;
376 
377 	return hwrm_send_message(softc, &req, sizeof(req));
378 }
379 
380 
381 int
382 bnxt_hwrm_func_drv_unrgtr(struct bnxt_softc *softc, bool shutdown)
383 {
384 	struct hwrm_func_drv_unrgtr_input req = {0};
385 
386 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_UNRGTR);
387 	if (shutdown == true)
388 		req.flags |=
389 		    HWRM_FUNC_DRV_UNRGTR_INPUT_FLAGS_PREPARE_FOR_SHUTDOWN;
390 	return hwrm_send_message(softc, &req, sizeof(req));
391 }
392 
393 
394 static inline int
395 _is_valid_ether_addr(uint8_t *addr)
396 {
397 	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
398 
399 	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
400 		return (FALSE);
401 
402 	return (TRUE);
403 }
404 
405 static inline void
406 get_random_ether_addr(uint8_t *addr)
407 {
408 	uint8_t temp[ETHER_ADDR_LEN];
409 
410 	arc4rand(&temp, sizeof(temp), 0);
411 	temp[0] &= 0xFE;
412 	temp[0] |= 0x02;
413 	bcopy(temp, addr, sizeof(temp));
414 }
415 
416 int
417 bnxt_hwrm_func_qcaps(struct bnxt_softc *softc)
418 {
419 	int rc = 0;
420 	struct hwrm_func_qcaps_input req = {0};
421 	struct hwrm_func_qcaps_output *resp =
422 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
423 	struct bnxt_func_info *func = &softc->func;
424 
425 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCAPS);
426 	req.fid = htole16(0xffff);
427 
428 	BNXT_HWRM_LOCK(softc);
429 	rc = _hwrm_send_message(softc, &req, sizeof(req));
430 	if (rc)
431 		goto fail;
432 
433 	if (resp->flags &
434 	    htole32(HWRM_FUNC_QCAPS_OUTPUT_FLAGS_WOL_MAGICPKT_SUPPORTED))
435 		softc->flags |= BNXT_FLAG_WOL_CAP;
436 
437 	func->fw_fid = le16toh(resp->fid);
438 	memcpy(func->mac_addr, resp->mac_address, ETHER_ADDR_LEN);
439 	func->max_rsscos_ctxs = le16toh(resp->max_rsscos_ctx);
440 	func->max_cp_rings = le16toh(resp->max_cmpl_rings);
441 	func->max_tx_rings = le16toh(resp->max_tx_rings);
442 	func->max_rx_rings = le16toh(resp->max_rx_rings);
443 	func->max_hw_ring_grps = le32toh(resp->max_hw_ring_grps);
444 	if (!func->max_hw_ring_grps)
445 		func->max_hw_ring_grps = func->max_tx_rings;
446 	func->max_l2_ctxs = le16toh(resp->max_l2_ctxs);
447 	func->max_vnics = le16toh(resp->max_vnics);
448 	func->max_stat_ctxs = le16toh(resp->max_stat_ctx);
449 	if (BNXT_PF(softc)) {
450 		struct bnxt_pf_info *pf = &softc->pf;
451 
452 		pf->port_id = le16toh(resp->port_id);
453 		pf->first_vf_id = le16toh(resp->first_vf_id);
454 		pf->max_vfs = le16toh(resp->max_vfs);
455 		pf->max_encap_records = le32toh(resp->max_encap_records);
456 		pf->max_decap_records = le32toh(resp->max_decap_records);
457 		pf->max_tx_em_flows = le32toh(resp->max_tx_em_flows);
458 		pf->max_tx_wm_flows = le32toh(resp->max_tx_wm_flows);
459 		pf->max_rx_em_flows = le32toh(resp->max_rx_em_flows);
460 		pf->max_rx_wm_flows = le32toh(resp->max_rx_wm_flows);
461 	}
462 	if (!_is_valid_ether_addr(func->mac_addr)) {
463 		device_printf(softc->dev, "Invalid ethernet address, generating random locally administered address\n");
464 		get_random_ether_addr(func->mac_addr);
465 	}
466 
467 fail:
468 	BNXT_HWRM_UNLOCK(softc);
469 	return rc;
470 }
471 
472 int
473 bnxt_hwrm_func_qcfg(struct bnxt_softc *softc)
474 {
475         struct hwrm_func_qcfg_input req = {0};
476         struct hwrm_func_qcfg_output *resp =
477 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
478 	struct bnxt_func_qcfg *fn_qcfg = &softc->fn_qcfg;
479         int rc;
480 
481 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCFG);
482         req.fid = htole16(0xffff);
483 	BNXT_HWRM_LOCK(softc);
484 	rc = _hwrm_send_message(softc, &req, sizeof(req));
485         if (rc)
486 		goto fail;
487 
488 	fn_qcfg->alloc_completion_rings = le16toh(resp->alloc_cmpl_rings);
489 	fn_qcfg->alloc_tx_rings = le16toh(resp->alloc_tx_rings);
490 	fn_qcfg->alloc_rx_rings = le16toh(resp->alloc_rx_rings);
491 	fn_qcfg->alloc_vnics = le16toh(resp->alloc_vnics);
492 fail:
493 	BNXT_HWRM_UNLOCK(softc);
494         return rc;
495 }
496 
497 int
498 bnxt_hwrm_func_reset(struct bnxt_softc *softc)
499 {
500 	struct hwrm_func_reset_input req = {0};
501 
502 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_RESET);
503 	req.enables = 0;
504 
505 	return hwrm_send_message(softc, &req, sizeof(req));
506 }
507 
508 static void
509 bnxt_hwrm_set_link_common(struct bnxt_softc *softc,
510     struct hwrm_port_phy_cfg_input *req)
511 {
512 	uint8_t autoneg = softc->link_info.autoneg;
513 	uint16_t fw_link_speed = softc->link_info.req_link_speed;
514 
515 	if (autoneg & BNXT_AUTONEG_SPEED) {
516 		req->auto_mode |=
517 		    HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_ALL_SPEEDS;
518 
519 		req->enables |=
520 		    htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE);
521 		req->flags |=
522 		    htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG);
523 	} else {
524 		req->force_link_speed = htole16(fw_link_speed);
525 		req->flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE);
526 	}
527 
528 	/* tell chimp that the setting takes effect immediately */
529 	req->flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESET_PHY);
530 }
531 
532 
533 static void
534 bnxt_hwrm_set_pause_common(struct bnxt_softc *softc,
535     struct hwrm_port_phy_cfg_input *req)
536 {
537 	struct bnxt_link_info *link_info = &softc->link_info;
538 
539 	if (link_info->flow_ctrl.autoneg) {
540 		req->auto_pause =
541 		    HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_AUTONEG_PAUSE;
542 		if (link_info->flow_ctrl.rx)
543 			req->auto_pause |=
544 			    HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_RX;
545 		if (link_info->flow_ctrl.tx)
546 			req->auto_pause |=
547 			    HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_TX;
548 		req->enables |=
549 		    htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_PAUSE);
550 	} else {
551 		if (link_info->flow_ctrl.rx)
552 			req->force_pause |=
553 			    HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_RX;
554 		if (link_info->flow_ctrl.tx)
555 			req->force_pause |=
556 			    HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_TX;
557 		req->enables |=
558 			htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_FORCE_PAUSE);
559 	}
560 }
561 
562 
563 /* JFV this needs interface connection */
564 static void
565 bnxt_hwrm_set_eee(struct bnxt_softc *softc, struct hwrm_port_phy_cfg_input *req)
566 {
567 	/* struct ethtool_eee *eee = &softc->eee; */
568 	bool	eee_enabled = false;
569 
570 	if (eee_enabled) {
571 #if 0
572 		uint16_t eee_speeds;
573 		uint32_t flags = HWRM_PORT_PHY_CFG_INPUT_FLAGS_EEE_ENABLE;
574 
575 		if (eee->tx_lpi_enabled)
576 			flags |= HWRM_PORT_PHY_CFG_INPUT_FLAGS_EEE_TX_LPI;
577 
578 		req->flags |= htole32(flags);
579 		eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised);
580 		req->eee_link_speed_mask = htole16(eee_speeds);
581 		req->tx_lpi_timer = htole32(eee->tx_lpi_timer);
582 #endif
583 	} else {
584 		req->flags |=
585 		    htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_EEE_DISABLE);
586 	}
587 }
588 
589 
590 int
591 bnxt_hwrm_set_link_setting(struct bnxt_softc *softc, bool set_pause,
592     bool set_eee, bool set_link)
593 {
594 	struct hwrm_port_phy_cfg_input req = {0};
595 	int rc;
596 
597 	if (softc->flags & BNXT_FLAG_NPAR)
598 		return ENOTSUP;
599 
600 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_CFG);
601 
602 	if (set_pause) {
603 		bnxt_hwrm_set_pause_common(softc, &req);
604 
605 		if (softc->link_info.flow_ctrl.autoneg)
606 			set_link = true;
607 	}
608 
609 	if (set_link)
610 		bnxt_hwrm_set_link_common(softc, &req);
611 
612 	if (set_eee)
613 		bnxt_hwrm_set_eee(softc, &req);
614 
615 	BNXT_HWRM_LOCK(softc);
616 	rc = _hwrm_send_message(softc, &req, sizeof(req));
617 
618 	if (!rc) {
619 		if (set_pause) {
620 			/* since changing of 'force pause' setting doesn't
621 			 * trigger any link change event, the driver needs to
622 			 * update the current pause result upon successfully i
623 			 * return of the phy_cfg command */
624 			if (!softc->link_info.flow_ctrl.autoneg)
625 				bnxt_report_link(softc);
626 		}
627 	}
628 	BNXT_HWRM_UNLOCK(softc);
629 	return rc;
630 }
631 
632 int
633 bnxt_hwrm_vnic_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
634 {
635 	struct hwrm_vnic_cfg_input req = {0};
636 
637 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_CFG);
638 
639 	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
640 		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_DEFAULT);
641 	if (vnic->flags & BNXT_VNIC_FLAG_BD_STALL)
642 		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_BD_STALL_MODE);
643 	if (vnic->flags & BNXT_VNIC_FLAG_VLAN_STRIP)
644 		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_VLAN_STRIP_MODE);
645 	req.enables = htole32(HWRM_VNIC_CFG_INPUT_ENABLES_DFLT_RING_GRP |
646 	    HWRM_VNIC_CFG_INPUT_ENABLES_RSS_RULE |
647 	    HWRM_VNIC_CFG_INPUT_ENABLES_MRU);
648 	req.vnic_id = htole16(vnic->id);
649 	req.dflt_ring_grp = htole16(vnic->def_ring_grp);
650 	req.rss_rule = htole16(vnic->rss_id);
651 	req.cos_rule = htole16(vnic->cos_rule);
652 	req.lb_rule = htole16(vnic->lb_rule);
653 	req.mru = htole16(vnic->mru);
654 
655 	return hwrm_send_message(softc, &req, sizeof(req));
656 }
657 
658 int
659 bnxt_hwrm_vnic_alloc(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
660 {
661 	struct hwrm_vnic_alloc_input req = {0};
662 	struct hwrm_vnic_alloc_output *resp =
663 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
664 	int rc;
665 
666 	if (vnic->id != (uint16_t)HWRM_NA_SIGNATURE) {
667 		device_printf(softc->dev,
668 		    "Attempt to re-allocate vnic %04x\n", vnic->id);
669 		return EDOOFUS;
670 	}
671 
672 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_ALLOC);
673 
674 	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
675 		req.flags = htole32(HWRM_VNIC_ALLOC_INPUT_FLAGS_DEFAULT);
676 
677 	BNXT_HWRM_LOCK(softc);
678 	rc = _hwrm_send_message(softc, &req, sizeof(req));
679 	if (rc)
680 		goto fail;
681 
682 	vnic->id = le32toh(resp->vnic_id);
683 
684 fail:
685 	BNXT_HWRM_UNLOCK(softc);
686 	return (rc);
687 }
688 
689 int
690 bnxt_hwrm_vnic_ctx_alloc(struct bnxt_softc *softc, uint16_t *ctx_id)
691 {
692 	struct hwrm_vnic_rss_cos_lb_ctx_alloc_input req = {0};
693 	struct hwrm_vnic_rss_cos_lb_ctx_alloc_output *resp =
694 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
695 	int rc;
696 
697 	if (*ctx_id != (uint16_t)HWRM_NA_SIGNATURE) {
698 		device_printf(softc->dev,
699 		    "Attempt to re-allocate vnic ctx %04x\n", *ctx_id);
700 		return EDOOFUS;
701 	}
702 
703 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_COS_LB_CTX_ALLOC);
704 
705 	BNXT_HWRM_LOCK(softc);
706 	rc = _hwrm_send_message(softc, &req, sizeof(req));
707 	if (rc)
708 		goto fail;
709 
710 	*ctx_id = le32toh(resp->rss_cos_lb_ctx_id);
711 
712 fail:
713 	BNXT_HWRM_UNLOCK(softc);
714 	return (rc);
715 }
716 
717 int
718 bnxt_hwrm_ring_grp_alloc(struct bnxt_softc *softc, struct bnxt_grp_info *grp)
719 {
720 	struct hwrm_ring_grp_alloc_input req = {0};
721 	struct hwrm_ring_grp_alloc_output *resp;
722 	int rc = 0;
723 
724 	if (grp->grp_id != (uint16_t)HWRM_NA_SIGNATURE) {
725 		device_printf(softc->dev,
726 		    "Attempt to re-allocate ring group %04x\n", grp->grp_id);
727 		return EDOOFUS;
728 	}
729 
730 	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
731 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_GRP_ALLOC);
732 	req.cr = htole16(grp->cp_ring_id);
733 	req.rr = htole16(grp->rx_ring_id);
734 	req.ar = htole16(grp->ag_ring_id);
735 	req.sc = htole16(grp->stats_ctx);
736 
737 	BNXT_HWRM_LOCK(softc);
738 	rc = _hwrm_send_message(softc, &req, sizeof(req));
739 	if (rc)
740 		goto fail;
741 
742 	grp->grp_id = le32toh(resp->ring_group_id);
743 
744 fail:
745 	BNXT_HWRM_UNLOCK(softc);
746 	return rc;
747 }
748 
749 /*
750  * Ring allocation message to the firmware
751  */
752 int
753 bnxt_hwrm_ring_alloc(struct bnxt_softc *softc, uint8_t type,
754     struct bnxt_ring *ring, uint16_t cmpl_ring_id, uint32_t stat_ctx_id,
755     bool irq)
756 {
757 	struct hwrm_ring_alloc_input req = {0};
758 	struct hwrm_ring_alloc_output *resp;
759 	int rc;
760 
761 	if (ring->phys_id != (uint16_t)HWRM_NA_SIGNATURE) {
762 		device_printf(softc->dev,
763 		    "Attempt to re-allocate ring %04x\n", ring->phys_id);
764 		return EDOOFUS;
765 	}
766 
767 	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
768 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_ALLOC);
769 	req.enables = htole32(0);
770 	req.fbo = htole32(0);
771 
772 	if (stat_ctx_id != HWRM_NA_SIGNATURE) {
773 		req.enables |= htole32(
774 		    HWRM_RING_ALLOC_INPUT_ENABLES_STAT_CTX_ID_VALID);
775 		req.stat_ctx_id = htole32(stat_ctx_id);
776 	}
777 	req.ring_type = type;
778 	req.page_tbl_addr = htole64(ring->paddr);
779 	req.length = htole32(ring->ring_size);
780 	req.logical_id = htole16(ring->id);
781 	req.cmpl_ring_id = htole16(cmpl_ring_id);
782 	req.queue_id = htole16(softc->q_info[0].id);
783 #if 0
784 	/* MODE_POLL appears to crash the firmware */
785 	if (irq)
786 		req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX;
787 	else
788 		req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_POLL;
789 #else
790 	req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX;
791 #endif
792 	BNXT_HWRM_LOCK(softc);
793 	rc = _hwrm_send_message(softc, &req, sizeof(req));
794 	if (rc)
795 		goto fail;
796 
797 	ring->phys_id = le16toh(resp->ring_id);
798 
799 fail:
800 	BNXT_HWRM_UNLOCK(softc);
801 	return rc;
802 }
803 
804 int
805 bnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr,
806     uint64_t paddr)
807 {
808 	struct hwrm_stat_ctx_alloc_input req = {0};
809 	struct hwrm_stat_ctx_alloc_output *resp;
810 	int rc = 0;
811 
812 	if (cpr->stats_ctx_id != HWRM_NA_SIGNATURE) {
813 		device_printf(softc->dev,
814 		    "Attempt to re-allocate stats ctx %08x\n",
815 		    cpr->stats_ctx_id);
816 		return EDOOFUS;
817 	}
818 
819 	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
820 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_STAT_CTX_ALLOC);
821 
822 	req.update_period_ms = htole32(1000);
823 	req.stats_dma_addr = htole64(paddr);
824 
825 	BNXT_HWRM_LOCK(softc);
826 	rc = _hwrm_send_message(softc, &req, sizeof(req));
827 	if (rc)
828 		goto fail;
829 
830 	cpr->stats_ctx_id = le32toh(resp->stat_ctx_id);
831 
832 fail:
833 	BNXT_HWRM_UNLOCK(softc);
834 
835 	return rc;
836 }
837 
838 int
839 bnxt_hwrm_port_qstats(struct bnxt_softc *softc)
840 {
841 	struct hwrm_port_qstats_input req = {0};
842 	int rc = 0;
843 
844 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_QSTATS);
845 
846 	req.port_id = htole16(softc->pf.port_id);
847 	req.rx_stat_host_addr = htole64(softc->hw_rx_port_stats.idi_paddr);
848 	req.tx_stat_host_addr = htole64(softc->hw_tx_port_stats.idi_paddr);
849 
850 	BNXT_HWRM_LOCK(softc);
851 	rc = _hwrm_send_message(softc, &req, sizeof(req));
852 	BNXT_HWRM_UNLOCK(softc);
853 
854 	return rc;
855 }
856 
857 int
858 bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt_softc *softc,
859     struct bnxt_vnic_info *vnic)
860 {
861 	struct hwrm_cfa_l2_set_rx_mask_input req = {0};
862 	struct bnxt_vlan_tag *tag;
863 	uint32_t *tags;
864 	uint32_t num_vlan_tags = 0;
865 	uint32_t i;
866 	uint32_t mask = vnic->rx_mask;
867 	int rc;
868 
869 	SLIST_FOREACH(tag, &vnic->vlan_tags, next)
870 		num_vlan_tags++;
871 
872 	if (num_vlan_tags) {
873 		if (!(mask &
874 		    HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ANYVLAN_NONVLAN)) {
875 			if (!vnic->vlan_only)
876 				mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLAN_NONVLAN;
877 			else
878 				mask |=
879 				    HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLANONLY;
880 		}
881 		if (vnic->vlan_tag_list.idi_vaddr) {
882 			iflib_dma_free(&vnic->vlan_tag_list);
883 			vnic->vlan_tag_list.idi_vaddr = NULL;
884 		}
885 		rc = iflib_dma_alloc(softc->ctx, 4 * num_vlan_tags,
886 		    &vnic->vlan_tag_list, BUS_DMA_NOWAIT);
887 		if (rc)
888 			return rc;
889 		tags = (uint32_t *)vnic->vlan_tag_list.idi_vaddr;
890 
891 		i = 0;
892 		SLIST_FOREACH(tag, &vnic->vlan_tags, next) {
893 			tags[i] = htole32((tag->tpid << 16) | tag->tag);
894 			i++;
895 		}
896 	}
897 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_SET_RX_MASK);
898 
899 	req.vnic_id = htole32(vnic->id);
900 	req.mask = htole32(mask);
901 	req.mc_tbl_addr = htole64(vnic->mc_list.idi_paddr);
902 	req.num_mc_entries = htole32(vnic->mc_list_count);
903 	req.vlan_tag_tbl_addr = htole64(vnic->vlan_tag_list.idi_paddr);
904 	req.num_vlan_tags = htole32(num_vlan_tags);
905 	return hwrm_send_message(softc, &req, sizeof(req));
906 }
907 
908 
909 int
910 bnxt_hwrm_set_filter(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
911 {
912 	struct hwrm_cfa_l2_filter_alloc_input	req = {0};
913 	struct hwrm_cfa_l2_filter_alloc_output	*resp;
914 	uint32_t enables = 0;
915 	int rc = 0;
916 
917 	if (vnic->filter_id != -1) {
918 		device_printf(softc->dev,
919 		    "Attempt to re-allocate l2 ctx filter\n");
920 		return EDOOFUS;
921 	}
922 
923 	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
924 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_FILTER_ALLOC);
925 
926 	req.flags = htole32(HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX);
927 	enables = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR
928 	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR_MASK
929 	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_DST_ID;
930 	req.enables = htole32(enables);
931 	req.dst_id = htole16(vnic->id);
932 	memcpy(req.l2_addr, if_getlladdr(iflib_get_ifp(softc->ctx)),
933 	    ETHER_ADDR_LEN);
934 	memset(&req.l2_addr_mask, 0xff, sizeof(req.l2_addr_mask));
935 
936 	BNXT_HWRM_LOCK(softc);
937 	rc = _hwrm_send_message(softc, &req, sizeof(req));
938 	if (rc)
939 		goto fail;
940 
941 	vnic->filter_id = le64toh(resp->l2_filter_id);
942 	vnic->flow_id = le64toh(resp->flow_id);
943 
944 fail:
945 	BNXT_HWRM_UNLOCK(softc);
946 	return (rc);
947 }
948 
949 int
950 bnxt_hwrm_rss_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic,
951     uint32_t hash_type)
952 {
953 	struct hwrm_vnic_rss_cfg_input	req = {0};
954 
955 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_CFG);
956 
957 	req.hash_type = htole32(hash_type);
958 	req.ring_grp_tbl_addr = htole64(vnic->rss_grp_tbl.idi_paddr);
959 	req.hash_key_tbl_addr = htole64(vnic->rss_hash_key_tbl.idi_paddr);
960 	req.rss_ctx_idx = htole16(vnic->rss_id);
961 
962 	return hwrm_send_message(softc, &req, sizeof(req));
963 }
964 
965 int
966 bnxt_cfg_async_cr(struct bnxt_softc *softc)
967 {
968 	int rc = 0;
969 
970 	if (BNXT_PF(softc)) {
971 		struct hwrm_func_cfg_input req = {0};
972 
973 		bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
974 
975 		req.fid = htole16(0xffff);
976 		req.enables = htole32(HWRM_FUNC_CFG_INPUT_ENABLES_ASYNC_EVENT_CR);
977 		req.async_event_cr = htole16(softc->def_cp_ring.ring.phys_id);
978 
979 		rc = hwrm_send_message(softc, &req, sizeof(req));
980 	}
981 	else {
982 		struct hwrm_func_vf_cfg_input req = {0};
983 
984 		bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_VF_CFG);
985 
986 		req.enables = htole32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_ASYNC_EVENT_CR);
987 		req.async_event_cr = htole16(softc->def_cp_ring.ring.phys_id);
988 
989 		rc = hwrm_send_message(softc, &req, sizeof(req));
990 	}
991 	return rc;
992 }
993 
994 void
995 bnxt_validate_hw_lro_settings(struct bnxt_softc *softc)
996 {
997 	softc->hw_lro.enable = min(softc->hw_lro.enable, 1);
998 
999         softc->hw_lro.is_mode_gro = min(softc->hw_lro.is_mode_gro, 1);
1000 
1001 	softc->hw_lro.max_agg_segs = min(softc->hw_lro.max_agg_segs,
1002 		HWRM_VNIC_TPA_CFG_INPUT_MAX_AGG_SEGS_MAX);
1003 
1004 	softc->hw_lro.max_aggs = min(softc->hw_lro.max_aggs,
1005 		HWRM_VNIC_TPA_CFG_INPUT_MAX_AGGS_MAX);
1006 
1007 	softc->hw_lro.min_agg_len = min(softc->hw_lro.min_agg_len, BNXT_MAX_MTU);
1008 }
1009 
1010 int
1011 bnxt_hwrm_vnic_tpa_cfg(struct bnxt_softc *softc)
1012 {
1013 	struct hwrm_vnic_tpa_cfg_input req = {0};
1014 	uint32_t flags;
1015 
1016 	if (softc->vnic_info.id == (uint16_t) HWRM_NA_SIGNATURE) {
1017 		return 0;
1018 	}
1019 
1020 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_TPA_CFG);
1021 
1022 	if (softc->hw_lro.enable) {
1023 		flags = HWRM_VNIC_TPA_CFG_INPUT_FLAGS_TPA |
1024 			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_ENCAP_TPA |
1025 			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_ECN |
1026 			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_SAME_GRE_SEQ;
1027 
1028         	if (softc->hw_lro.is_mode_gro)
1029 			flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_GRO;
1030 		else
1031 			flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_RSC_WND_UPDATE;
1032 
1033 		req.flags = htole32(flags);
1034 
1035 		req.enables = htole32(HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGG_SEGS |
1036 				HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGGS |
1037 				HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MIN_AGG_LEN);
1038 
1039 		req.max_agg_segs = htole16(softc->hw_lro.max_agg_segs);
1040 		req.max_aggs = htole16(softc->hw_lro.max_aggs);
1041 		req.min_agg_len = htole32(softc->hw_lro.min_agg_len);
1042 	}
1043 
1044 	req.vnic_id = htole16(softc->vnic_info.id);
1045 
1046 	return hwrm_send_message(softc, &req, sizeof(req));
1047 }
1048 
1049 int
1050 bnxt_hwrm_nvm_find_dir_entry(struct bnxt_softc *softc, uint16_t type,
1051     uint16_t *ordinal, uint16_t ext, uint16_t *index, bool use_index,
1052     uint8_t search_opt, uint32_t *data_length, uint32_t *item_length,
1053     uint32_t *fw_ver)
1054 {
1055 	struct hwrm_nvm_find_dir_entry_input req = {0};
1056 	struct hwrm_nvm_find_dir_entry_output *resp =
1057 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1058 	int	rc = 0;
1059 	uint32_t old_timeo;
1060 
1061 	MPASS(ordinal);
1062 
1063 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_FIND_DIR_ENTRY);
1064 	if (use_index) {
1065 		req.enables = htole32(
1066 		    HWRM_NVM_FIND_DIR_ENTRY_INPUT_ENABLES_DIR_IDX_VALID);
1067 		req.dir_idx = htole16(*index);
1068 	}
1069 	req.dir_type = htole16(type);
1070 	req.dir_ordinal = htole16(*ordinal);
1071 	req.dir_ext = htole16(ext);
1072 	req.opt_ordinal = search_opt;
1073 
1074 	BNXT_HWRM_LOCK(softc);
1075 	old_timeo = softc->hwrm_cmd_timeo;
1076 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1077 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1078 	softc->hwrm_cmd_timeo = old_timeo;
1079 	if (rc)
1080 		goto exit;
1081 
1082 	if (item_length)
1083 		*item_length = le32toh(resp->dir_item_length);
1084 	if (data_length)
1085 		*data_length = le32toh(resp->dir_data_length);
1086 	if (fw_ver)
1087 		*fw_ver = le32toh(resp->fw_ver);
1088 	*ordinal = le16toh(resp->dir_ordinal);
1089 	if (index)
1090 		*index = le16toh(resp->dir_idx);
1091 
1092 exit:
1093 	BNXT_HWRM_UNLOCK(softc);
1094 	return (rc);
1095 }
1096 
1097 int
1098 bnxt_hwrm_nvm_read(struct bnxt_softc *softc, uint16_t index, uint32_t offset,
1099     uint32_t length, struct iflib_dma_info *data)
1100 {
1101 	struct hwrm_nvm_read_input req = {0};
1102 	int rc;
1103 	uint32_t old_timeo;
1104 
1105 	if (length > data->idi_size) {
1106 		rc = EINVAL;
1107 		goto exit;
1108 	}
1109 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_READ);
1110 	req.host_dest_addr = htole64(data->idi_paddr);
1111 	req.dir_idx = htole16(index);
1112 	req.offset = htole32(offset);
1113 	req.len = htole32(length);
1114 	BNXT_HWRM_LOCK(softc);
1115 	old_timeo = softc->hwrm_cmd_timeo;
1116 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1117 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1118 	softc->hwrm_cmd_timeo = old_timeo;
1119 	BNXT_HWRM_UNLOCK(softc);
1120 	if (rc)
1121 		goto exit;
1122 	bus_dmamap_sync(data->idi_tag, data->idi_map, BUS_DMASYNC_POSTREAD);
1123 
1124 	goto exit;
1125 
1126 exit:
1127 	return rc;
1128 }
1129 
1130 int
1131 bnxt_hwrm_nvm_modify(struct bnxt_softc *softc, uint16_t index, uint32_t offset,
1132     void *data, bool cpyin, uint32_t length)
1133 {
1134 	struct hwrm_nvm_modify_input req = {0};
1135 	struct iflib_dma_info dma_data;
1136 	int rc;
1137 	uint32_t old_timeo;
1138 
1139 	if (length == 0 || !data)
1140 		return EINVAL;
1141 	rc = iflib_dma_alloc(softc->ctx, length, &dma_data,
1142 	    BUS_DMA_NOWAIT);
1143 	if (rc)
1144 		return ENOMEM;
1145 	if (cpyin) {
1146 		rc = copyin(data, dma_data.idi_vaddr, length);
1147 		if (rc)
1148 			goto exit;
1149 	}
1150 	else
1151 		memcpy(dma_data.idi_vaddr, data, length);
1152 	bus_dmamap_sync(dma_data.idi_tag, dma_data.idi_map,
1153 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1154 
1155 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_MODIFY);
1156 	req.host_src_addr = htole64(dma_data.idi_paddr);
1157 	req.dir_idx = htole16(index);
1158 	req.offset = htole32(offset);
1159 	req.len = htole32(length);
1160 	BNXT_HWRM_LOCK(softc);
1161 	old_timeo = softc->hwrm_cmd_timeo;
1162 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1163 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1164 	softc->hwrm_cmd_timeo = old_timeo;
1165 	BNXT_HWRM_UNLOCK(softc);
1166 
1167 exit:
1168 	iflib_dma_free(&dma_data);
1169 	return rc;
1170 }
1171 
1172 int
1173 bnxt_hwrm_fw_reset(struct bnxt_softc *softc, uint8_t processor,
1174     uint8_t *selfreset)
1175 {
1176 	struct hwrm_fw_reset_input req = {0};
1177 	struct hwrm_fw_reset_output *resp =
1178 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1179 	int rc;
1180 
1181 	MPASS(selfreset);
1182 
1183 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_RESET);
1184 	req.embedded_proc_type = processor;
1185 	req.selfrst_status = *selfreset;
1186 
1187 	BNXT_HWRM_LOCK(softc);
1188 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1189 	if (rc)
1190 		goto exit;
1191 	*selfreset = resp->selfrst_status;
1192 
1193 exit:
1194 	BNXT_HWRM_UNLOCK(softc);
1195 	return rc;
1196 }
1197 
1198 int
1199 bnxt_hwrm_fw_qstatus(struct bnxt_softc *softc, uint8_t type, uint8_t *selfreset)
1200 {
1201 	struct hwrm_fw_qstatus_input req = {0};
1202 	struct hwrm_fw_qstatus_output *resp =
1203 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1204 	int rc;
1205 
1206 	MPASS(selfreset);
1207 
1208 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_QSTATUS);
1209 	req.embedded_proc_type = type;
1210 
1211 	BNXT_HWRM_LOCK(softc);
1212 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1213 	if (rc)
1214 		goto exit;
1215 	*selfreset = resp->selfrst_status;
1216 
1217 exit:
1218 	BNXT_HWRM_UNLOCK(softc);
1219 	return rc;
1220 }
1221 
1222 int
1223 bnxt_hwrm_nvm_write(struct bnxt_softc *softc, void *data, bool cpyin,
1224     uint16_t type, uint16_t ordinal, uint16_t ext, uint16_t attr,
1225     uint16_t option, uint32_t data_length, bool keep, uint32_t *item_length,
1226     uint16_t *index)
1227 {
1228 	struct hwrm_nvm_write_input req = {0};
1229 	struct hwrm_nvm_write_output *resp =
1230 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1231 	struct iflib_dma_info dma_data;
1232 	int rc;
1233 	uint32_t old_timeo;
1234 
1235 	if (data_length) {
1236 		rc = iflib_dma_alloc(softc->ctx, data_length, &dma_data,
1237 		    BUS_DMA_NOWAIT);
1238 		if (rc)
1239 			return ENOMEM;
1240 		if (cpyin) {
1241 			rc = copyin(data, dma_data.idi_vaddr, data_length);
1242 			if (rc)
1243 				goto early_exit;
1244 		}
1245 		else
1246 			memcpy(dma_data.idi_vaddr, data, data_length);
1247 		bus_dmamap_sync(dma_data.idi_tag, dma_data.idi_map,
1248 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1249 	}
1250 	else
1251 		dma_data.idi_paddr = 0;
1252 
1253 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_WRITE);
1254 
1255 	req.host_src_addr = htole64(dma_data.idi_paddr);
1256 	req.dir_type = htole16(type);
1257 	req.dir_ordinal = htole16(ordinal);
1258 	req.dir_ext = htole16(ext);
1259 	req.dir_attr = htole16(attr);
1260 	req.dir_data_length = htole32(data_length);
1261 	req.option = htole16(option);
1262 	if (keep) {
1263 		req.flags =
1264 		    htole16(HWRM_NVM_WRITE_INPUT_FLAGS_KEEP_ORIG_ACTIVE_IMG);
1265 	}
1266 	if (item_length)
1267 		req.dir_item_length = htole32(*item_length);
1268 
1269 	BNXT_HWRM_LOCK(softc);
1270 	old_timeo = softc->hwrm_cmd_timeo;
1271 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1272 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1273 	softc->hwrm_cmd_timeo = old_timeo;
1274 	if (rc)
1275 		goto exit;
1276 	if (item_length)
1277 		*item_length = le32toh(resp->dir_item_length);
1278 	if (index)
1279 		*index = le16toh(resp->dir_idx);
1280 
1281 exit:
1282 	BNXT_HWRM_UNLOCK(softc);
1283 early_exit:
1284 	if (data_length)
1285 		iflib_dma_free(&dma_data);
1286 	return rc;
1287 }
1288 
1289 int
1290 bnxt_hwrm_nvm_erase_dir_entry(struct bnxt_softc *softc, uint16_t index)
1291 {
1292 	struct hwrm_nvm_erase_dir_entry_input req = {0};
1293 	uint32_t old_timeo;
1294 	int rc;
1295 
1296 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_ERASE_DIR_ENTRY);
1297 	req.dir_idx = htole16(index);
1298 	BNXT_HWRM_LOCK(softc);
1299 	old_timeo = softc->hwrm_cmd_timeo;
1300 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1301 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1302 	softc->hwrm_cmd_timeo = old_timeo;
1303 	BNXT_HWRM_UNLOCK(softc);
1304 	return rc;
1305 }
1306 
1307 int
1308 bnxt_hwrm_nvm_get_dir_info(struct bnxt_softc *softc, uint32_t *entries,
1309     uint32_t *entry_length)
1310 {
1311 	struct hwrm_nvm_get_dir_info_input req = {0};
1312 	struct hwrm_nvm_get_dir_info_output *resp =
1313 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1314 	int rc;
1315 	uint32_t old_timeo;
1316 
1317 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DIR_INFO);
1318 
1319 	BNXT_HWRM_LOCK(softc);
1320 	old_timeo = softc->hwrm_cmd_timeo;
1321 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1322 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1323 	softc->hwrm_cmd_timeo = old_timeo;
1324 	if (rc)
1325 		goto exit;
1326 
1327 	if (entries)
1328 		*entries = le32toh(resp->entries);
1329 	if (entry_length)
1330 		*entry_length = le32toh(resp->entry_length);
1331 
1332 exit:
1333 	BNXT_HWRM_UNLOCK(softc);
1334 	return rc;
1335 }
1336 
1337 int
1338 bnxt_hwrm_nvm_get_dir_entries(struct bnxt_softc *softc, uint32_t *entries,
1339     uint32_t *entry_length, struct iflib_dma_info *dma_data)
1340 {
1341 	struct hwrm_nvm_get_dir_entries_input req = {0};
1342 	uint32_t ent;
1343 	uint32_t ent_len;
1344 	int rc;
1345 	uint32_t old_timeo;
1346 
1347 	if (!entries)
1348 		entries = &ent;
1349 	if (!entry_length)
1350 		entry_length = &ent_len;
1351 
1352 	rc = bnxt_hwrm_nvm_get_dir_info(softc, entries, entry_length);
1353 	if (rc)
1354 		goto exit;
1355 	if (*entries * *entry_length > dma_data->idi_size) {
1356 		rc = EINVAL;
1357 		goto exit;
1358 	}
1359 
1360 	/*
1361 	 * TODO: There's a race condition here that could blow up DMA memory...
1362 	 *	 we need to allocate the max size, not the currently in use
1363 	 *	 size.  The command should totally have a max size here.
1364 	 */
1365 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DIR_ENTRIES);
1366 	req.host_dest_addr = htole64(dma_data->idi_paddr);
1367 	BNXT_HWRM_LOCK(softc);
1368 	old_timeo = softc->hwrm_cmd_timeo;
1369 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1370 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1371 	softc->hwrm_cmd_timeo = old_timeo;
1372 	BNXT_HWRM_UNLOCK(softc);
1373 	if (rc)
1374 		goto exit;
1375 	bus_dmamap_sync(dma_data->idi_tag, dma_data->idi_map,
1376 	    BUS_DMASYNC_POSTWRITE);
1377 
1378 exit:
1379 	return rc;
1380 }
1381 
1382 int
1383 bnxt_hwrm_nvm_get_dev_info(struct bnxt_softc *softc, uint16_t *mfg_id,
1384     uint16_t *device_id, uint32_t *sector_size, uint32_t *nvram_size,
1385     uint32_t *reserved_size, uint32_t *available_size)
1386 {
1387 	struct hwrm_nvm_get_dev_info_input req = {0};
1388 	struct hwrm_nvm_get_dev_info_output *resp =
1389 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1390 	int rc;
1391 	uint32_t old_timeo;
1392 
1393 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DEV_INFO);
1394 
1395 	BNXT_HWRM_LOCK(softc);
1396 	old_timeo = softc->hwrm_cmd_timeo;
1397 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1398 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1399 	softc->hwrm_cmd_timeo = old_timeo;
1400 	if (rc)
1401 		goto exit;
1402 
1403 	if (mfg_id)
1404 		*mfg_id = le16toh(resp->manufacturer_id);
1405 	if (device_id)
1406 		*device_id = le16toh(resp->device_id);
1407 	if (sector_size)
1408 		*sector_size = le32toh(resp->sector_size);
1409 	if (nvram_size)
1410 		*nvram_size = le32toh(resp->nvram_size);
1411 	if (reserved_size)
1412 		*reserved_size = le32toh(resp->reserved_size);
1413 	if (available_size)
1414 		*available_size = le32toh(resp->available_size);
1415 
1416 exit:
1417 	BNXT_HWRM_UNLOCK(softc);
1418 	return rc;
1419 }
1420 
1421 int
1422 bnxt_hwrm_nvm_install_update(struct bnxt_softc *softc,
1423     uint32_t install_type, uint64_t *installed_items, uint8_t *result,
1424     uint8_t *problem_item, uint8_t *reset_required)
1425 {
1426 	struct hwrm_nvm_install_update_input req = {0};
1427 	struct hwrm_nvm_install_update_output *resp =
1428 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1429 	int rc;
1430 	uint32_t old_timeo;
1431 
1432 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_INSTALL_UPDATE);
1433 	req.install_type = htole32(install_type);
1434 
1435 	BNXT_HWRM_LOCK(softc);
1436 	old_timeo = softc->hwrm_cmd_timeo;
1437 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1438 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1439 	softc->hwrm_cmd_timeo = old_timeo;
1440 	if (rc)
1441 		goto exit;
1442 
1443 	if (installed_items)
1444 		*installed_items = le32toh(resp->installed_items);
1445 	if (result)
1446 		*result = resp->result;
1447 	if (problem_item)
1448 		*problem_item = resp->problem_item;
1449 	if (reset_required)
1450 		*reset_required = resp->reset_required;
1451 
1452 exit:
1453 	BNXT_HWRM_UNLOCK(softc);
1454 	return rc;
1455 }
1456 
1457 int
1458 bnxt_hwrm_nvm_verify_update(struct bnxt_softc *softc, uint16_t type,
1459     uint16_t ordinal, uint16_t ext)
1460 {
1461 	struct hwrm_nvm_verify_update_input req = {0};
1462 	uint32_t old_timeo;
1463 	int rc;
1464 
1465 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_VERIFY_UPDATE);
1466 
1467 	req.dir_type = htole16(type);
1468 	req.dir_ordinal = htole16(ordinal);
1469 	req.dir_ext = htole16(ext);
1470 
1471 	BNXT_HWRM_LOCK(softc);
1472 	old_timeo = softc->hwrm_cmd_timeo;
1473 	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1474 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1475 	softc->hwrm_cmd_timeo = old_timeo;
1476 	BNXT_HWRM_UNLOCK(softc);
1477 	return rc;
1478 }
1479 
1480 int
1481 bnxt_hwrm_fw_get_time(struct bnxt_softc *softc, uint16_t *year, uint8_t *month,
1482     uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second,
1483     uint16_t *millisecond, uint16_t *zone)
1484 {
1485 	struct hwrm_fw_get_time_input req = {0};
1486 	struct hwrm_fw_get_time_output *resp =
1487 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1488 	int rc;
1489 
1490 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_GET_TIME);
1491 
1492 	BNXT_HWRM_LOCK(softc);
1493 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1494 	if (rc)
1495 		goto exit;
1496 
1497 	if (year)
1498 		*year = le16toh(resp->year);
1499 	if (month)
1500 		*month = resp->month;
1501 	if (day)
1502 		*day = resp->day;
1503 	if (hour)
1504 		*hour = resp->hour;
1505 	if (minute)
1506 		*minute = resp->minute;
1507 	if (second)
1508 		*second = resp->second;
1509 	if (millisecond)
1510 		*millisecond = le16toh(resp->millisecond);
1511 	if (zone)
1512 		*zone = le16toh(resp->zone);
1513 
1514 exit:
1515 	BNXT_HWRM_UNLOCK(softc);
1516 	return rc;
1517 }
1518 
1519 int
1520 bnxt_hwrm_fw_set_time(struct bnxt_softc *softc, uint16_t year, uint8_t month,
1521     uint8_t day, uint8_t hour, uint8_t minute, uint8_t second,
1522     uint16_t millisecond, uint16_t zone)
1523 {
1524 	struct hwrm_fw_set_time_input req = {0};
1525 
1526 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_SET_TIME);
1527 
1528 	req.year = htole16(year);
1529 	req.month = month;
1530 	req.day = day;
1531 	req.hour = hour;
1532 	req.minute = minute;
1533 	req.second = second;
1534 	req.millisecond = htole16(millisecond);
1535 	req.zone = htole16(zone);
1536 	return hwrm_send_message(softc, &req, sizeof(req));
1537 }
1538 
1539 int
1540 bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *softc)
1541 {
1542 	struct bnxt_link_info *link_info = &softc->link_info;
1543 	struct hwrm_port_phy_qcfg_input req = {0};
1544 	struct hwrm_port_phy_qcfg_output *resp =
1545 	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1546 	int rc = 0;
1547 
1548 	BNXT_HWRM_LOCK(softc);
1549 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_QCFG);
1550 
1551 	rc = _hwrm_send_message(softc, &req, sizeof(req));
1552 	if (rc)
1553 		goto exit;
1554 
1555 	link_info->phy_link_status = resp->link;
1556 	link_info->duplex =  resp->duplex_cfg;
1557 	link_info->auto_mode = resp->auto_mode;
1558 
1559         /*
1560          * When AUTO_PAUSE_AUTONEG_PAUSE bit is set to 1,
1561          * the advertisement of pause is enabled.
1562          * 1. When the auto_mode is not set to none and this flag is set to 1,
1563          *    then the auto_pause bits on this port are being advertised and
1564          *    autoneg pause results are being interpreted.
1565          * 2. When the auto_mode is not set to none and this flag is set to 0,
1566          *    the pause is forced as indicated in force_pause, and also
1567 	 *    advertised as auto_pause bits, but the autoneg results are not
1568 	 *    interpreted since the pause configuration is being forced.
1569          * 3. When the auto_mode is set to none and this flag is set to 1,
1570          *    auto_pause bits should be ignored and should be set to 0.
1571          */
1572 
1573 	link_info->flow_ctrl.autoneg = false;
1574 	link_info->flow_ctrl.tx = false;
1575 	link_info->flow_ctrl.rx = false;
1576 
1577 	if ((resp->auto_mode) &&
1578             (resp->auto_pause & BNXT_AUTO_PAUSE_AUTONEG_PAUSE)) {
1579 			link_info->flow_ctrl.autoneg = true;
1580 	}
1581 
1582 	if (link_info->flow_ctrl.autoneg) {
1583 		if (resp->auto_pause & BNXT_PAUSE_TX)
1584 			link_info->flow_ctrl.tx = true;
1585 		if (resp->auto_pause & BNXT_PAUSE_RX)
1586 			link_info->flow_ctrl.rx = true;
1587 	} else {
1588 		if (resp->force_pause & BNXT_PAUSE_TX)
1589 			link_info->flow_ctrl.tx = true;
1590 		if (resp->force_pause & BNXT_PAUSE_RX)
1591 			link_info->flow_ctrl.rx = true;
1592 	}
1593 
1594 	link_info->duplex_setting = resp->duplex_cfg;
1595 	if (link_info->phy_link_status == HWRM_PORT_PHY_QCFG_OUTPUT_LINK_LINK)
1596 		link_info->link_speed = le16toh(resp->link_speed);
1597 	else
1598 		link_info->link_speed = 0;
1599 	link_info->force_link_speed = le16toh(resp->force_link_speed);
1600 	link_info->auto_link_speed = le16toh(resp->auto_link_speed);
1601 	link_info->support_speeds = le16toh(resp->support_speeds);
1602 	link_info->auto_link_speeds = le16toh(resp->auto_link_speed_mask);
1603 	link_info->preemphasis = le32toh(resp->preemphasis);
1604 	link_info->phy_ver[0] = resp->phy_maj;
1605 	link_info->phy_ver[1] = resp->phy_min;
1606 	link_info->phy_ver[2] = resp->phy_bld;
1607 	snprintf(softc->ver_info->phy_ver, sizeof(softc->ver_info->phy_ver),
1608 	    "%d.%d.%d", link_info->phy_ver[0], link_info->phy_ver[1],
1609 	    link_info->phy_ver[2]);
1610 	strlcpy(softc->ver_info->phy_vendor, resp->phy_vendor_name,
1611 	    BNXT_NAME_SIZE);
1612 	strlcpy(softc->ver_info->phy_partnumber, resp->phy_vendor_partnumber,
1613 	    BNXT_NAME_SIZE);
1614 	link_info->media_type = resp->media_type;
1615 	link_info->phy_type = resp->phy_type;
1616 	link_info->transceiver = resp->xcvr_pkg_type;
1617 	link_info->phy_addr = resp->eee_config_phy_addr &
1618 	    HWRM_PORT_PHY_QCFG_OUTPUT_PHY_ADDR_MASK;
1619 
1620 exit:
1621 	BNXT_HWRM_UNLOCK(softc);
1622 	return rc;
1623 }
1624 
1625 uint16_t
1626 bnxt_hwrm_get_wol_fltrs(struct bnxt_softc *softc, uint16_t handle)
1627 {
1628 	struct hwrm_wol_filter_qcfg_input req = {0};
1629 	struct hwrm_wol_filter_qcfg_output *resp =
1630 			(void *)softc->hwrm_cmd_resp.idi_vaddr;
1631 	uint16_t next_handle = 0;
1632 	int rc;
1633 
1634 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_WOL_FILTER_QCFG);
1635 	req.port_id = htole16(softc->pf.port_id);
1636 	req.handle = htole16(handle);
1637 	rc = hwrm_send_message(softc, &req, sizeof(req));
1638 	if (!rc) {
1639 		next_handle = le16toh(resp->next_handle);
1640 		if (next_handle != 0) {
1641 			if (resp->wol_type ==
1642 				HWRM_WOL_FILTER_ALLOC_INPUT_WOL_TYPE_MAGICPKT) {
1643 				softc->wol = 1;
1644 				softc->wol_filter_id = resp->wol_filter_id;
1645 			}
1646 		}
1647 	}
1648 	return next_handle;
1649 }
1650 
1651 int
1652 bnxt_hwrm_alloc_wol_fltr(struct bnxt_softc *softc)
1653 {
1654 	struct hwrm_wol_filter_alloc_input req = {0};
1655 	struct hwrm_wol_filter_alloc_output *resp =
1656 		(void *)softc->hwrm_cmd_resp.idi_vaddr;
1657 	int rc;
1658 
1659 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_WOL_FILTER_ALLOC);
1660 	req.port_id = htole16(softc->pf.port_id);
1661 	req.wol_type = HWRM_WOL_FILTER_ALLOC_INPUT_WOL_TYPE_MAGICPKT;
1662 	req.enables =
1663 		htole32(HWRM_WOL_FILTER_ALLOC_INPUT_ENABLES_MAC_ADDRESS);
1664 	memcpy(req.mac_address, softc->func.mac_addr, ETHER_ADDR_LEN);
1665 	rc = hwrm_send_message(softc, &req, sizeof(req));
1666 	if (!rc)
1667 		softc->wol_filter_id = resp->wol_filter_id;
1668 
1669 	return rc;
1670 }
1671 
1672 int
1673 bnxt_hwrm_free_wol_fltr(struct bnxt_softc *softc)
1674 {
1675 	struct hwrm_wol_filter_free_input req = {0};
1676 
1677 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_WOL_FILTER_FREE);
1678 	req.port_id = htole16(softc->pf.port_id);
1679 	req.enables =
1680 		htole32(HWRM_WOL_FILTER_FREE_INPUT_ENABLES_WOL_FILTER_ID);
1681 	req.wol_filter_id = softc->wol_filter_id;
1682 	return hwrm_send_message(softc, &req, sizeof(req));
1683 }
1684 
1685 static void bnxt_hwrm_set_coal_params(struct bnxt_softc *softc, uint32_t max_frames,
1686         uint32_t buf_tmrs, uint16_t flags,
1687         struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req)
1688 {
1689         req->flags = htole16(flags);
1690         req->num_cmpl_dma_aggr = htole16((uint16_t)max_frames);
1691         req->num_cmpl_dma_aggr_during_int = htole16(max_frames >> 16);
1692         req->cmpl_aggr_dma_tmr = htole16((uint16_t)buf_tmrs);
1693         req->cmpl_aggr_dma_tmr_during_int = htole16(buf_tmrs >> 16);
1694         /* Minimum time between 2 interrupts set to buf_tmr x 2 */
1695         req->int_lat_tmr_min = htole16((uint16_t)buf_tmrs * 2);
1696         req->int_lat_tmr_max = htole16((uint16_t)buf_tmrs * 4);
1697         req->num_cmpl_aggr_int = htole16((uint16_t)max_frames * 4);
1698 }
1699 
1700 
1701 int bnxt_hwrm_set_coal(struct bnxt_softc *softc)
1702 {
1703         int i, rc = 0;
1704         struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req_rx = {0},
1705                                                            req_tx = {0}, *req;
1706         uint16_t max_buf, max_buf_irq;
1707         uint16_t buf_tmr, buf_tmr_irq;
1708         uint32_t flags;
1709 
1710         bnxt_hwrm_cmd_hdr_init(softc, &req_rx,
1711                                HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS);
1712         bnxt_hwrm_cmd_hdr_init(softc, &req_tx,
1713                                HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS);
1714 
1715         /* Each rx completion (2 records) should be DMAed immediately.
1716          * DMA 1/4 of the completion buffers at a time.
1717          */
1718         max_buf = min_t(uint16_t, softc->rx_coal_frames / 4, 2);
1719         /* max_buf must not be zero */
1720         max_buf = clamp_t(uint16_t, max_buf, 1, 63);
1721         max_buf_irq = clamp_t(uint16_t, softc->rx_coal_frames_irq, 1, 63);
1722         buf_tmr = BNXT_USEC_TO_COAL_TIMER(softc->rx_coal_usecs);
1723         /* buf timer set to 1/4 of interrupt timer */
1724         buf_tmr = max_t(uint16_t, buf_tmr / 4, 1);
1725         buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(softc->rx_coal_usecs_irq);
1726         buf_tmr_irq = max_t(uint16_t, buf_tmr_irq, 1);
1727 
1728         flags = HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET;
1729 
1730         /* RING_IDLE generates more IRQs for lower latency.  Enable it only
1731          * if coal_usecs is less than 25 us.
1732          */
1733         if (softc->rx_coal_usecs < 25)
1734                 flags |= HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_RING_IDLE;
1735 
1736         bnxt_hwrm_set_coal_params(softc, max_buf_irq << 16 | max_buf,
1737                                   buf_tmr_irq << 16 | buf_tmr, flags, &req_rx);
1738 
1739         /* max_buf must not be zero */
1740         max_buf = clamp_t(uint16_t, softc->tx_coal_frames, 1, 63);
1741         max_buf_irq = clamp_t(uint16_t, softc->tx_coal_frames_irq, 1, 63);
1742         buf_tmr = BNXT_USEC_TO_COAL_TIMER(softc->tx_coal_usecs);
1743         /* buf timer set to 1/4 of interrupt timer */
1744         buf_tmr = max_t(uint16_t, buf_tmr / 4, 1);
1745         buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(softc->tx_coal_usecs_irq);
1746         buf_tmr_irq = max_t(uint16_t, buf_tmr_irq, 1);
1747         flags = HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET;
1748         bnxt_hwrm_set_coal_params(softc, max_buf_irq << 16 | max_buf,
1749                                   buf_tmr_irq << 16 | buf_tmr, flags, &req_tx);
1750 
1751         for (i = 0; i < softc->nrxqsets; i++) {
1752 
1753 
1754 		req = &req_rx;
1755                 /*
1756                  * TBD:
1757 		 *      Check if Tx also needs to be done
1758                  *      So far, Tx processing has been done in softirq contest
1759                  *
1760 		 * req = &req_tx;
1761 		 */
1762 		req->ring_id = htole16(softc->grp_info[i].cp_ring_id);
1763 
1764                 rc = hwrm_send_message(softc, req, sizeof(*req));
1765                 if (rc)
1766                         break;
1767         }
1768         return rc;
1769 }
1770 
1771 
1772 
1773 int bnxt_hwrm_func_rgtr_async_events(struct bnxt_softc *softc, unsigned long *bmap,
1774                                      int bmap_size)
1775 {
1776 	struct hwrm_func_drv_rgtr_input req = {0};
1777 	bitstr_t *async_events_bmap;
1778 	uint32_t *events;
1779 	int i;
1780 
1781 #define AE_BMAP_SZ_BITS	256
1782 	async_events_bmap = bit_alloc(AE_BMAP_SZ_BITS, M_DEVBUF, M_WAITOK);
1783 
1784 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR);
1785 
1786 	req.enables =
1787 		htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_ASYNC_EVENT_FWD);
1788 
1789 	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE);
1790 	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD);
1791 	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED);
1792 	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE);
1793 	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE);
1794 
1795 	if (bmap && bmap_size) {
1796 		for (i = 0; i < bmap_size; i++) {
1797 			if (bit_test(bmap, i))
1798 				bit_set(async_events_bmap, i);
1799 		}
1800 	}
1801 
1802 #define AE_BMAP_SZ_WORDS	(AE_BMAP_SZ_BITS / 8 / sizeof(uint32_t))
1803 	events = (uint32_t *)async_events_bmap;
1804 	for (i = 0; i < AE_BMAP_SZ_WORDS; i++)
1805 		req.async_event_fwd[i] |= htole32(events[i]);
1806 #undef AE_BMAP_SZ_WORDS
1807 #undef AE_BMAP_SZ_BITS
1808 
1809 	free(async_events_bmap, M_DEVBUF);
1810 
1811 	return hwrm_send_message(softc, &req, sizeof(req));
1812 }
1813