1308696Sshurd/*-
2308696Sshurd * Broadcom NetXtreme-C/E network driver.
3308696Sshurd *
4308696Sshurd * Copyright (c) 2016 Broadcom, All Rights Reserved.
5308696Sshurd * The term Broadcom refers to Broadcom Limited and/or its subsidiaries
6308696Sshurd *
7308696Sshurd * Redistribution and use in source and binary forms, with or without
8308696Sshurd * modification, are permitted provided that the following conditions
9308696Sshurd * are met:
10308696Sshurd * 1. Redistributions of source code must retain the above copyright
11308696Sshurd *    notice, this list of conditions and the following disclaimer.
12308696Sshurd * 2. Redistributions in binary form must reproduce the above copyright
13308696Sshurd *    notice, this list of conditions and the following disclaimer in the
14308696Sshurd *    documentation and/or other materials provided with the distribution.
15308696Sshurd *
16308696Sshurd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
17308696Sshurd * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18308696Sshurd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19308696Sshurd * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20308696Sshurd * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21308696Sshurd * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22308696Sshurd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23308696Sshurd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24308696Sshurd * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25308696Sshurd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26308696Sshurd * THE POSSIBILITY OF SUCH DAMAGE.
27308696Sshurd */
28308696Sshurd
29308696Sshurd#include <sys/cdefs.h>
30308696Sshurd__FBSDID("$FreeBSD: stable/11/sys/dev/bnxt/bnxt_hwrm.c 334178 2018-05-24 18:53:29Z shurd $");
31308696Sshurd
32308696Sshurd#include <sys/endian.h>
33333364Sshurd#include <sys/bitstring.h>
34308696Sshurd
35308696Sshurd#include "bnxt.h"
36308696Sshurd#include "bnxt_hwrm.h"
37308696Sshurd#include "hsi_struct_def.h"
38308696Sshurd
39308696Sshurdstatic int bnxt_hwrm_err_map(uint16_t err);
40308696Sshurdstatic inline int _is_valid_ether_addr(uint8_t *);
41308696Sshurdstatic inline void get_random_ether_addr(uint8_t *);
42308696Sshurdstatic void	bnxt_hwrm_set_link_common(struct bnxt_softc *softc,
43308696Sshurd		    struct hwrm_port_phy_cfg_input *req);
44308696Sshurdstatic void	bnxt_hwrm_set_pause_common(struct bnxt_softc *softc,
45308696Sshurd		    struct hwrm_port_phy_cfg_input *req);
46308696Sshurdstatic void	bnxt_hwrm_set_eee(struct bnxt_softc *softc,
47308696Sshurd		    struct hwrm_port_phy_cfg_input *req);
48308696Sshurdstatic int	_hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
49308696Sshurdstatic int	hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
50308696Sshurdstatic void bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *, void *, uint16_t);
51308696Sshurd
52308696Sshurd/* NVRam stuff has a five minute timeout */
53308696Sshurd#define BNXT_NVM_TIMEO	(5 * 60 * 1000)
54308696Sshurd
55308696Sshurdstatic int
56308696Sshurdbnxt_hwrm_err_map(uint16_t err)
57308696Sshurd{
58308696Sshurd	int rc;
59308696Sshurd
60308696Sshurd	switch (err) {
61308696Sshurd	case HWRM_ERR_CODE_SUCCESS:
62308696Sshurd		return 0;
63308696Sshurd	case HWRM_ERR_CODE_INVALID_PARAMS:
64308696Sshurd	case HWRM_ERR_CODE_INVALID_FLAGS:
65308696Sshurd	case HWRM_ERR_CODE_INVALID_ENABLES:
66308696Sshurd		return EINVAL;
67308696Sshurd	case HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED:
68308696Sshurd		return EACCES;
69308696Sshurd	case HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR:
70308696Sshurd		return ENOMEM;
71308696Sshurd	case HWRM_ERR_CODE_CMD_NOT_SUPPORTED:
72308696Sshurd		return ENOSYS;
73308696Sshurd	case HWRM_ERR_CODE_FAIL:
74308696Sshurd		return EIO;
75308696Sshurd	case HWRM_ERR_CODE_HWRM_ERROR:
76308696Sshurd	case HWRM_ERR_CODE_UNKNOWN_ERR:
77308696Sshurd	default:
78308696Sshurd		return EDOOFUS;
79308696Sshurd	}
80308696Sshurd
81308696Sshurd	return rc;
82308696Sshurd}
83308696Sshurd
84308696Sshurdint
85308696Sshurdbnxt_alloc_hwrm_dma_mem(struct bnxt_softc *softc)
86308696Sshurd{
87308696Sshurd	int rc;
88308696Sshurd
89308696Sshurd	rc = iflib_dma_alloc(softc->ctx, PAGE_SIZE, &softc->hwrm_cmd_resp,
90308696Sshurd	    BUS_DMA_NOWAIT);
91308696Sshurd	return rc;
92308696Sshurd}
93308696Sshurd
94308696Sshurdvoid
95308696Sshurdbnxt_free_hwrm_dma_mem(struct bnxt_softc *softc)
96308696Sshurd{
97308696Sshurd	if (softc->hwrm_cmd_resp.idi_vaddr)
98308696Sshurd		iflib_dma_free(&softc->hwrm_cmd_resp);
99308696Sshurd	softc->hwrm_cmd_resp.idi_vaddr = NULL;
100308696Sshurd	return;
101308696Sshurd}
102308696Sshurd
103308696Sshurdstatic void
104308696Sshurdbnxt_hwrm_cmd_hdr_init(struct bnxt_softc *softc, void *request,
105308696Sshurd    uint16_t req_type)
106308696Sshurd{
107308696Sshurd	struct input *req = request;
108308696Sshurd
109308696Sshurd	req->req_type = htole16(req_type);
110308696Sshurd	req->cmpl_ring = 0xffff;
111308696Sshurd	req->target_id = 0xffff;
112308696Sshurd	req->resp_addr = htole64(softc->hwrm_cmd_resp.idi_paddr);
113308696Sshurd}
114308696Sshurd
115308696Sshurdstatic int
116308696Sshurd_hwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len)
117308696Sshurd{
118308696Sshurd	struct input *req = msg;
119308696Sshurd	struct hwrm_err_output *resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
120308696Sshurd	uint32_t *data = msg;
121308696Sshurd	int i;
122308696Sshurd	uint16_t cp_ring_id;
123308696Sshurd	uint8_t *valid;
124308696Sshurd	uint16_t err;
125333364Sshurd	uint16_t max_req_len = HWRM_MAX_REQ_LEN;
126333364Sshurd	struct hwrm_short_input short_input = {0};
127308696Sshurd
128308696Sshurd	/* TODO: DMASYNC in here. */
129308696Sshurd	req->seq_id = htole16(softc->hwrm_cmd_seq++);
130308696Sshurd	memset(resp, 0, PAGE_SIZE);
131308696Sshurd	cp_ring_id = le16toh(req->cmpl_ring);
132308696Sshurd
133333364Sshurd	if (softc->flags & BNXT_FLAG_SHORT_CMD) {
134333364Sshurd		void *short_cmd_req = softc->hwrm_short_cmd_req_addr.idi_vaddr;
135333364Sshurd
136333364Sshurd		memcpy(short_cmd_req, req, msg_len);
137333364Sshurd		memset((uint8_t *) short_cmd_req + msg_len, 0, softc->hwrm_max_req_len-
138333364Sshurd		    msg_len);
139333364Sshurd
140333364Sshurd		short_input.req_type = req->req_type;
141333364Sshurd		short_input.signature =
142333364Sshurd		    htole16(HWRM_SHORT_INPUT_SIGNATURE_SHORT_CMD);
143333364Sshurd		short_input.size = htole16(msg_len);
144333364Sshurd		short_input.req_addr =
145333364Sshurd		    htole64(softc->hwrm_short_cmd_req_addr.idi_paddr);
146333364Sshurd
147333364Sshurd		data = (uint32_t *)&short_input;
148333364Sshurd		msg_len = sizeof(short_input);
149333364Sshurd
150333364Sshurd		/* Sync memory write before updating doorbell */
151333364Sshurd		wmb();
152333364Sshurd
153333364Sshurd		max_req_len = BNXT_HWRM_SHORT_REQ_LEN;
154333364Sshurd	}
155333364Sshurd
156308696Sshurd	/* Write request msg to hwrm channel */
157308696Sshurd	for (i = 0; i < msg_len; i += 4) {
158308696Sshurd		bus_space_write_4(softc->hwrm_bar.tag,
159308696Sshurd				  softc->hwrm_bar.handle,
160308696Sshurd				  i, *data);
161308696Sshurd		data++;
162308696Sshurd	}
163308696Sshurd
164308696Sshurd	/* Clear to the end of the request buffer */
165333364Sshurd	for (i = msg_len; i < max_req_len; i += 4)
166308696Sshurd		bus_space_write_4(softc->hwrm_bar.tag, softc->hwrm_bar.handle,
167308696Sshurd		    i, 0);
168308696Sshurd
169308696Sshurd	/* Ring channel doorbell */
170308696Sshurd	bus_space_write_4(softc->hwrm_bar.tag,
171308696Sshurd			  softc->hwrm_bar.handle,
172308696Sshurd			  0x100, htole32(1));
173308696Sshurd
174308696Sshurd	/* Check if response len is updated */
175308696Sshurd	for (i = 0; i < softc->hwrm_cmd_timeo; i++) {
176308696Sshurd		if (resp->resp_len && resp->resp_len <= 4096)
177308696Sshurd			break;
178308696Sshurd		DELAY(1000);
179308696Sshurd	}
180308696Sshurd	if (i >= softc->hwrm_cmd_timeo) {
181308696Sshurd		device_printf(softc->dev,
182308696Sshurd		    "Timeout sending %s: (timeout: %u) seq: %d\n",
183308696Sshurd		    GET_HWRM_REQ_TYPE(req->req_type), softc->hwrm_cmd_timeo,
184308696Sshurd		    le16toh(req->seq_id));
185308696Sshurd		return ETIMEDOUT;
186308696Sshurd	}
187308696Sshurd	/* Last byte of resp contains the valid key */
188308696Sshurd	valid = (uint8_t *)resp + resp->resp_len - 1;
189308696Sshurd	for (i = 0; i < softc->hwrm_cmd_timeo; i++) {
190308696Sshurd		if (*valid == HWRM_RESP_VALID_KEY)
191308696Sshurd			break;
192308696Sshurd		DELAY(1000);
193308696Sshurd	}
194308696Sshurd	if (i >= softc->hwrm_cmd_timeo) {
195308696Sshurd		device_printf(softc->dev, "Timeout sending %s: "
196308696Sshurd		    "(timeout: %u) msg {0x%x 0x%x} len:%d v: %d\n",
197308696Sshurd		    GET_HWRM_REQ_TYPE(req->req_type),
198308696Sshurd		    softc->hwrm_cmd_timeo, le16toh(req->req_type),
199308696Sshurd		    le16toh(req->seq_id), msg_len,
200308696Sshurd		    *valid);
201308696Sshurd		return ETIMEDOUT;
202308696Sshurd	}
203308696Sshurd
204308696Sshurd	err = le16toh(resp->error_code);
205308696Sshurd	if (err) {
206308696Sshurd		/* HWRM_ERR_CODE_FAIL is a "normal" error, don't log */
207308696Sshurd		if (err != HWRM_ERR_CODE_FAIL) {
208308696Sshurd			device_printf(softc->dev,
209308696Sshurd			    "%s command returned %s error.\n",
210308696Sshurd			    GET_HWRM_REQ_TYPE(req->req_type),
211308696Sshurd			    GET_HWRM_ERROR_CODE(err));
212308696Sshurd		}
213308696Sshurd		return bnxt_hwrm_err_map(err);
214308696Sshurd	}
215308696Sshurd
216308696Sshurd	return 0;
217308696Sshurd}
218308696Sshurd
219308696Sshurdstatic int
220308696Sshurdhwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len)
221308696Sshurd{
222308696Sshurd	int rc;
223308696Sshurd
224308696Sshurd	BNXT_HWRM_LOCK(softc);
225308696Sshurd	rc = _hwrm_send_message(softc, msg, msg_len);
226308696Sshurd	BNXT_HWRM_UNLOCK(softc);
227308696Sshurd	return rc;
228308696Sshurd}
229308696Sshurd
230308696Sshurdint
231308696Sshurdbnxt_hwrm_queue_qportcfg(struct bnxt_softc *softc)
232308696Sshurd{
233308696Sshurd	struct hwrm_queue_qportcfg_input req = {0};
234308696Sshurd	struct hwrm_queue_qportcfg_output *resp =
235308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
236308696Sshurd
237308696Sshurd	int	rc = 0;
238308696Sshurd	uint8_t	*qptr;
239308696Sshurd
240308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_QPORTCFG);
241308696Sshurd
242308696Sshurd	BNXT_HWRM_LOCK(softc);
243308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
244308696Sshurd	if (rc)
245308696Sshurd		goto qportcfg_exit;
246308696Sshurd
247308696Sshurd	if (!resp->max_configurable_queues) {
248308696Sshurd		rc = -EINVAL;
249308696Sshurd		goto qportcfg_exit;
250308696Sshurd	}
251308696Sshurd	softc->max_tc = resp->max_configurable_queues;
252308696Sshurd	if (softc->max_tc > BNXT_MAX_QUEUE)
253308696Sshurd		softc->max_tc = BNXT_MAX_QUEUE;
254308696Sshurd
255308696Sshurd	qptr = &resp->queue_id0;
256308696Sshurd	for (int i = 0; i < softc->max_tc; i++) {
257308696Sshurd		softc->q_info[i].id = *qptr++;
258308696Sshurd		softc->q_info[i].profile = *qptr++;
259308696Sshurd	}
260308696Sshurd
261308696Sshurdqportcfg_exit:
262308696Sshurd	BNXT_HWRM_UNLOCK(softc);
263308696Sshurd	return (rc);
264308696Sshurd}
265308696Sshurd
266308696Sshurd
267308696Sshurdint
268308696Sshurdbnxt_hwrm_ver_get(struct bnxt_softc *softc)
269308696Sshurd{
270308696Sshurd	struct hwrm_ver_get_input	req = {0};
271308696Sshurd	struct hwrm_ver_get_output	*resp =
272308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
273308696Sshurd	int				rc;
274308696Sshurd	const char nastr[] = "<not installed>";
275308696Sshurd	const char naver[] = "<N/A>";
276333364Sshurd	uint32_t dev_caps_cfg;
277308696Sshurd
278308696Sshurd	softc->hwrm_max_req_len = HWRM_MAX_REQ_LEN;
279308696Sshurd	softc->hwrm_cmd_timeo = 1000;
280308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VER_GET);
281308696Sshurd
282308696Sshurd	req.hwrm_intf_maj = HWRM_VERSION_MAJOR;
283308696Sshurd	req.hwrm_intf_min = HWRM_VERSION_MINOR;
284308696Sshurd	req.hwrm_intf_upd = HWRM_VERSION_UPDATE;
285308696Sshurd
286308696Sshurd	BNXT_HWRM_LOCK(softc);
287308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
288308696Sshurd	if (rc)
289308696Sshurd		goto fail;
290308696Sshurd
291308696Sshurd	snprintf(softc->ver_info->hwrm_if_ver, BNXT_VERSTR_SIZE, "%d.%d.%d",
292308696Sshurd	    resp->hwrm_intf_maj, resp->hwrm_intf_min, resp->hwrm_intf_upd);
293308696Sshurd	softc->ver_info->hwrm_if_major = resp->hwrm_intf_maj;
294308696Sshurd	softc->ver_info->hwrm_if_minor = resp->hwrm_intf_min;
295308696Sshurd	softc->ver_info->hwrm_if_update = resp->hwrm_intf_upd;
296308696Sshurd	snprintf(softc->ver_info->hwrm_fw_ver, BNXT_VERSTR_SIZE, "%d.%d.%d",
297308696Sshurd	    resp->hwrm_fw_maj, resp->hwrm_fw_min, resp->hwrm_fw_bld);
298308696Sshurd	strlcpy(softc->ver_info->driver_hwrm_if_ver, HWRM_VERSION_STR,
299308696Sshurd	    BNXT_VERSTR_SIZE);
300308696Sshurd	strlcpy(softc->ver_info->hwrm_fw_name, resp->hwrm_fw_name,
301308696Sshurd	    BNXT_NAME_SIZE);
302308696Sshurd
303308696Sshurd	if (resp->mgmt_fw_maj == 0 && resp->mgmt_fw_min == 0 &&
304308696Sshurd	    resp->mgmt_fw_bld == 0) {
305308696Sshurd		strlcpy(softc->ver_info->mgmt_fw_ver, naver, BNXT_VERSTR_SIZE);
306308696Sshurd		strlcpy(softc->ver_info->mgmt_fw_name, nastr, BNXT_NAME_SIZE);
307308696Sshurd	}
308308696Sshurd	else {
309308696Sshurd		snprintf(softc->ver_info->mgmt_fw_ver, BNXT_VERSTR_SIZE,
310308696Sshurd		    "%d.%d.%d", resp->mgmt_fw_maj, resp->mgmt_fw_min,
311308696Sshurd		    resp->mgmt_fw_bld);
312308696Sshurd		strlcpy(softc->ver_info->mgmt_fw_name, resp->mgmt_fw_name,
313308696Sshurd		    BNXT_NAME_SIZE);
314308696Sshurd	}
315308696Sshurd	if (resp->netctrl_fw_maj == 0 && resp->netctrl_fw_min == 0 &&
316308696Sshurd	    resp->netctrl_fw_bld == 0) {
317308696Sshurd		strlcpy(softc->ver_info->netctrl_fw_ver, naver,
318308696Sshurd		    BNXT_VERSTR_SIZE);
319308696Sshurd		strlcpy(softc->ver_info->netctrl_fw_name, nastr,
320308696Sshurd		    BNXT_NAME_SIZE);
321308696Sshurd	}
322308696Sshurd	else {
323308696Sshurd		snprintf(softc->ver_info->netctrl_fw_ver, BNXT_VERSTR_SIZE,
324308696Sshurd		    "%d.%d.%d", resp->netctrl_fw_maj, resp->netctrl_fw_min,
325308696Sshurd		    resp->netctrl_fw_bld);
326308696Sshurd		strlcpy(softc->ver_info->netctrl_fw_name, resp->netctrl_fw_name,
327308696Sshurd		    BNXT_NAME_SIZE);
328308696Sshurd	}
329308696Sshurd	if (resp->roce_fw_maj == 0 && resp->roce_fw_min == 0 &&
330308696Sshurd	    resp->roce_fw_bld == 0) {
331308696Sshurd		strlcpy(softc->ver_info->roce_fw_ver, naver, BNXT_VERSTR_SIZE);
332308696Sshurd		strlcpy(softc->ver_info->roce_fw_name, nastr, BNXT_NAME_SIZE);
333308696Sshurd	}
334308696Sshurd	else {
335308696Sshurd		snprintf(softc->ver_info->roce_fw_ver, BNXT_VERSTR_SIZE,
336308696Sshurd		    "%d.%d.%d", resp->roce_fw_maj, resp->roce_fw_min,
337308696Sshurd		    resp->roce_fw_bld);
338308696Sshurd		strlcpy(softc->ver_info->roce_fw_name, resp->roce_fw_name,
339308696Sshurd		    BNXT_NAME_SIZE);
340308696Sshurd	}
341308696Sshurd	softc->ver_info->chip_num = le16toh(resp->chip_num);
342308696Sshurd	softc->ver_info->chip_rev = resp->chip_rev;
343308696Sshurd	softc->ver_info->chip_metal = resp->chip_metal;
344308696Sshurd	softc->ver_info->chip_bond_id = resp->chip_bond_id;
345308696Sshurd	softc->ver_info->chip_type = resp->chip_platform_type;
346308696Sshurd
347308696Sshurd	if (resp->max_req_win_len)
348308696Sshurd		softc->hwrm_max_req_len = le16toh(resp->max_req_win_len);
349308696Sshurd	if (resp->def_req_timeout)
350308696Sshurd		softc->hwrm_cmd_timeo = le16toh(resp->def_req_timeout);
351308696Sshurd
352333364Sshurd	dev_caps_cfg = le32toh(resp->dev_caps_cfg);
353333364Sshurd	if ((dev_caps_cfg & HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED) &&
354333364Sshurd	    (dev_caps_cfg & HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_REQUIRED))
355333364Sshurd		softc->flags |= BNXT_FLAG_SHORT_CMD;
356333364Sshurd
357308696Sshurdfail:
358308696Sshurd	BNXT_HWRM_UNLOCK(softc);
359308696Sshurd	return rc;
360308696Sshurd}
361308696Sshurd
362308696Sshurdint
363308696Sshurdbnxt_hwrm_func_drv_rgtr(struct bnxt_softc *softc)
364308696Sshurd{
365308696Sshurd	struct hwrm_func_drv_rgtr_input req = {0};
366308696Sshurd
367308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR);
368308696Sshurd
369308696Sshurd	req.enables = htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_VER |
370308696Sshurd	    HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_OS_TYPE);
371308696Sshurd	req.os_type = htole16(HWRM_FUNC_DRV_RGTR_INPUT_OS_TYPE_FREEBSD);
372308696Sshurd
373308696Sshurd	req.ver_maj = __FreeBSD_version / 100000;
374308696Sshurd	req.ver_min = (__FreeBSD_version / 1000) % 100;
375308696Sshurd	req.ver_upd = (__FreeBSD_version / 100) % 10;
376308696Sshurd
377308696Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
378308696Sshurd}
379308696Sshurd
380308696Sshurd
381308696Sshurdint
382308696Sshurdbnxt_hwrm_func_drv_unrgtr(struct bnxt_softc *softc, bool shutdown)
383308696Sshurd{
384308696Sshurd	struct hwrm_func_drv_unrgtr_input req = {0};
385308696Sshurd
386308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_UNRGTR);
387308696Sshurd	if (shutdown == true)
388308696Sshurd		req.flags |=
389308696Sshurd		    HWRM_FUNC_DRV_UNRGTR_INPUT_FLAGS_PREPARE_FOR_SHUTDOWN;
390308696Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
391308696Sshurd}
392308696Sshurd
393308696Sshurd
394308696Sshurdstatic inline int
395308696Sshurd_is_valid_ether_addr(uint8_t *addr)
396308696Sshurd{
397308696Sshurd	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
398308696Sshurd
399308696Sshurd	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
400308696Sshurd		return (FALSE);
401308696Sshurd
402308696Sshurd	return (TRUE);
403308696Sshurd}
404308696Sshurd
405308696Sshurdstatic inline void
406308696Sshurdget_random_ether_addr(uint8_t *addr)
407308696Sshurd{
408308696Sshurd	uint8_t temp[ETHER_ADDR_LEN];
409308696Sshurd
410308696Sshurd	arc4rand(&temp, sizeof(temp), 0);
411308696Sshurd	temp[0] &= 0xFE;
412308696Sshurd	temp[0] |= 0x02;
413308696Sshurd	bcopy(temp, addr, sizeof(temp));
414308696Sshurd}
415308696Sshurd
416308696Sshurdint
417308696Sshurdbnxt_hwrm_func_qcaps(struct bnxt_softc *softc)
418308696Sshurd{
419308696Sshurd	int rc = 0;
420308696Sshurd	struct hwrm_func_qcaps_input req = {0};
421308696Sshurd	struct hwrm_func_qcaps_output *resp =
422308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
423308696Sshurd	struct bnxt_func_info *func = &softc->func;
424308696Sshurd
425308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCAPS);
426308696Sshurd	req.fid = htole16(0xffff);
427308696Sshurd
428308696Sshurd	BNXT_HWRM_LOCK(softc);
429308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
430308696Sshurd	if (rc)
431308696Sshurd		goto fail;
432308696Sshurd
433333364Sshurd	if (resp->flags &
434333364Sshurd	    htole32(HWRM_FUNC_QCAPS_OUTPUT_FLAGS_WOL_MAGICPKT_SUPPORTED))
435333364Sshurd		softc->flags |= BNXT_FLAG_WOL_CAP;
436333364Sshurd
437308696Sshurd	func->fw_fid = le16toh(resp->fid);
438308696Sshurd	memcpy(func->mac_addr, resp->mac_address, ETHER_ADDR_LEN);
439308696Sshurd	func->max_rsscos_ctxs = le16toh(resp->max_rsscos_ctx);
440308696Sshurd	func->max_cp_rings = le16toh(resp->max_cmpl_rings);
441308696Sshurd	func->max_tx_rings = le16toh(resp->max_tx_rings);
442308696Sshurd	func->max_rx_rings = le16toh(resp->max_rx_rings);
443308696Sshurd	func->max_hw_ring_grps = le32toh(resp->max_hw_ring_grps);
444308696Sshurd	if (!func->max_hw_ring_grps)
445308696Sshurd		func->max_hw_ring_grps = func->max_tx_rings;
446308696Sshurd	func->max_l2_ctxs = le16toh(resp->max_l2_ctxs);
447308696Sshurd	func->max_vnics = le16toh(resp->max_vnics);
448308696Sshurd	func->max_stat_ctxs = le16toh(resp->max_stat_ctx);
449308696Sshurd	if (BNXT_PF(softc)) {
450308696Sshurd		struct bnxt_pf_info *pf = &softc->pf;
451308696Sshurd
452308696Sshurd		pf->port_id = le16toh(resp->port_id);
453308696Sshurd		pf->first_vf_id = le16toh(resp->first_vf_id);
454308696Sshurd		pf->max_vfs = le16toh(resp->max_vfs);
455308696Sshurd		pf->max_encap_records = le32toh(resp->max_encap_records);
456308696Sshurd		pf->max_decap_records = le32toh(resp->max_decap_records);
457308696Sshurd		pf->max_tx_em_flows = le32toh(resp->max_tx_em_flows);
458308696Sshurd		pf->max_tx_wm_flows = le32toh(resp->max_tx_wm_flows);
459308696Sshurd		pf->max_rx_em_flows = le32toh(resp->max_rx_em_flows);
460308696Sshurd		pf->max_rx_wm_flows = le32toh(resp->max_rx_wm_flows);
461308696Sshurd	}
462308696Sshurd	if (!_is_valid_ether_addr(func->mac_addr)) {
463309377Sshurd		device_printf(softc->dev, "Invalid ethernet address, generating random locally administered address\n");
464308696Sshurd		get_random_ether_addr(func->mac_addr);
465308696Sshurd	}
466308696Sshurd
467308696Sshurdfail:
468308696Sshurd	BNXT_HWRM_UNLOCK(softc);
469308696Sshurd	return rc;
470308696Sshurd}
471308696Sshurd
472333364Sshurdint
473333364Sshurdbnxt_hwrm_func_qcfg(struct bnxt_softc *softc)
474333364Sshurd{
475333364Sshurd        struct hwrm_func_qcfg_input req = {0};
476333364Sshurd        struct hwrm_func_qcfg_output *resp =
477333364Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
478333364Sshurd	struct bnxt_func_qcfg *fn_qcfg = &softc->fn_qcfg;
479333364Sshurd        int rc;
480333364Sshurd
481333364Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCFG);
482333364Sshurd        req.fid = htole16(0xffff);
483333364Sshurd	BNXT_HWRM_LOCK(softc);
484333364Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
485333364Sshurd        if (rc)
486333364Sshurd		goto fail;
487333364Sshurd
488333364Sshurd	fn_qcfg->alloc_completion_rings = le16toh(resp->alloc_cmpl_rings);
489333364Sshurd	fn_qcfg->alloc_tx_rings = le16toh(resp->alloc_tx_rings);
490333364Sshurd	fn_qcfg->alloc_rx_rings = le16toh(resp->alloc_rx_rings);
491333364Sshurd	fn_qcfg->alloc_vnics = le16toh(resp->alloc_vnics);
492333364Sshurdfail:
493333364Sshurd	BNXT_HWRM_UNLOCK(softc);
494333364Sshurd        return rc;
495333364Sshurd}
496333364Sshurd
497308696Sshurdint
498308696Sshurdbnxt_hwrm_func_reset(struct bnxt_softc *softc)
499308696Sshurd{
500308696Sshurd	struct hwrm_func_reset_input req = {0};
501308696Sshurd
502308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_RESET);
503308696Sshurd	req.enables = 0;
504308696Sshurd
505308696Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
506308696Sshurd}
507308696Sshurd
508308696Sshurdstatic void
509308696Sshurdbnxt_hwrm_set_link_common(struct bnxt_softc *softc,
510308696Sshurd    struct hwrm_port_phy_cfg_input *req)
511308696Sshurd{
512308696Sshurd	uint8_t autoneg = softc->link_info.autoneg;
513308696Sshurd	uint16_t fw_link_speed = softc->link_info.req_link_speed;
514308696Sshurd
515308696Sshurd	if (autoneg & BNXT_AUTONEG_SPEED) {
516308696Sshurd		req->auto_mode |=
517308696Sshurd		    HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_ALL_SPEEDS;
518308696Sshurd
519308696Sshurd		req->enables |=
520308696Sshurd		    htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE);
521308696Sshurd		req->flags |=
522308696Sshurd		    htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG);
523308696Sshurd	} else {
524308696Sshurd		req->force_link_speed = htole16(fw_link_speed);
525308696Sshurd		req->flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE);
526308696Sshurd	}
527308696Sshurd
528308696Sshurd	/* tell chimp that the setting takes effect immediately */
529308696Sshurd	req->flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESET_PHY);
530308696Sshurd}
531308696Sshurd
532308696Sshurd
533308696Sshurdstatic void
534308696Sshurdbnxt_hwrm_set_pause_common(struct bnxt_softc *softc,
535308696Sshurd    struct hwrm_port_phy_cfg_input *req)
536308696Sshurd{
537333364Sshurd	struct bnxt_link_info *link_info = &softc->link_info;
538333364Sshurd
539333364Sshurd	if (link_info->flow_ctrl.autoneg) {
540308696Sshurd		req->auto_pause =
541308696Sshurd		    HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_AUTONEG_PAUSE;
542333364Sshurd		if (link_info->flow_ctrl.rx)
543308696Sshurd			req->auto_pause |=
544308696Sshurd			    HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_RX;
545333364Sshurd		if (link_info->flow_ctrl.tx)
546308696Sshurd			req->auto_pause |=
547333364Sshurd			    HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_TX;
548308696Sshurd		req->enables |=
549308696Sshurd		    htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_PAUSE);
550308696Sshurd	} else {
551333364Sshurd		if (link_info->flow_ctrl.rx)
552308696Sshurd			req->force_pause |=
553308696Sshurd			    HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_RX;
554333364Sshurd		if (link_info->flow_ctrl.tx)
555308696Sshurd			req->force_pause |=
556308696Sshurd			    HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_TX;
557308696Sshurd		req->enables |=
558308696Sshurd			htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_FORCE_PAUSE);
559308696Sshurd	}
560308696Sshurd}
561308696Sshurd
562308696Sshurd
563308696Sshurd/* JFV this needs interface connection */
564308696Sshurdstatic void
565308696Sshurdbnxt_hwrm_set_eee(struct bnxt_softc *softc, struct hwrm_port_phy_cfg_input *req)
566308696Sshurd{
567308696Sshurd	/* struct ethtool_eee *eee = &softc->eee; */
568308696Sshurd	bool	eee_enabled = false;
569308696Sshurd
570308696Sshurd	if (eee_enabled) {
571308696Sshurd#if 0
572308696Sshurd		uint16_t eee_speeds;
573308696Sshurd		uint32_t flags = HWRM_PORT_PHY_CFG_INPUT_FLAGS_EEE_ENABLE;
574308696Sshurd
575308696Sshurd		if (eee->tx_lpi_enabled)
576308696Sshurd			flags |= HWRM_PORT_PHY_CFG_INPUT_FLAGS_EEE_TX_LPI;
577308696Sshurd
578308696Sshurd		req->flags |= htole32(flags);
579308696Sshurd		eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised);
580308696Sshurd		req->eee_link_speed_mask = htole16(eee_speeds);
581308696Sshurd		req->tx_lpi_timer = htole32(eee->tx_lpi_timer);
582308696Sshurd#endif
583308696Sshurd	} else {
584308696Sshurd		req->flags |=
585308696Sshurd		    htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_EEE_DISABLE);
586308696Sshurd	}
587308696Sshurd}
588308696Sshurd
589308696Sshurd
590308696Sshurdint
591308696Sshurdbnxt_hwrm_set_link_setting(struct bnxt_softc *softc, bool set_pause,
592333364Sshurd    bool set_eee, bool set_link)
593308696Sshurd{
594308696Sshurd	struct hwrm_port_phy_cfg_input req = {0};
595333364Sshurd	int rc;
596308696Sshurd
597308696Sshurd	if (softc->flags & BNXT_FLAG_NPAR)
598308696Sshurd		return ENOTSUP;
599308696Sshurd
600308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_CFG);
601333364Sshurd
602333364Sshurd	if (set_pause) {
603308696Sshurd		bnxt_hwrm_set_pause_common(softc, &req);
604308696Sshurd
605333364Sshurd		if (softc->link_info.flow_ctrl.autoneg)
606333364Sshurd			set_link = true;
607333364Sshurd	}
608333364Sshurd
609333364Sshurd	if (set_link)
610333364Sshurd		bnxt_hwrm_set_link_common(softc, &req);
611333364Sshurd
612308696Sshurd	if (set_eee)
613308696Sshurd		bnxt_hwrm_set_eee(softc, &req);
614333364Sshurd
615308696Sshurd	BNXT_HWRM_LOCK(softc);
616308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
617333364Sshurd
618333364Sshurd	if (!rc) {
619333364Sshurd		if (set_pause) {
620333364Sshurd			/* since changing of 'force pause' setting doesn't
621333364Sshurd			 * trigger any link change event, the driver needs to
622333364Sshurd			 * update the current pause result upon successfully i
623333364Sshurd			 * return of the phy_cfg command */
624333364Sshurd			if (!softc->link_info.flow_ctrl.autoneg)
625333364Sshurd				bnxt_report_link(softc);
626333364Sshurd		}
627308696Sshurd	}
628308696Sshurd	BNXT_HWRM_UNLOCK(softc);
629308696Sshurd	return rc;
630308696Sshurd}
631308696Sshurd
632308696Sshurdint
633308696Sshurdbnxt_hwrm_vnic_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
634308696Sshurd{
635308696Sshurd	struct hwrm_vnic_cfg_input req = {0};
636308696Sshurd	struct hwrm_vnic_cfg_output *resp;
637308696Sshurd
638308696Sshurd	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
639308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_CFG);
640308696Sshurd
641308696Sshurd	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
642308696Sshurd		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_DEFAULT);
643308696Sshurd	if (vnic->flags & BNXT_VNIC_FLAG_BD_STALL)
644308696Sshurd		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_BD_STALL_MODE);
645308696Sshurd	if (vnic->flags & BNXT_VNIC_FLAG_VLAN_STRIP)
646308696Sshurd		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_VLAN_STRIP_MODE);
647308696Sshurd	req.enables = htole32(HWRM_VNIC_CFG_INPUT_ENABLES_DFLT_RING_GRP |
648308696Sshurd	    HWRM_VNIC_CFG_INPUT_ENABLES_RSS_RULE |
649308696Sshurd	    HWRM_VNIC_CFG_INPUT_ENABLES_MRU);
650308696Sshurd	req.vnic_id = htole16(vnic->id);
651308696Sshurd	req.dflt_ring_grp = htole16(vnic->def_ring_grp);
652308696Sshurd	req.rss_rule = htole16(vnic->rss_id);
653308696Sshurd	req.cos_rule = htole16(vnic->cos_rule);
654308696Sshurd	req.lb_rule = htole16(vnic->lb_rule);
655308696Sshurd	req.mru = htole16(vnic->mru);
656308696Sshurd
657308696Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
658308696Sshurd}
659308696Sshurd
660308696Sshurdint
661308696Sshurdbnxt_hwrm_vnic_alloc(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
662308696Sshurd{
663308696Sshurd	struct hwrm_vnic_alloc_input req = {0};
664308696Sshurd	struct hwrm_vnic_alloc_output *resp =
665308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
666308696Sshurd	int rc;
667308696Sshurd
668308696Sshurd	if (vnic->id != (uint16_t)HWRM_NA_SIGNATURE) {
669308696Sshurd		device_printf(softc->dev,
670308696Sshurd		    "Attempt to re-allocate vnic %04x\n", vnic->id);
671308696Sshurd		return EDOOFUS;
672308696Sshurd	}
673308696Sshurd
674308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_ALLOC);
675308696Sshurd
676308696Sshurd	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
677308696Sshurd		req.flags = htole32(HWRM_VNIC_ALLOC_INPUT_FLAGS_DEFAULT);
678308696Sshurd
679308696Sshurd	BNXT_HWRM_LOCK(softc);
680308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
681308696Sshurd	if (rc)
682308696Sshurd		goto fail;
683308696Sshurd
684308696Sshurd	vnic->id = le32toh(resp->vnic_id);
685308696Sshurd
686308696Sshurdfail:
687308696Sshurd	BNXT_HWRM_UNLOCK(softc);
688308696Sshurd	return (rc);
689308696Sshurd}
690308696Sshurd
691308696Sshurdint
692308696Sshurdbnxt_hwrm_vnic_ctx_alloc(struct bnxt_softc *softc, uint16_t *ctx_id)
693308696Sshurd{
694308696Sshurd	struct hwrm_vnic_rss_cos_lb_ctx_alloc_input req = {0};
695308696Sshurd	struct hwrm_vnic_rss_cos_lb_ctx_alloc_output *resp =
696308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
697308696Sshurd	int rc;
698308696Sshurd
699308696Sshurd	if (*ctx_id != (uint16_t)HWRM_NA_SIGNATURE) {
700308696Sshurd		device_printf(softc->dev,
701308696Sshurd		    "Attempt to re-allocate vnic ctx %04x\n", *ctx_id);
702308696Sshurd		return EDOOFUS;
703308696Sshurd	}
704308696Sshurd
705308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_COS_LB_CTX_ALLOC);
706308696Sshurd
707308696Sshurd	BNXT_HWRM_LOCK(softc);
708308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
709308696Sshurd	if (rc)
710308696Sshurd		goto fail;
711308696Sshurd
712308696Sshurd	*ctx_id = le32toh(resp->rss_cos_lb_ctx_id);
713308696Sshurd
714308696Sshurdfail:
715308696Sshurd	BNXT_HWRM_UNLOCK(softc);
716308696Sshurd	return (rc);
717308696Sshurd}
718308696Sshurd
719308696Sshurdint
720308696Sshurdbnxt_hwrm_ring_grp_alloc(struct bnxt_softc *softc, struct bnxt_grp_info *grp)
721308696Sshurd{
722308696Sshurd	struct hwrm_ring_grp_alloc_input req = {0};
723308696Sshurd	struct hwrm_ring_grp_alloc_output *resp;
724308696Sshurd	int rc = 0;
725308696Sshurd
726308696Sshurd	if (grp->grp_id != (uint16_t)HWRM_NA_SIGNATURE) {
727308696Sshurd		device_printf(softc->dev,
728308696Sshurd		    "Attempt to re-allocate ring group %04x\n", grp->grp_id);
729308696Sshurd		return EDOOFUS;
730308696Sshurd	}
731308696Sshurd
732308696Sshurd	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
733308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_GRP_ALLOC);
734308696Sshurd	req.cr = htole16(grp->cp_ring_id);
735308696Sshurd	req.rr = htole16(grp->rx_ring_id);
736308696Sshurd	req.ar = htole16(grp->ag_ring_id);
737308696Sshurd	req.sc = htole16(grp->stats_ctx);
738308696Sshurd
739308696Sshurd	BNXT_HWRM_LOCK(softc);
740308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
741308696Sshurd	if (rc)
742308696Sshurd		goto fail;
743308696Sshurd
744308696Sshurd	grp->grp_id = le32toh(resp->ring_group_id);
745308696Sshurd
746308696Sshurdfail:
747308696Sshurd	BNXT_HWRM_UNLOCK(softc);
748308696Sshurd	return rc;
749308696Sshurd}
750308696Sshurd
751308696Sshurd/*
752308696Sshurd * Ring allocation message to the firmware
753308696Sshurd */
754308696Sshurdint
755308696Sshurdbnxt_hwrm_ring_alloc(struct bnxt_softc *softc, uint8_t type,
756308696Sshurd    struct bnxt_ring *ring, uint16_t cmpl_ring_id, uint32_t stat_ctx_id,
757308696Sshurd    bool irq)
758308696Sshurd{
759308696Sshurd	struct hwrm_ring_alloc_input req = {0};
760308696Sshurd	struct hwrm_ring_alloc_output *resp;
761308696Sshurd	int rc;
762308696Sshurd
763308696Sshurd	if (ring->phys_id != (uint16_t)HWRM_NA_SIGNATURE) {
764308696Sshurd		device_printf(softc->dev,
765308696Sshurd		    "Attempt to re-allocate ring %04x\n", ring->phys_id);
766308696Sshurd		return EDOOFUS;
767308696Sshurd	}
768308696Sshurd
769308696Sshurd	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
770308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_ALLOC);
771308696Sshurd	req.enables = htole32(0);
772308696Sshurd	req.fbo = htole32(0);
773308696Sshurd
774308696Sshurd	if (stat_ctx_id != HWRM_NA_SIGNATURE) {
775308696Sshurd		req.enables |= htole32(
776308696Sshurd		    HWRM_RING_ALLOC_INPUT_ENABLES_STAT_CTX_ID_VALID);
777308696Sshurd		req.stat_ctx_id = htole32(stat_ctx_id);
778308696Sshurd	}
779308696Sshurd	req.ring_type = type;
780308696Sshurd	req.page_tbl_addr = htole64(ring->paddr);
781308696Sshurd	req.length = htole32(ring->ring_size);
782308696Sshurd	req.logical_id = htole16(ring->id);
783308696Sshurd	req.cmpl_ring_id = htole16(cmpl_ring_id);
784308696Sshurd	req.queue_id = htole16(softc->q_info[0].id);
785308696Sshurd#if 0
786308696Sshurd	/* MODE_POLL appears to crash the firmware */
787308696Sshurd	if (irq)
788308696Sshurd		req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX;
789308696Sshurd	else
790308696Sshurd		req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_POLL;
791308696Sshurd#else
792308696Sshurd	req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX;
793308696Sshurd#endif
794308696Sshurd	BNXT_HWRM_LOCK(softc);
795308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
796308696Sshurd	if (rc)
797308696Sshurd		goto fail;
798308696Sshurd
799308696Sshurd	ring->phys_id = le16toh(resp->ring_id);
800308696Sshurd
801308696Sshurdfail:
802308696Sshurd	BNXT_HWRM_UNLOCK(softc);
803308696Sshurd	return rc;
804308696Sshurd}
805308696Sshurd
806308696Sshurdint
807308696Sshurdbnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr,
808308696Sshurd    uint64_t paddr)
809308696Sshurd{
810308696Sshurd	struct hwrm_stat_ctx_alloc_input req = {0};
811308696Sshurd	struct hwrm_stat_ctx_alloc_output *resp;
812308696Sshurd	int rc = 0;
813308696Sshurd
814308696Sshurd	if (cpr->stats_ctx_id != HWRM_NA_SIGNATURE) {
815308696Sshurd		device_printf(softc->dev,
816308696Sshurd		    "Attempt to re-allocate stats ctx %08x\n",
817308696Sshurd		    cpr->stats_ctx_id);
818308696Sshurd		return EDOOFUS;
819308696Sshurd	}
820308696Sshurd
821308696Sshurd	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
822308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_STAT_CTX_ALLOC);
823308696Sshurd
824308696Sshurd	req.update_period_ms = htole32(1000);
825308696Sshurd	req.stats_dma_addr = htole64(paddr);
826308696Sshurd
827308696Sshurd	BNXT_HWRM_LOCK(softc);
828308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
829308696Sshurd	if (rc)
830308696Sshurd		goto fail;
831308696Sshurd
832308696Sshurd	cpr->stats_ctx_id = le32toh(resp->stat_ctx_id);
833308696Sshurd
834308696Sshurdfail:
835308696Sshurd	BNXT_HWRM_UNLOCK(softc);
836308696Sshurd
837308696Sshurd	return rc;
838308696Sshurd}
839308696Sshurd
840308696Sshurdint
841333364Sshurdbnxt_hwrm_port_qstats(struct bnxt_softc *softc)
842333364Sshurd{
843333364Sshurd	struct hwrm_port_qstats_input req = {0};
844333364Sshurd	int rc = 0;
845333364Sshurd
846333364Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_QSTATS);
847333364Sshurd
848333364Sshurd	req.port_id = htole16(softc->pf.port_id);
849333364Sshurd	req.rx_stat_host_addr = htole64(softc->hw_rx_port_stats.idi_paddr);
850333364Sshurd	req.tx_stat_host_addr = htole64(softc->hw_tx_port_stats.idi_paddr);
851333364Sshurd
852333364Sshurd	BNXT_HWRM_LOCK(softc);
853333364Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
854333364Sshurd	BNXT_HWRM_UNLOCK(softc);
855333364Sshurd
856333364Sshurd	return rc;
857333364Sshurd}
858333364Sshurd
859333364Sshurdint
860308696Sshurdbnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt_softc *softc,
861308696Sshurd    struct bnxt_vnic_info *vnic)
862308696Sshurd{
863308696Sshurd	struct hwrm_cfa_l2_set_rx_mask_input req = {0};
864308696Sshurd	struct bnxt_vlan_tag *tag;
865308696Sshurd	uint32_t *tags;
866308696Sshurd	uint32_t num_vlan_tags = 0;;
867308696Sshurd	uint32_t i;
868308696Sshurd	uint32_t mask = vnic->rx_mask;
869308696Sshurd	int rc;
870308696Sshurd
871308696Sshurd	SLIST_FOREACH(tag, &vnic->vlan_tags, next)
872308696Sshurd		num_vlan_tags++;
873308696Sshurd
874308696Sshurd	if (num_vlan_tags) {
875308696Sshurd		if (!(mask &
876308696Sshurd		    HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ANYVLAN_NONVLAN)) {
877308696Sshurd			if (!vnic->vlan_only)
878308696Sshurd				mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLAN_NONVLAN;
879308696Sshurd			else
880308696Sshurd				mask |=
881308696Sshurd				    HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLANONLY;
882308696Sshurd		}
883308696Sshurd		if (vnic->vlan_tag_list.idi_vaddr) {
884308696Sshurd			iflib_dma_free(&vnic->vlan_tag_list);
885308696Sshurd			vnic->vlan_tag_list.idi_vaddr = NULL;
886308696Sshurd		}
887308696Sshurd		rc = iflib_dma_alloc(softc->ctx, 4 * num_vlan_tags,
888308696Sshurd		    &vnic->vlan_tag_list, BUS_DMA_NOWAIT);
889308696Sshurd		if (rc)
890308696Sshurd			return rc;
891308696Sshurd		tags = (uint32_t *)vnic->vlan_tag_list.idi_vaddr;
892308696Sshurd
893308696Sshurd		i = 0;
894308696Sshurd		SLIST_FOREACH(tag, &vnic->vlan_tags, next) {
895308696Sshurd			tags[i] = htole32((tag->tpid << 16) | tag->tag);
896308696Sshurd			i++;
897308696Sshurd		}
898308696Sshurd	}
899308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_SET_RX_MASK);
900308696Sshurd
901308696Sshurd	req.vnic_id = htole32(vnic->id);
902308696Sshurd	req.mask = htole32(mask);
903308696Sshurd	req.mc_tbl_addr = htole64(vnic->mc_list.idi_paddr);
904308696Sshurd	req.num_mc_entries = htole32(vnic->mc_list_count);
905308696Sshurd	req.vlan_tag_tbl_addr = htole64(vnic->vlan_tag_list.idi_paddr);
906308696Sshurd	req.num_vlan_tags = htole32(num_vlan_tags);
907308696Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
908308696Sshurd}
909308696Sshurd
910308696Sshurd
911308696Sshurdint
912308696Sshurdbnxt_hwrm_set_filter(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
913308696Sshurd{
914308696Sshurd	struct hwrm_cfa_l2_filter_alloc_input	req = {0};
915308696Sshurd	struct hwrm_cfa_l2_filter_alloc_output	*resp;
916308696Sshurd	uint32_t enables = 0;
917308696Sshurd	int rc = 0;
918308696Sshurd
919308696Sshurd	if (vnic->filter_id != -1) {
920308696Sshurd		device_printf(softc->dev,
921308696Sshurd		    "Attempt to re-allocate l2 ctx filter\n");
922308696Sshurd		return EDOOFUS;
923308696Sshurd	}
924308696Sshurd
925308696Sshurd	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
926308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_FILTER_ALLOC);
927308696Sshurd
928308696Sshurd	req.flags = htole32(HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX);
929308696Sshurd	enables = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR
930308696Sshurd	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR_MASK
931308696Sshurd	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_DST_ID;
932308696Sshurd	req.enables = htole32(enables);
933308696Sshurd	req.dst_id = htole16(vnic->id);
934308696Sshurd	memcpy(req.l2_addr, if_getlladdr(iflib_get_ifp(softc->ctx)),
935308696Sshurd	    ETHER_ADDR_LEN);
936308696Sshurd	memset(&req.l2_addr_mask, 0xff, sizeof(req.l2_addr_mask));
937308696Sshurd
938308696Sshurd	BNXT_HWRM_LOCK(softc);
939308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
940308696Sshurd	if (rc)
941308696Sshurd		goto fail;
942308696Sshurd
943308696Sshurd	vnic->filter_id = le64toh(resp->l2_filter_id);
944308696Sshurd	vnic->flow_id = le64toh(resp->flow_id);
945308696Sshurd
946308696Sshurdfail:
947308696Sshurd	BNXT_HWRM_UNLOCK(softc);
948308696Sshurd	return (rc);
949308696Sshurd}
950308696Sshurd
951308696Sshurdint
952308696Sshurdbnxt_hwrm_rss_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic,
953308696Sshurd    uint32_t hash_type)
954308696Sshurd{
955308696Sshurd	struct hwrm_vnic_rss_cfg_input	req = {0};
956308696Sshurd	struct hwrm_vnic_rss_cfg_output	*resp;
957308696Sshurd
958308696Sshurd	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
959308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_CFG);
960308696Sshurd
961308696Sshurd	req.hash_type = htole32(hash_type);
962308696Sshurd	req.ring_grp_tbl_addr = htole64(vnic->rss_grp_tbl.idi_paddr);
963308696Sshurd	req.hash_key_tbl_addr = htole64(vnic->rss_hash_key_tbl.idi_paddr);
964308696Sshurd	req.rss_ctx_idx = htole16(vnic->rss_id);
965308696Sshurd
966308696Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
967308696Sshurd}
968308696Sshurd
969308696Sshurdint
970333364Sshurdbnxt_cfg_async_cr(struct bnxt_softc *softc)
971308696Sshurd{
972333364Sshurd	int rc = 0;
973333364Sshurd
974333364Sshurd	if (BNXT_PF(softc)) {
975333364Sshurd		struct hwrm_func_cfg_input req = {0};
976308696Sshurd
977333364Sshurd		bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
978308696Sshurd
979333364Sshurd		req.fid = htole16(0xffff);
980333364Sshurd		req.enables = htole32(HWRM_FUNC_CFG_INPUT_ENABLES_ASYNC_EVENT_CR);
981333364Sshurd		req.async_event_cr = htole16(softc->def_cp_ring.ring.phys_id);
982308696Sshurd
983333364Sshurd		rc = hwrm_send_message(softc, &req, sizeof(req));
984333364Sshurd	}
985333364Sshurd	else {
986333364Sshurd		struct hwrm_func_vf_cfg_input req = {0};
987308696Sshurd
988333364Sshurd		bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_VF_CFG);
989333364Sshurd
990333364Sshurd		req.enables = htole32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_ASYNC_EVENT_CR);
991333364Sshurd		req.async_event_cr = htole16(softc->def_cp_ring.ring.phys_id);
992333364Sshurd
993333364Sshurd		rc = hwrm_send_message(softc, &req, sizeof(req));
994333364Sshurd	}
995333364Sshurd	return rc;
996308696Sshurd}
997308696Sshurd
998333364Sshurdvoid
999333364Sshurdbnxt_validate_hw_lro_settings(struct bnxt_softc *softc)
1000333364Sshurd{
1001333364Sshurd	softc->hw_lro.enable = min(softc->hw_lro.enable, 1);
1002333364Sshurd
1003333364Sshurd        softc->hw_lro.is_mode_gro = min(softc->hw_lro.is_mode_gro, 1);
1004333364Sshurd
1005333364Sshurd	softc->hw_lro.max_agg_segs = min(softc->hw_lro.max_agg_segs,
1006333364Sshurd		HWRM_VNIC_TPA_CFG_INPUT_MAX_AGG_SEGS_MAX);
1007333364Sshurd
1008333364Sshurd	softc->hw_lro.max_aggs = min(softc->hw_lro.max_aggs,
1009333364Sshurd		HWRM_VNIC_TPA_CFG_INPUT_MAX_AGGS_MAX);
1010333364Sshurd
1011333364Sshurd	softc->hw_lro.min_agg_len = min(softc->hw_lro.min_agg_len, BNXT_MAX_MTU);
1012333364Sshurd}
1013333364Sshurd
1014308696Sshurdint
1015333364Sshurdbnxt_hwrm_vnic_tpa_cfg(struct bnxt_softc *softc)
1016308696Sshurd{
1017308696Sshurd	struct hwrm_vnic_tpa_cfg_input req = {0};
1018333364Sshurd	uint32_t flags;
1019308696Sshurd
1020334178Sshurd	if (softc->vnic_info.id == (uint16_t) HWRM_NA_SIGNATURE) {
1021334178Sshurd		return 0;
1022334178Sshurd	}
1023334178Sshurd
1024308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_TPA_CFG);
1025308696Sshurd
1026333364Sshurd	if (softc->hw_lro.enable) {
1027333364Sshurd		flags = HWRM_VNIC_TPA_CFG_INPUT_FLAGS_TPA |
1028333364Sshurd			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_ENCAP_TPA |
1029333364Sshurd			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_ECN |
1030333364Sshurd			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_SAME_GRE_SEQ;
1031333364Sshurd
1032333364Sshurd        	if (softc->hw_lro.is_mode_gro)
1033333364Sshurd			flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_GRO;
1034333364Sshurd		else
1035333364Sshurd			flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_RSC_WND_UPDATE;
1036333364Sshurd
1037333364Sshurd		req.flags = htole32(flags);
1038308696Sshurd
1039333364Sshurd		req.enables = htole32(HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGG_SEGS |
1040333364Sshurd				HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGGS |
1041333364Sshurd				HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MIN_AGG_LEN);
1042333364Sshurd
1043333364Sshurd		req.max_agg_segs = htole16(softc->hw_lro.max_agg_segs);
1044333364Sshurd		req.max_aggs = htole16(softc->hw_lro.max_aggs);
1045333364Sshurd		req.min_agg_len = htole32(softc->hw_lro.min_agg_len);
1046333364Sshurd	}
1047333364Sshurd
1048333364Sshurd	req.vnic_id = htole16(softc->vnic_info.id);
1049333364Sshurd
1050308696Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
1051308696Sshurd}
1052308696Sshurd
1053308696Sshurdint
1054308696Sshurdbnxt_hwrm_nvm_find_dir_entry(struct bnxt_softc *softc, uint16_t type,
1055308696Sshurd    uint16_t *ordinal, uint16_t ext, uint16_t *index, bool use_index,
1056308696Sshurd    uint8_t search_opt, uint32_t *data_length, uint32_t *item_length,
1057308696Sshurd    uint32_t *fw_ver)
1058308696Sshurd{
1059308696Sshurd	struct hwrm_nvm_find_dir_entry_input req = {0};
1060308696Sshurd	struct hwrm_nvm_find_dir_entry_output *resp =
1061308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1062308696Sshurd	int	rc = 0;
1063308696Sshurd	uint32_t old_timeo;
1064308696Sshurd
1065308696Sshurd	MPASS(ordinal);
1066308696Sshurd
1067308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_FIND_DIR_ENTRY);
1068308696Sshurd	if (use_index) {
1069308696Sshurd		req.enables = htole32(
1070308696Sshurd		    HWRM_NVM_FIND_DIR_ENTRY_INPUT_ENABLES_DIR_IDX_VALID);
1071308696Sshurd		req.dir_idx = htole16(*index);
1072308696Sshurd	}
1073308696Sshurd	req.dir_type = htole16(type);
1074308696Sshurd	req.dir_ordinal = htole16(*ordinal);
1075308696Sshurd	req.dir_ext = htole16(ext);
1076308696Sshurd	req.opt_ordinal = search_opt;
1077308696Sshurd
1078308696Sshurd	BNXT_HWRM_LOCK(softc);
1079308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1080308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1081308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1082308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1083308696Sshurd	if (rc)
1084308696Sshurd		goto exit;
1085308696Sshurd
1086308696Sshurd	if (item_length)
1087308696Sshurd		*item_length = le32toh(resp->dir_item_length);
1088308696Sshurd	if (data_length)
1089308696Sshurd		*data_length = le32toh(resp->dir_data_length);
1090308696Sshurd	if (fw_ver)
1091308696Sshurd		*fw_ver = le32toh(resp->fw_ver);
1092308696Sshurd	*ordinal = le16toh(resp->dir_ordinal);
1093308696Sshurd	if (index)
1094308696Sshurd		*index = le16toh(resp->dir_idx);
1095308696Sshurd
1096308696Sshurdexit:
1097308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1098308696Sshurd	return (rc);
1099308696Sshurd}
1100308696Sshurd
1101308696Sshurdint
1102308696Sshurdbnxt_hwrm_nvm_read(struct bnxt_softc *softc, uint16_t index, uint32_t offset,
1103308696Sshurd    uint32_t length, struct iflib_dma_info *data)
1104308696Sshurd{
1105308696Sshurd	struct hwrm_nvm_read_input req = {0};
1106308696Sshurd	int rc;
1107308696Sshurd	uint32_t old_timeo;
1108308696Sshurd
1109308696Sshurd	if (length > data->idi_size) {
1110308696Sshurd		rc = EINVAL;
1111308696Sshurd		goto exit;
1112308696Sshurd	}
1113308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_READ);
1114308696Sshurd	req.host_dest_addr = htole64(data->idi_paddr);
1115308696Sshurd	req.dir_idx = htole16(index);
1116308696Sshurd	req.offset = htole32(offset);
1117308696Sshurd	req.len = htole32(length);
1118308696Sshurd	BNXT_HWRM_LOCK(softc);
1119308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1120308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1121308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1122308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1123308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1124308696Sshurd	if (rc)
1125308696Sshurd		goto exit;
1126308696Sshurd	bus_dmamap_sync(data->idi_tag, data->idi_map, BUS_DMASYNC_POSTREAD);
1127308696Sshurd
1128308696Sshurd	goto exit;
1129308696Sshurd
1130308696Sshurdexit:
1131308696Sshurd	return rc;
1132308696Sshurd}
1133308696Sshurd
1134308696Sshurdint
1135308696Sshurdbnxt_hwrm_nvm_modify(struct bnxt_softc *softc, uint16_t index, uint32_t offset,
1136308696Sshurd    void *data, bool cpyin, uint32_t length)
1137308696Sshurd{
1138308696Sshurd	struct hwrm_nvm_modify_input req = {0};
1139308696Sshurd	struct iflib_dma_info dma_data;
1140308696Sshurd	int rc;
1141308696Sshurd	uint32_t old_timeo;
1142308696Sshurd
1143308696Sshurd	if (length == 0 || !data)
1144308696Sshurd		return EINVAL;
1145308696Sshurd	rc = iflib_dma_alloc(softc->ctx, length, &dma_data,
1146308696Sshurd	    BUS_DMA_NOWAIT);
1147308696Sshurd	if (rc)
1148308696Sshurd		return ENOMEM;
1149308696Sshurd	if (cpyin) {
1150308696Sshurd		rc = copyin(data, dma_data.idi_vaddr, length);
1151308696Sshurd		if (rc)
1152308696Sshurd			goto exit;
1153308696Sshurd	}
1154308696Sshurd	else
1155308696Sshurd		memcpy(dma_data.idi_vaddr, data, length);
1156308696Sshurd	bus_dmamap_sync(dma_data.idi_tag, dma_data.idi_map,
1157308696Sshurd	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1158308696Sshurd
1159308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_MODIFY);
1160308696Sshurd	req.host_src_addr = htole64(dma_data.idi_paddr);
1161308696Sshurd	req.dir_idx = htole16(index);
1162308696Sshurd	req.offset = htole32(offset);
1163308696Sshurd	req.len = htole32(length);
1164308696Sshurd	BNXT_HWRM_LOCK(softc);
1165308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1166308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1167308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1168308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1169308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1170308696Sshurd
1171308696Sshurdexit:
1172308696Sshurd	iflib_dma_free(&dma_data);
1173308696Sshurd	return rc;
1174308696Sshurd}
1175308696Sshurd
1176308696Sshurdint
1177308696Sshurdbnxt_hwrm_fw_reset(struct bnxt_softc *softc, uint8_t processor,
1178308696Sshurd    uint8_t *selfreset)
1179308696Sshurd{
1180308696Sshurd	struct hwrm_fw_reset_input req = {0};
1181308696Sshurd	struct hwrm_fw_reset_output *resp =
1182308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1183308696Sshurd	int rc;
1184308696Sshurd
1185308696Sshurd	MPASS(selfreset);
1186308696Sshurd
1187308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_RESET);
1188308696Sshurd	req.embedded_proc_type = processor;
1189308696Sshurd	req.selfrst_status = *selfreset;
1190308696Sshurd
1191308696Sshurd	BNXT_HWRM_LOCK(softc);
1192308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1193308696Sshurd	if (rc)
1194308696Sshurd		goto exit;
1195308696Sshurd	*selfreset = resp->selfrst_status;
1196308696Sshurd
1197308696Sshurdexit:
1198308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1199308696Sshurd	return rc;
1200308696Sshurd}
1201308696Sshurd
1202308696Sshurdint
1203308696Sshurdbnxt_hwrm_fw_qstatus(struct bnxt_softc *softc, uint8_t type, uint8_t *selfreset)
1204308696Sshurd{
1205308696Sshurd	struct hwrm_fw_qstatus_input req = {0};
1206308696Sshurd	struct hwrm_fw_qstatus_output *resp =
1207308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1208308696Sshurd	int rc;
1209308696Sshurd
1210308696Sshurd	MPASS(selfreset);
1211308696Sshurd
1212308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_QSTATUS);
1213308696Sshurd	req.embedded_proc_type = type;
1214308696Sshurd
1215308696Sshurd	BNXT_HWRM_LOCK(softc);
1216308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1217308696Sshurd	if (rc)
1218308696Sshurd		goto exit;
1219308696Sshurd	*selfreset = resp->selfrst_status;
1220308696Sshurd
1221308696Sshurdexit:
1222308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1223308696Sshurd	return rc;
1224308696Sshurd}
1225308696Sshurd
1226308696Sshurdint
1227308696Sshurdbnxt_hwrm_nvm_write(struct bnxt_softc *softc, void *data, bool cpyin,
1228308696Sshurd    uint16_t type, uint16_t ordinal, uint16_t ext, uint16_t attr,
1229308696Sshurd    uint16_t option, uint32_t data_length, bool keep, uint32_t *item_length,
1230308696Sshurd    uint16_t *index)
1231308696Sshurd{
1232308696Sshurd	struct hwrm_nvm_write_input req = {0};
1233308696Sshurd	struct hwrm_nvm_write_output *resp =
1234308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1235308696Sshurd	struct iflib_dma_info dma_data;
1236308696Sshurd	int rc;
1237308696Sshurd	uint32_t old_timeo;
1238308696Sshurd
1239308696Sshurd	if (data_length) {
1240308696Sshurd		rc = iflib_dma_alloc(softc->ctx, data_length, &dma_data,
1241308696Sshurd		    BUS_DMA_NOWAIT);
1242308696Sshurd		if (rc)
1243308696Sshurd			return ENOMEM;
1244308696Sshurd		if (cpyin) {
1245308696Sshurd			rc = copyin(data, dma_data.idi_vaddr, data_length);
1246308696Sshurd			if (rc)
1247308696Sshurd				goto early_exit;
1248308696Sshurd		}
1249308696Sshurd		else
1250308696Sshurd			memcpy(dma_data.idi_vaddr, data, data_length);
1251308696Sshurd		bus_dmamap_sync(dma_data.idi_tag, dma_data.idi_map,
1252308696Sshurd		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1253308696Sshurd	}
1254308696Sshurd	else
1255308696Sshurd		dma_data.idi_paddr = 0;
1256308696Sshurd
1257308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_WRITE);
1258308696Sshurd
1259308696Sshurd	req.host_src_addr = htole64(dma_data.idi_paddr);
1260308696Sshurd	req.dir_type = htole16(type);
1261308696Sshurd	req.dir_ordinal = htole16(ordinal);
1262308696Sshurd	req.dir_ext = htole16(ext);
1263308696Sshurd	req.dir_attr = htole16(attr);
1264308696Sshurd	req.dir_data_length = htole32(data_length);
1265308696Sshurd	req.option = htole16(option);
1266308696Sshurd	if (keep) {
1267308696Sshurd		req.flags =
1268308696Sshurd		    htole16(HWRM_NVM_WRITE_INPUT_FLAGS_KEEP_ORIG_ACTIVE_IMG);
1269308696Sshurd	}
1270308696Sshurd	if (item_length)
1271308696Sshurd		req.dir_item_length = htole32(*item_length);
1272308696Sshurd
1273308696Sshurd	BNXT_HWRM_LOCK(softc);
1274308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1275308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1276308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1277308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1278308696Sshurd	if (rc)
1279308696Sshurd		goto exit;
1280308696Sshurd	if (item_length)
1281308696Sshurd		*item_length = le32toh(resp->dir_item_length);
1282308696Sshurd	if (index)
1283308696Sshurd		*index = le16toh(resp->dir_idx);
1284308696Sshurd
1285308696Sshurdexit:
1286308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1287308696Sshurdearly_exit:
1288308696Sshurd	if (data_length)
1289308696Sshurd		iflib_dma_free(&dma_data);
1290308696Sshurd	return rc;
1291308696Sshurd}
1292308696Sshurd
1293308696Sshurdint
1294308696Sshurdbnxt_hwrm_nvm_erase_dir_entry(struct bnxt_softc *softc, uint16_t index)
1295308696Sshurd{
1296308696Sshurd	struct hwrm_nvm_erase_dir_entry_input req = {0};
1297308696Sshurd	uint32_t old_timeo;
1298308696Sshurd	int rc;
1299308696Sshurd
1300308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_ERASE_DIR_ENTRY);
1301308696Sshurd	req.dir_idx = htole16(index);
1302308696Sshurd	BNXT_HWRM_LOCK(softc);
1303308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1304308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1305308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1306308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1307308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1308308696Sshurd	return rc;
1309308696Sshurd}
1310308696Sshurd
1311308696Sshurdint
1312308696Sshurdbnxt_hwrm_nvm_get_dir_info(struct bnxt_softc *softc, uint32_t *entries,
1313308696Sshurd    uint32_t *entry_length)
1314308696Sshurd{
1315308696Sshurd	struct hwrm_nvm_get_dir_info_input req = {0};
1316308696Sshurd	struct hwrm_nvm_get_dir_info_output *resp =
1317308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1318308696Sshurd	int rc;
1319308696Sshurd	uint32_t old_timeo;
1320308696Sshurd
1321308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DIR_INFO);
1322308696Sshurd
1323308696Sshurd	BNXT_HWRM_LOCK(softc);
1324308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1325308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1326308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1327308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1328308696Sshurd	if (rc)
1329308696Sshurd		goto exit;
1330308696Sshurd
1331308696Sshurd	if (entries)
1332308696Sshurd		*entries = le32toh(resp->entries);
1333308696Sshurd	if (entry_length)
1334308696Sshurd		*entry_length = le32toh(resp->entry_length);
1335308696Sshurd
1336308696Sshurdexit:
1337308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1338308696Sshurd	return rc;
1339308696Sshurd}
1340308696Sshurd
1341308696Sshurdint
1342308696Sshurdbnxt_hwrm_nvm_get_dir_entries(struct bnxt_softc *softc, uint32_t *entries,
1343308696Sshurd    uint32_t *entry_length, struct iflib_dma_info *dma_data)
1344308696Sshurd{
1345308696Sshurd	struct hwrm_nvm_get_dir_entries_input req = {0};
1346308696Sshurd	uint32_t ent;
1347308696Sshurd	uint32_t ent_len;
1348308696Sshurd	int rc;
1349308696Sshurd	uint32_t old_timeo;
1350308696Sshurd
1351308696Sshurd	if (!entries)
1352308696Sshurd		entries = &ent;
1353308696Sshurd	if (!entry_length)
1354308696Sshurd		entry_length = &ent_len;
1355308696Sshurd
1356308696Sshurd	rc = bnxt_hwrm_nvm_get_dir_info(softc, entries, entry_length);
1357308696Sshurd	if (rc)
1358308696Sshurd		goto exit;
1359308696Sshurd	if (*entries * *entry_length > dma_data->idi_size) {
1360308696Sshurd		rc = EINVAL;
1361308696Sshurd		goto exit;
1362308696Sshurd	}
1363308696Sshurd
1364308696Sshurd	/*
1365308696Sshurd	 * TODO: There's a race condition here that could blow up DMA memory...
1366308696Sshurd	 *	 we need to allocate the max size, not the currently in use
1367308696Sshurd	 *	 size.  The command should totally have a max size here.
1368308696Sshurd	 */
1369308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DIR_ENTRIES);
1370308696Sshurd	req.host_dest_addr = htole64(dma_data->idi_paddr);
1371308696Sshurd	BNXT_HWRM_LOCK(softc);
1372308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1373308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1374308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1375308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1376308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1377308696Sshurd	if (rc)
1378308696Sshurd		goto exit;
1379308696Sshurd	bus_dmamap_sync(dma_data->idi_tag, dma_data->idi_map,
1380308696Sshurd	    BUS_DMASYNC_POSTWRITE);
1381308696Sshurd
1382308696Sshurdexit:
1383308696Sshurd	return rc;
1384308696Sshurd}
1385308696Sshurd
1386308696Sshurdint
1387308696Sshurdbnxt_hwrm_nvm_get_dev_info(struct bnxt_softc *softc, uint16_t *mfg_id,
1388308696Sshurd    uint16_t *device_id, uint32_t *sector_size, uint32_t *nvram_size,
1389308696Sshurd    uint32_t *reserved_size, uint32_t *available_size)
1390308696Sshurd{
1391308696Sshurd	struct hwrm_nvm_get_dev_info_input req = {0};
1392308696Sshurd	struct hwrm_nvm_get_dev_info_output *resp =
1393308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1394308696Sshurd	int rc;
1395308696Sshurd	uint32_t old_timeo;
1396308696Sshurd
1397308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DEV_INFO);
1398308696Sshurd
1399308696Sshurd	BNXT_HWRM_LOCK(softc);
1400308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1401308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1402308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1403308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1404308696Sshurd	if (rc)
1405308696Sshurd		goto exit;
1406308696Sshurd
1407308696Sshurd	if (mfg_id)
1408308696Sshurd		*mfg_id = le16toh(resp->manufacturer_id);
1409308696Sshurd	if (device_id)
1410308696Sshurd		*device_id = le16toh(resp->device_id);
1411308696Sshurd	if (sector_size)
1412308696Sshurd		*sector_size = le32toh(resp->sector_size);
1413308696Sshurd	if (nvram_size)
1414308696Sshurd		*nvram_size = le32toh(resp->nvram_size);
1415308696Sshurd	if (reserved_size)
1416308696Sshurd		*reserved_size = le32toh(resp->reserved_size);
1417308696Sshurd	if (available_size)
1418308696Sshurd		*available_size = le32toh(resp->available_size);
1419308696Sshurd
1420308696Sshurdexit:
1421308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1422308696Sshurd	return rc;
1423308696Sshurd}
1424308696Sshurd
1425308696Sshurdint
1426308696Sshurdbnxt_hwrm_nvm_install_update(struct bnxt_softc *softc,
1427308696Sshurd    uint32_t install_type, uint64_t *installed_items, uint8_t *result,
1428308696Sshurd    uint8_t *problem_item, uint8_t *reset_required)
1429308696Sshurd{
1430308696Sshurd	struct hwrm_nvm_install_update_input req = {0};
1431308696Sshurd	struct hwrm_nvm_install_update_output *resp =
1432308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1433308696Sshurd	int rc;
1434308696Sshurd	uint32_t old_timeo;
1435308696Sshurd
1436308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_INSTALL_UPDATE);
1437308696Sshurd	req.install_type = htole32(install_type);
1438308696Sshurd
1439308696Sshurd	BNXT_HWRM_LOCK(softc);
1440308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1441308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1442308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1443308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1444308696Sshurd	if (rc)
1445308696Sshurd		goto exit;
1446308696Sshurd
1447308696Sshurd	if (installed_items)
1448308696Sshurd		*installed_items = le32toh(resp->installed_items);
1449308696Sshurd	if (result)
1450308696Sshurd		*result = resp->result;
1451308696Sshurd	if (problem_item)
1452308696Sshurd		*problem_item = resp->problem_item;
1453308696Sshurd	if (reset_required)
1454308696Sshurd		*reset_required = resp->reset_required;
1455308696Sshurd
1456308696Sshurdexit:
1457308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1458308696Sshurd	return rc;
1459308696Sshurd}
1460308696Sshurd
1461308696Sshurdint
1462308696Sshurdbnxt_hwrm_nvm_verify_update(struct bnxt_softc *softc, uint16_t type,
1463308696Sshurd    uint16_t ordinal, uint16_t ext)
1464308696Sshurd{
1465308696Sshurd	struct hwrm_nvm_verify_update_input req = {0};
1466308696Sshurd	uint32_t old_timeo;
1467308696Sshurd	int rc;
1468308696Sshurd
1469308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_VERIFY_UPDATE);
1470308696Sshurd
1471308696Sshurd	req.dir_type = htole16(type);
1472308696Sshurd	req.dir_ordinal = htole16(ordinal);
1473308696Sshurd	req.dir_ext = htole16(ext);
1474308696Sshurd
1475308696Sshurd	BNXT_HWRM_LOCK(softc);
1476308696Sshurd	old_timeo = softc->hwrm_cmd_timeo;
1477308696Sshurd	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1478308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1479308696Sshurd	softc->hwrm_cmd_timeo = old_timeo;
1480308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1481308696Sshurd	return rc;
1482308696Sshurd}
1483308696Sshurd
1484308696Sshurdint
1485308696Sshurdbnxt_hwrm_fw_get_time(struct bnxt_softc *softc, uint16_t *year, uint8_t *month,
1486308696Sshurd    uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second,
1487308696Sshurd    uint16_t *millisecond, uint16_t *zone)
1488308696Sshurd{
1489308696Sshurd	struct hwrm_fw_get_time_input req = {0};
1490308696Sshurd	struct hwrm_fw_get_time_output *resp =
1491308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1492308696Sshurd	int rc;
1493308696Sshurd
1494308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_GET_TIME);
1495308696Sshurd
1496308696Sshurd	BNXT_HWRM_LOCK(softc);
1497308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1498308696Sshurd	if (rc)
1499308696Sshurd		goto exit;
1500308696Sshurd
1501308696Sshurd	if (year)
1502308696Sshurd		*year = le16toh(resp->year);
1503308696Sshurd	if (month)
1504308696Sshurd		*month = resp->month;
1505308696Sshurd	if (day)
1506308696Sshurd		*day = resp->day;
1507308696Sshurd	if (hour)
1508308696Sshurd		*hour = resp->hour;
1509308696Sshurd	if (minute)
1510308696Sshurd		*minute = resp->minute;
1511308696Sshurd	if (second)
1512308696Sshurd		*second = resp->second;
1513308696Sshurd	if (millisecond)
1514308696Sshurd		*millisecond = le16toh(resp->millisecond);
1515308696Sshurd	if (zone)
1516308696Sshurd		*zone = le16toh(resp->zone);
1517308696Sshurd
1518308696Sshurdexit:
1519308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1520308696Sshurd	return rc;
1521308696Sshurd}
1522308696Sshurd
1523308696Sshurdint
1524308696Sshurdbnxt_hwrm_fw_set_time(struct bnxt_softc *softc, uint16_t year, uint8_t month,
1525308696Sshurd    uint8_t day, uint8_t hour, uint8_t minute, uint8_t second,
1526308696Sshurd    uint16_t millisecond, uint16_t zone)
1527308696Sshurd{
1528308696Sshurd	struct hwrm_fw_set_time_input req = {0};
1529308696Sshurd
1530308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_SET_TIME);
1531308696Sshurd
1532308696Sshurd	req.year = htole16(year);
1533308696Sshurd	req.month = month;
1534308696Sshurd	req.day = day;
1535308696Sshurd	req.hour = hour;
1536308696Sshurd	req.minute = minute;
1537308696Sshurd	req.second = second;
1538308696Sshurd	req.millisecond = htole16(millisecond);
1539308696Sshurd	req.zone = htole16(zone);
1540308696Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
1541308696Sshurd}
1542308696Sshurd
1543308696Sshurdint
1544308696Sshurdbnxt_hwrm_port_phy_qcfg(struct bnxt_softc *softc)
1545308696Sshurd{
1546308696Sshurd	struct bnxt_link_info *link_info = &softc->link_info;
1547308696Sshurd	struct hwrm_port_phy_qcfg_input req = {0};
1548308696Sshurd	struct hwrm_port_phy_qcfg_output *resp =
1549308696Sshurd	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1550308696Sshurd	int rc = 0;
1551308696Sshurd
1552308696Sshurd	BNXT_HWRM_LOCK(softc);
1553308696Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_QCFG);
1554308696Sshurd
1555308696Sshurd	rc = _hwrm_send_message(softc, &req, sizeof(req));
1556308696Sshurd	if (rc)
1557308696Sshurd		goto exit;
1558308696Sshurd
1559308696Sshurd	link_info->phy_link_status = resp->link;
1560333364Sshurd	link_info->duplex =  resp->duplex_cfg;
1561308696Sshurd	link_info->auto_mode = resp->auto_mode;
1562333364Sshurd
1563333364Sshurd        /*
1564333364Sshurd         * When AUTO_PAUSE_AUTONEG_PAUSE bit is set to 1,
1565333364Sshurd         * the advertisement of pause is enabled.
1566333364Sshurd         * 1. When the auto_mode is not set to none and this flag is set to 1,
1567333364Sshurd         *    then the auto_pause bits on this port are being advertised and
1568333364Sshurd         *    autoneg pause results are being interpreted.
1569333364Sshurd         * 2. When the auto_mode is not set to none and this flag is set to 0,
1570333364Sshurd         *    the pause is forced as indicated in force_pause, and also
1571333364Sshurd	 *    advertised as auto_pause bits, but the autoneg results are not
1572333364Sshurd	 *    interpreted since the pause configuration is being forced.
1573333364Sshurd         * 3. When the auto_mode is set to none and this flag is set to 1,
1574333364Sshurd         *    auto_pause bits should be ignored and should be set to 0.
1575333364Sshurd         */
1576333364Sshurd
1577333364Sshurd	link_info->flow_ctrl.autoneg = false;
1578333364Sshurd	link_info->flow_ctrl.tx = false;
1579333364Sshurd	link_info->flow_ctrl.rx = false;
1580333364Sshurd
1581333364Sshurd	if ((resp->auto_mode) &&
1582333364Sshurd            (resp->auto_pause & BNXT_AUTO_PAUSE_AUTONEG_PAUSE)) {
1583333364Sshurd			link_info->flow_ctrl.autoneg = true;
1584333364Sshurd	}
1585333364Sshurd
1586333364Sshurd	if (link_info->flow_ctrl.autoneg) {
1587333364Sshurd		if (resp->auto_pause & BNXT_PAUSE_TX)
1588333364Sshurd			link_info->flow_ctrl.tx = true;
1589333364Sshurd		if (resp->auto_pause & BNXT_PAUSE_RX)
1590333364Sshurd			link_info->flow_ctrl.rx = true;
1591333364Sshurd	} else {
1592333364Sshurd		if (resp->force_pause & BNXT_PAUSE_TX)
1593333364Sshurd			link_info->flow_ctrl.tx = true;
1594333364Sshurd		if (resp->force_pause & BNXT_PAUSE_RX)
1595333364Sshurd			link_info->flow_ctrl.rx = true;
1596333364Sshurd	}
1597333364Sshurd
1598333364Sshurd	link_info->duplex_setting = resp->duplex_cfg;
1599308696Sshurd	if (link_info->phy_link_status == HWRM_PORT_PHY_QCFG_OUTPUT_LINK_LINK)
1600308696Sshurd		link_info->link_speed = le16toh(resp->link_speed);
1601308696Sshurd	else
1602308696Sshurd		link_info->link_speed = 0;
1603308696Sshurd	link_info->force_link_speed = le16toh(resp->force_link_speed);
1604308696Sshurd	link_info->auto_link_speed = le16toh(resp->auto_link_speed);
1605308696Sshurd	link_info->support_speeds = le16toh(resp->support_speeds);
1606308696Sshurd	link_info->auto_link_speeds = le16toh(resp->auto_link_speed_mask);
1607308696Sshurd	link_info->preemphasis = le32toh(resp->preemphasis);
1608308696Sshurd	link_info->phy_ver[0] = resp->phy_maj;
1609308696Sshurd	link_info->phy_ver[1] = resp->phy_min;
1610308696Sshurd	link_info->phy_ver[2] = resp->phy_bld;
1611308696Sshurd	snprintf(softc->ver_info->phy_ver, sizeof(softc->ver_info->phy_ver),
1612308696Sshurd	    "%d.%d.%d", link_info->phy_ver[0], link_info->phy_ver[1],
1613308696Sshurd	    link_info->phy_ver[2]);
1614308696Sshurd	strlcpy(softc->ver_info->phy_vendor, resp->phy_vendor_name,
1615308696Sshurd	    BNXT_NAME_SIZE);
1616308696Sshurd	strlcpy(softc->ver_info->phy_partnumber, resp->phy_vendor_partnumber,
1617308696Sshurd	    BNXT_NAME_SIZE);
1618308696Sshurd	link_info->media_type = resp->media_type;
1619308696Sshurd	link_info->phy_type = resp->phy_type;
1620308696Sshurd	link_info->transceiver = resp->xcvr_pkg_type;
1621308696Sshurd	link_info->phy_addr = resp->eee_config_phy_addr &
1622308696Sshurd	    HWRM_PORT_PHY_QCFG_OUTPUT_PHY_ADDR_MASK;
1623308696Sshurd
1624308696Sshurdexit:
1625308696Sshurd	BNXT_HWRM_UNLOCK(softc);
1626308696Sshurd	return rc;
1627308696Sshurd}
1628333364Sshurd
1629333364Sshurduint16_t
1630333364Sshurdbnxt_hwrm_get_wol_fltrs(struct bnxt_softc *softc, uint16_t handle)
1631333364Sshurd{
1632333364Sshurd	struct hwrm_wol_filter_qcfg_input req = {0};
1633333364Sshurd	struct hwrm_wol_filter_qcfg_output *resp =
1634333364Sshurd			(void *)softc->hwrm_cmd_resp.idi_vaddr;
1635333364Sshurd	uint16_t next_handle = 0;
1636333364Sshurd	int rc;
1637333364Sshurd
1638333364Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_WOL_FILTER_QCFG);
1639333364Sshurd	req.port_id = htole16(softc->pf.port_id);
1640333364Sshurd	req.handle = htole16(handle);
1641333364Sshurd	rc = hwrm_send_message(softc, &req, sizeof(req));
1642333364Sshurd	if (!rc) {
1643333364Sshurd		next_handle = le16toh(resp->next_handle);
1644333364Sshurd		if (next_handle != 0) {
1645333364Sshurd			if (resp->wol_type ==
1646333364Sshurd				HWRM_WOL_FILTER_ALLOC_INPUT_WOL_TYPE_MAGICPKT) {
1647333364Sshurd				softc->wol = 1;
1648333364Sshurd				softc->wol_filter_id = resp->wol_filter_id;
1649333364Sshurd			}
1650333364Sshurd		}
1651333364Sshurd	}
1652333364Sshurd	return next_handle;
1653333364Sshurd}
1654333364Sshurd
1655333364Sshurdint
1656333364Sshurdbnxt_hwrm_alloc_wol_fltr(struct bnxt_softc *softc)
1657333364Sshurd{
1658333364Sshurd	struct hwrm_wol_filter_alloc_input req = {0};
1659333364Sshurd	struct hwrm_wol_filter_alloc_output *resp =
1660333364Sshurd		(void *)softc->hwrm_cmd_resp.idi_vaddr;
1661333364Sshurd	int rc;
1662333364Sshurd
1663333364Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_WOL_FILTER_ALLOC);
1664333364Sshurd	req.port_id = htole16(softc->pf.port_id);
1665333364Sshurd	req.wol_type = HWRM_WOL_FILTER_ALLOC_INPUT_WOL_TYPE_MAGICPKT;
1666333364Sshurd	req.enables =
1667333364Sshurd		htole32(HWRM_WOL_FILTER_ALLOC_INPUT_ENABLES_MAC_ADDRESS);
1668333364Sshurd	memcpy(req.mac_address, softc->func.mac_addr, ETHER_ADDR_LEN);
1669333364Sshurd	rc = hwrm_send_message(softc, &req, sizeof(req));
1670333364Sshurd	if (!rc)
1671333364Sshurd		softc->wol_filter_id = resp->wol_filter_id;
1672333364Sshurd
1673333364Sshurd	return rc;
1674333364Sshurd}
1675333364Sshurd
1676333364Sshurdint
1677333364Sshurdbnxt_hwrm_free_wol_fltr(struct bnxt_softc *softc)
1678333364Sshurd{
1679333364Sshurd	struct hwrm_wol_filter_free_input req = {0};
1680333364Sshurd
1681333364Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_WOL_FILTER_FREE);
1682333364Sshurd	req.port_id = htole16(softc->pf.port_id);
1683333364Sshurd	req.enables =
1684333364Sshurd		htole32(HWRM_WOL_FILTER_FREE_INPUT_ENABLES_WOL_FILTER_ID);
1685333364Sshurd	req.wol_filter_id = softc->wol_filter_id;
1686333364Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
1687333364Sshurd}
1688333364Sshurd
1689333364Sshurdstatic void bnxt_hwrm_set_coal_params(struct bnxt_softc *softc, uint32_t max_frames,
1690333364Sshurd        uint32_t buf_tmrs, uint16_t flags,
1691333364Sshurd        struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req)
1692333364Sshurd{
1693333364Sshurd        req->flags = htole16(flags);
1694333364Sshurd        req->num_cmpl_dma_aggr = htole16((uint16_t)max_frames);
1695333364Sshurd        req->num_cmpl_dma_aggr_during_int = htole16(max_frames >> 16);
1696333364Sshurd        req->cmpl_aggr_dma_tmr = htole16((uint16_t)buf_tmrs);
1697333364Sshurd        req->cmpl_aggr_dma_tmr_during_int = htole16(buf_tmrs >> 16);
1698333364Sshurd        /* Minimum time between 2 interrupts set to buf_tmr x 2 */
1699333364Sshurd        req->int_lat_tmr_min = htole16((uint16_t)buf_tmrs * 2);
1700333364Sshurd        req->int_lat_tmr_max = htole16((uint16_t)buf_tmrs * 4);
1701333364Sshurd        req->num_cmpl_aggr_int = htole16((uint16_t)max_frames * 4);
1702333364Sshurd}
1703333364Sshurd
1704333364Sshurd
1705333364Sshurdint bnxt_hwrm_set_coal(struct bnxt_softc *softc)
1706333364Sshurd{
1707333364Sshurd        int i, rc = 0;
1708333364Sshurd        struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req_rx = {0},
1709333364Sshurd                                                           req_tx = {0}, *req;
1710333364Sshurd        uint16_t max_buf, max_buf_irq;
1711333364Sshurd        uint16_t buf_tmr, buf_tmr_irq;
1712333364Sshurd        uint32_t flags;
1713333364Sshurd
1714333364Sshurd        bnxt_hwrm_cmd_hdr_init(softc, &req_rx,
1715333364Sshurd                               HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS);
1716333364Sshurd        bnxt_hwrm_cmd_hdr_init(softc, &req_tx,
1717333364Sshurd                               HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS);
1718333364Sshurd
1719333364Sshurd        /* Each rx completion (2 records) should be DMAed immediately.
1720333364Sshurd         * DMA 1/4 of the completion buffers at a time.
1721333364Sshurd         */
1722333364Sshurd        max_buf = min_t(uint16_t, softc->rx_coal_frames / 4, 2);
1723333364Sshurd        /* max_buf must not be zero */
1724333364Sshurd        max_buf = clamp_t(uint16_t, max_buf, 1, 63);
1725333364Sshurd        max_buf_irq = clamp_t(uint16_t, softc->rx_coal_frames_irq, 1, 63);
1726333364Sshurd        buf_tmr = BNXT_USEC_TO_COAL_TIMER(softc->rx_coal_usecs);
1727333364Sshurd        /* buf timer set to 1/4 of interrupt timer */
1728333364Sshurd        buf_tmr = max_t(uint16_t, buf_tmr / 4, 1);
1729333364Sshurd        buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(softc->rx_coal_usecs_irq);
1730333364Sshurd        buf_tmr_irq = max_t(uint16_t, buf_tmr_irq, 1);
1731333364Sshurd
1732333364Sshurd        flags = HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET;
1733333364Sshurd
1734333364Sshurd        /* RING_IDLE generates more IRQs for lower latency.  Enable it only
1735333364Sshurd         * if coal_usecs is less than 25 us.
1736333364Sshurd         */
1737333364Sshurd        if (softc->rx_coal_usecs < 25)
1738333364Sshurd                flags |= HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_RING_IDLE;
1739333364Sshurd
1740333364Sshurd        bnxt_hwrm_set_coal_params(softc, max_buf_irq << 16 | max_buf,
1741333364Sshurd                                  buf_tmr_irq << 16 | buf_tmr, flags, &req_rx);
1742333364Sshurd
1743333364Sshurd        /* max_buf must not be zero */
1744333364Sshurd        max_buf = clamp_t(uint16_t, softc->tx_coal_frames, 1, 63);
1745333364Sshurd        max_buf_irq = clamp_t(uint16_t, softc->tx_coal_frames_irq, 1, 63);
1746333364Sshurd        buf_tmr = BNXT_USEC_TO_COAL_TIMER(softc->tx_coal_usecs);
1747333364Sshurd        /* buf timer set to 1/4 of interrupt timer */
1748333364Sshurd        buf_tmr = max_t(uint16_t, buf_tmr / 4, 1);
1749333364Sshurd        buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(softc->tx_coal_usecs_irq);
1750333364Sshurd        buf_tmr_irq = max_t(uint16_t, buf_tmr_irq, 1);
1751333364Sshurd        flags = HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET;
1752333364Sshurd        bnxt_hwrm_set_coal_params(softc, max_buf_irq << 16 | max_buf,
1753333364Sshurd                                  buf_tmr_irq << 16 | buf_tmr, flags, &req_tx);
1754333364Sshurd
1755333364Sshurd        for (i = 0; i < softc->nrxqsets; i++) {
1756333364Sshurd
1757333364Sshurd
1758333364Sshurd		req = &req_rx;
1759333364Sshurd                /*
1760333364Sshurd                 * TBD:
1761333364Sshurd		 *      Check if Tx also needs to be done
1762333364Sshurd                 *      So far, Tx processing has been done in softirq contest
1763333364Sshurd                 *
1764333364Sshurd		 * req = &req_tx;
1765333364Sshurd		 */
1766333364Sshurd		req->ring_id = htole16(softc->grp_info[i].cp_ring_id);
1767333364Sshurd
1768333364Sshurd                rc = hwrm_send_message(softc, req, sizeof(*req));
1769333364Sshurd                if (rc)
1770333364Sshurd                        break;
1771333364Sshurd        }
1772333364Sshurd        return rc;
1773333364Sshurd}
1774333364Sshurd
1775333364Sshurd
1776333364Sshurd
1777333364Sshurdint bnxt_hwrm_func_rgtr_async_events(struct bnxt_softc *softc, unsigned long *bmap,
1778333364Sshurd                                     int bmap_size)
1779333364Sshurd{
1780333364Sshurd	struct hwrm_func_drv_rgtr_input req = {0};
1781333364Sshurd	bitstr_t *async_events_bmap;
1782333364Sshurd	uint32_t *events;
1783333364Sshurd	int i;
1784333364Sshurd
1785333364Sshurd	async_events_bmap = bit_alloc(256, M_DEVBUF, M_WAITOK|M_ZERO);
1786333364Sshurd	events = (uint32_t *)async_events_bmap;
1787333364Sshurd
1788333364Sshurd	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR);
1789333364Sshurd
1790333364Sshurd	req.enables =
1791333364Sshurd		htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_ASYNC_EVENT_FWD);
1792333364Sshurd
1793333364Sshurd	memset(async_events_bmap, 0, sizeof(256 / 8));
1794333364Sshurd
1795333364Sshurd	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE);
1796333364Sshurd	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD);
1797333364Sshurd	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED);
1798333364Sshurd	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE);
1799333364Sshurd	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE);
1800333364Sshurd
1801333364Sshurd	if (bmap && bmap_size) {
1802333364Sshurd		for (i = 0; i < bmap_size; i++) {
1803333364Sshurd			if (bit_test(bmap, i))
1804333364Sshurd				bit_set(async_events_bmap, i);
1805333364Sshurd		}
1806333364Sshurd	}
1807333364Sshurd
1808333364Sshurd	for (i = 0; i < 8; i++)
1809333364Sshurd		req.async_event_fwd[i] |= htole32(events[i]);
1810333364Sshurd
1811333364Sshurd	free(async_events_bmap, M_DEVBUF);
1812333364Sshurd
1813333364Sshurd	return hwrm_send_message(softc, &req, sizeof(req));
1814333364Sshurd}
1815