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
39static int bnxt_hwrm_err_map(uint16_t err);
40static inline int _is_valid_ether_addr(uint8_t *);
41static inline void get_random_ether_addr(uint8_t *);
42static void	bnxt_hwrm_set_link_common(struct bnxt_softc *softc,
43		    struct hwrm_port_phy_cfg_input *req);
44static void	bnxt_hwrm_set_pause_common(struct bnxt_softc *softc,
45		    struct hwrm_port_phy_cfg_input *req);
46static void	bnxt_hwrm_set_eee(struct bnxt_softc *softc,
47		    struct hwrm_port_phy_cfg_input *req);
48static int	_hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
49static int	hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
50static 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
55static int
56bnxt_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
84int
85bnxt_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
94void
95bnxt_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
103static void
104bnxt_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
115static 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
219static int
220hwrm_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
230int
231bnxt_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
261qportcfg_exit:
262	BNXT_HWRM_UNLOCK(softc);
263	return (rc);
264}
265
266
267int
268bnxt_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
357fail:
358	BNXT_HWRM_UNLOCK(softc);
359	return rc;
360}
361
362int
363bnxt_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
381int
382bnxt_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
394static 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
405static inline void
406get_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
416int
417bnxt_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
467fail:
468	BNXT_HWRM_UNLOCK(softc);
469	return rc;
470}
471
472int
473bnxt_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);
492fail:
493	BNXT_HWRM_UNLOCK(softc);
494        return rc;
495}
496
497int
498bnxt_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
508static void
509bnxt_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
533static void
534bnxt_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 */
564static void
565bnxt_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
590int
591bnxt_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
632int
633bnxt_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
658int
659bnxt_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
684fail:
685	BNXT_HWRM_UNLOCK(softc);
686	return (rc);
687}
688
689int
690bnxt_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
712fail:
713	BNXT_HWRM_UNLOCK(softc);
714	return (rc);
715}
716
717int
718bnxt_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
744fail:
745	BNXT_HWRM_UNLOCK(softc);
746	return rc;
747}
748
749/*
750 * Ring allocation message to the firmware
751 */
752int
753bnxt_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
799fail:
800	BNXT_HWRM_UNLOCK(softc);
801	return rc;
802}
803
804int
805bnxt_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
832fail:
833	BNXT_HWRM_UNLOCK(softc);
834
835	return rc;
836}
837
838int
839bnxt_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
857int
858bnxt_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
909int
910bnxt_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
944fail:
945	BNXT_HWRM_UNLOCK(softc);
946	return (rc);
947}
948
949int
950bnxt_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
965int
966bnxt_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
994void
995bnxt_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
1010int
1011bnxt_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
1049int
1050bnxt_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
1092exit:
1093	BNXT_HWRM_UNLOCK(softc);
1094	return (rc);
1095}
1096
1097int
1098bnxt_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
1126exit:
1127	return rc;
1128}
1129
1130int
1131bnxt_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
1167exit:
1168	iflib_dma_free(&dma_data);
1169	return rc;
1170}
1171
1172int
1173bnxt_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
1193exit:
1194	BNXT_HWRM_UNLOCK(softc);
1195	return rc;
1196}
1197
1198int
1199bnxt_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
1217exit:
1218	BNXT_HWRM_UNLOCK(softc);
1219	return rc;
1220}
1221
1222int
1223bnxt_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
1281exit:
1282	BNXT_HWRM_UNLOCK(softc);
1283early_exit:
1284	if (data_length)
1285		iflib_dma_free(&dma_data);
1286	return rc;
1287}
1288
1289int
1290bnxt_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
1307int
1308bnxt_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
1332exit:
1333	BNXT_HWRM_UNLOCK(softc);
1334	return rc;
1335}
1336
1337int
1338bnxt_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
1378exit:
1379	return rc;
1380}
1381
1382int
1383bnxt_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
1416exit:
1417	BNXT_HWRM_UNLOCK(softc);
1418	return rc;
1419}
1420
1421int
1422bnxt_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
1452exit:
1453	BNXT_HWRM_UNLOCK(softc);
1454	return rc;
1455}
1456
1457int
1458bnxt_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
1480int
1481bnxt_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
1514exit:
1515	BNXT_HWRM_UNLOCK(softc);
1516	return rc;
1517}
1518
1519int
1520bnxt_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
1539int
1540bnxt_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
1620exit:
1621	BNXT_HWRM_UNLOCK(softc);
1622	return rc;
1623}
1624
1625uint16_t
1626bnxt_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
1651int
1652bnxt_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
1672int
1673bnxt_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
1685static 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
1701int 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
1773int 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	async_events_bmap = bit_alloc(256, M_DEVBUF, M_WAITOK|M_ZERO);
1782	events = (uint32_t *)async_events_bmap;
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	memset(async_events_bmap, 0, sizeof(256 / 8));
1790
1791	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE);
1792	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD);
1793	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED);
1794	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE);
1795	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE);
1796
1797	if (bmap && bmap_size) {
1798		for (i = 0; i < bmap_size; i++) {
1799			if (bit_test(bmap, i))
1800				bit_set(async_events_bmap, i);
1801		}
1802	}
1803
1804	for (i = 0; i < 8; i++)
1805		req.async_event_fwd[i] |= htole32(events[i]);
1806
1807	free(async_events_bmap, M_DEVBUF);
1808
1809	return hwrm_send_message(softc, &req, sizeof(req));
1810}
1811