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: stable/11/sys/dev/bnxt/bnxt_hwrm.c 334178 2018-05-24 18:53:29Z shurd $");
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	struct hwrm_vnic_cfg_output *resp;
637
638	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
639	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_CFG);
640
641	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
642		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_DEFAULT);
643	if (vnic->flags & BNXT_VNIC_FLAG_BD_STALL)
644		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_BD_STALL_MODE);
645	if (vnic->flags & BNXT_VNIC_FLAG_VLAN_STRIP)
646		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_VLAN_STRIP_MODE);
647	req.enables = htole32(HWRM_VNIC_CFG_INPUT_ENABLES_DFLT_RING_GRP |
648	    HWRM_VNIC_CFG_INPUT_ENABLES_RSS_RULE |
649	    HWRM_VNIC_CFG_INPUT_ENABLES_MRU);
650	req.vnic_id = htole16(vnic->id);
651	req.dflt_ring_grp = htole16(vnic->def_ring_grp);
652	req.rss_rule = htole16(vnic->rss_id);
653	req.cos_rule = htole16(vnic->cos_rule);
654	req.lb_rule = htole16(vnic->lb_rule);
655	req.mru = htole16(vnic->mru);
656
657	return hwrm_send_message(softc, &req, sizeof(req));
658}
659
660int
661bnxt_hwrm_vnic_alloc(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
662{
663	struct hwrm_vnic_alloc_input req = {0};
664	struct hwrm_vnic_alloc_output *resp =
665	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
666	int rc;
667
668	if (vnic->id != (uint16_t)HWRM_NA_SIGNATURE) {
669		device_printf(softc->dev,
670		    "Attempt to re-allocate vnic %04x\n", vnic->id);
671		return EDOOFUS;
672	}
673
674	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_ALLOC);
675
676	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
677		req.flags = htole32(HWRM_VNIC_ALLOC_INPUT_FLAGS_DEFAULT);
678
679	BNXT_HWRM_LOCK(softc);
680	rc = _hwrm_send_message(softc, &req, sizeof(req));
681	if (rc)
682		goto fail;
683
684	vnic->id = le32toh(resp->vnic_id);
685
686fail:
687	BNXT_HWRM_UNLOCK(softc);
688	return (rc);
689}
690
691int
692bnxt_hwrm_vnic_ctx_alloc(struct bnxt_softc *softc, uint16_t *ctx_id)
693{
694	struct hwrm_vnic_rss_cos_lb_ctx_alloc_input req = {0};
695	struct hwrm_vnic_rss_cos_lb_ctx_alloc_output *resp =
696	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
697	int rc;
698
699	if (*ctx_id != (uint16_t)HWRM_NA_SIGNATURE) {
700		device_printf(softc->dev,
701		    "Attempt to re-allocate vnic ctx %04x\n", *ctx_id);
702		return EDOOFUS;
703	}
704
705	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_COS_LB_CTX_ALLOC);
706
707	BNXT_HWRM_LOCK(softc);
708	rc = _hwrm_send_message(softc, &req, sizeof(req));
709	if (rc)
710		goto fail;
711
712	*ctx_id = le32toh(resp->rss_cos_lb_ctx_id);
713
714fail:
715	BNXT_HWRM_UNLOCK(softc);
716	return (rc);
717}
718
719int
720bnxt_hwrm_ring_grp_alloc(struct bnxt_softc *softc, struct bnxt_grp_info *grp)
721{
722	struct hwrm_ring_grp_alloc_input req = {0};
723	struct hwrm_ring_grp_alloc_output *resp;
724	int rc = 0;
725
726	if (grp->grp_id != (uint16_t)HWRM_NA_SIGNATURE) {
727		device_printf(softc->dev,
728		    "Attempt to re-allocate ring group %04x\n", grp->grp_id);
729		return EDOOFUS;
730	}
731
732	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
733	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_GRP_ALLOC);
734	req.cr = htole16(grp->cp_ring_id);
735	req.rr = htole16(grp->rx_ring_id);
736	req.ar = htole16(grp->ag_ring_id);
737	req.sc = htole16(grp->stats_ctx);
738
739	BNXT_HWRM_LOCK(softc);
740	rc = _hwrm_send_message(softc, &req, sizeof(req));
741	if (rc)
742		goto fail;
743
744	grp->grp_id = le32toh(resp->ring_group_id);
745
746fail:
747	BNXT_HWRM_UNLOCK(softc);
748	return rc;
749}
750
751/*
752 * Ring allocation message to the firmware
753 */
754int
755bnxt_hwrm_ring_alloc(struct bnxt_softc *softc, uint8_t type,
756    struct bnxt_ring *ring, uint16_t cmpl_ring_id, uint32_t stat_ctx_id,
757    bool irq)
758{
759	struct hwrm_ring_alloc_input req = {0};
760	struct hwrm_ring_alloc_output *resp;
761	int rc;
762
763	if (ring->phys_id != (uint16_t)HWRM_NA_SIGNATURE) {
764		device_printf(softc->dev,
765		    "Attempt to re-allocate ring %04x\n", ring->phys_id);
766		return EDOOFUS;
767	}
768
769	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
770	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_ALLOC);
771	req.enables = htole32(0);
772	req.fbo = htole32(0);
773
774	if (stat_ctx_id != HWRM_NA_SIGNATURE) {
775		req.enables |= htole32(
776		    HWRM_RING_ALLOC_INPUT_ENABLES_STAT_CTX_ID_VALID);
777		req.stat_ctx_id = htole32(stat_ctx_id);
778	}
779	req.ring_type = type;
780	req.page_tbl_addr = htole64(ring->paddr);
781	req.length = htole32(ring->ring_size);
782	req.logical_id = htole16(ring->id);
783	req.cmpl_ring_id = htole16(cmpl_ring_id);
784	req.queue_id = htole16(softc->q_info[0].id);
785#if 0
786	/* MODE_POLL appears to crash the firmware */
787	if (irq)
788		req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX;
789	else
790		req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_POLL;
791#else
792	req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX;
793#endif
794	BNXT_HWRM_LOCK(softc);
795	rc = _hwrm_send_message(softc, &req, sizeof(req));
796	if (rc)
797		goto fail;
798
799	ring->phys_id = le16toh(resp->ring_id);
800
801fail:
802	BNXT_HWRM_UNLOCK(softc);
803	return rc;
804}
805
806int
807bnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr,
808    uint64_t paddr)
809{
810	struct hwrm_stat_ctx_alloc_input req = {0};
811	struct hwrm_stat_ctx_alloc_output *resp;
812	int rc = 0;
813
814	if (cpr->stats_ctx_id != HWRM_NA_SIGNATURE) {
815		device_printf(softc->dev,
816		    "Attempt to re-allocate stats ctx %08x\n",
817		    cpr->stats_ctx_id);
818		return EDOOFUS;
819	}
820
821	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
822	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_STAT_CTX_ALLOC);
823
824	req.update_period_ms = htole32(1000);
825	req.stats_dma_addr = htole64(paddr);
826
827	BNXT_HWRM_LOCK(softc);
828	rc = _hwrm_send_message(softc, &req, sizeof(req));
829	if (rc)
830		goto fail;
831
832	cpr->stats_ctx_id = le32toh(resp->stat_ctx_id);
833
834fail:
835	BNXT_HWRM_UNLOCK(softc);
836
837	return rc;
838}
839
840int
841bnxt_hwrm_port_qstats(struct bnxt_softc *softc)
842{
843	struct hwrm_port_qstats_input req = {0};
844	int rc = 0;
845
846	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_QSTATS);
847
848	req.port_id = htole16(softc->pf.port_id);
849	req.rx_stat_host_addr = htole64(softc->hw_rx_port_stats.idi_paddr);
850	req.tx_stat_host_addr = htole64(softc->hw_tx_port_stats.idi_paddr);
851
852	BNXT_HWRM_LOCK(softc);
853	rc = _hwrm_send_message(softc, &req, sizeof(req));
854	BNXT_HWRM_UNLOCK(softc);
855
856	return rc;
857}
858
859int
860bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt_softc *softc,
861    struct bnxt_vnic_info *vnic)
862{
863	struct hwrm_cfa_l2_set_rx_mask_input req = {0};
864	struct bnxt_vlan_tag *tag;
865	uint32_t *tags;
866	uint32_t num_vlan_tags = 0;;
867	uint32_t i;
868	uint32_t mask = vnic->rx_mask;
869	int rc;
870
871	SLIST_FOREACH(tag, &vnic->vlan_tags, next)
872		num_vlan_tags++;
873
874	if (num_vlan_tags) {
875		if (!(mask &
876		    HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ANYVLAN_NONVLAN)) {
877			if (!vnic->vlan_only)
878				mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLAN_NONVLAN;
879			else
880				mask |=
881				    HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLANONLY;
882		}
883		if (vnic->vlan_tag_list.idi_vaddr) {
884			iflib_dma_free(&vnic->vlan_tag_list);
885			vnic->vlan_tag_list.idi_vaddr = NULL;
886		}
887		rc = iflib_dma_alloc(softc->ctx, 4 * num_vlan_tags,
888		    &vnic->vlan_tag_list, BUS_DMA_NOWAIT);
889		if (rc)
890			return rc;
891		tags = (uint32_t *)vnic->vlan_tag_list.idi_vaddr;
892
893		i = 0;
894		SLIST_FOREACH(tag, &vnic->vlan_tags, next) {
895			tags[i] = htole32((tag->tpid << 16) | tag->tag);
896			i++;
897		}
898	}
899	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_SET_RX_MASK);
900
901	req.vnic_id = htole32(vnic->id);
902	req.mask = htole32(mask);
903	req.mc_tbl_addr = htole64(vnic->mc_list.idi_paddr);
904	req.num_mc_entries = htole32(vnic->mc_list_count);
905	req.vlan_tag_tbl_addr = htole64(vnic->vlan_tag_list.idi_paddr);
906	req.num_vlan_tags = htole32(num_vlan_tags);
907	return hwrm_send_message(softc, &req, sizeof(req));
908}
909
910
911int
912bnxt_hwrm_set_filter(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
913{
914	struct hwrm_cfa_l2_filter_alloc_input	req = {0};
915	struct hwrm_cfa_l2_filter_alloc_output	*resp;
916	uint32_t enables = 0;
917	int rc = 0;
918
919	if (vnic->filter_id != -1) {
920		device_printf(softc->dev,
921		    "Attempt to re-allocate l2 ctx filter\n");
922		return EDOOFUS;
923	}
924
925	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
926	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_FILTER_ALLOC);
927
928	req.flags = htole32(HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX);
929	enables = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR
930	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR_MASK
931	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_DST_ID;
932	req.enables = htole32(enables);
933	req.dst_id = htole16(vnic->id);
934	memcpy(req.l2_addr, if_getlladdr(iflib_get_ifp(softc->ctx)),
935	    ETHER_ADDR_LEN);
936	memset(&req.l2_addr_mask, 0xff, sizeof(req.l2_addr_mask));
937
938	BNXT_HWRM_LOCK(softc);
939	rc = _hwrm_send_message(softc, &req, sizeof(req));
940	if (rc)
941		goto fail;
942
943	vnic->filter_id = le64toh(resp->l2_filter_id);
944	vnic->flow_id = le64toh(resp->flow_id);
945
946fail:
947	BNXT_HWRM_UNLOCK(softc);
948	return (rc);
949}
950
951int
952bnxt_hwrm_rss_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic,
953    uint32_t hash_type)
954{
955	struct hwrm_vnic_rss_cfg_input	req = {0};
956	struct hwrm_vnic_rss_cfg_output	*resp;
957
958	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
959	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_CFG);
960
961	req.hash_type = htole32(hash_type);
962	req.ring_grp_tbl_addr = htole64(vnic->rss_grp_tbl.idi_paddr);
963	req.hash_key_tbl_addr = htole64(vnic->rss_hash_key_tbl.idi_paddr);
964	req.rss_ctx_idx = htole16(vnic->rss_id);
965
966	return hwrm_send_message(softc, &req, sizeof(req));
967}
968
969int
970bnxt_cfg_async_cr(struct bnxt_softc *softc)
971{
972	int rc = 0;
973
974	if (BNXT_PF(softc)) {
975		struct hwrm_func_cfg_input req = {0};
976
977		bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
978
979		req.fid = htole16(0xffff);
980		req.enables = htole32(HWRM_FUNC_CFG_INPUT_ENABLES_ASYNC_EVENT_CR);
981		req.async_event_cr = htole16(softc->def_cp_ring.ring.phys_id);
982
983		rc = hwrm_send_message(softc, &req, sizeof(req));
984	}
985	else {
986		struct hwrm_func_vf_cfg_input req = {0};
987
988		bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_VF_CFG);
989
990		req.enables = htole32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_ASYNC_EVENT_CR);
991		req.async_event_cr = htole16(softc->def_cp_ring.ring.phys_id);
992
993		rc = hwrm_send_message(softc, &req, sizeof(req));
994	}
995	return rc;
996}
997
998void
999bnxt_validate_hw_lro_settings(struct bnxt_softc *softc)
1000{
1001	softc->hw_lro.enable = min(softc->hw_lro.enable, 1);
1002
1003        softc->hw_lro.is_mode_gro = min(softc->hw_lro.is_mode_gro, 1);
1004
1005	softc->hw_lro.max_agg_segs = min(softc->hw_lro.max_agg_segs,
1006		HWRM_VNIC_TPA_CFG_INPUT_MAX_AGG_SEGS_MAX);
1007
1008	softc->hw_lro.max_aggs = min(softc->hw_lro.max_aggs,
1009		HWRM_VNIC_TPA_CFG_INPUT_MAX_AGGS_MAX);
1010
1011	softc->hw_lro.min_agg_len = min(softc->hw_lro.min_agg_len, BNXT_MAX_MTU);
1012}
1013
1014int
1015bnxt_hwrm_vnic_tpa_cfg(struct bnxt_softc *softc)
1016{
1017	struct hwrm_vnic_tpa_cfg_input req = {0};
1018	uint32_t flags;
1019
1020	if (softc->vnic_info.id == (uint16_t) HWRM_NA_SIGNATURE) {
1021		return 0;
1022	}
1023
1024	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_TPA_CFG);
1025
1026	if (softc->hw_lro.enable) {
1027		flags = HWRM_VNIC_TPA_CFG_INPUT_FLAGS_TPA |
1028			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_ENCAP_TPA |
1029			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_ECN |
1030			HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_SAME_GRE_SEQ;
1031
1032        	if (softc->hw_lro.is_mode_gro)
1033			flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_GRO;
1034		else
1035			flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_RSC_WND_UPDATE;
1036
1037		req.flags = htole32(flags);
1038
1039		req.enables = htole32(HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGG_SEGS |
1040				HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGGS |
1041				HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MIN_AGG_LEN);
1042
1043		req.max_agg_segs = htole16(softc->hw_lro.max_agg_segs);
1044		req.max_aggs = htole16(softc->hw_lro.max_aggs);
1045		req.min_agg_len = htole32(softc->hw_lro.min_agg_len);
1046	}
1047
1048	req.vnic_id = htole16(softc->vnic_info.id);
1049
1050	return hwrm_send_message(softc, &req, sizeof(req));
1051}
1052
1053int
1054bnxt_hwrm_nvm_find_dir_entry(struct bnxt_softc *softc, uint16_t type,
1055    uint16_t *ordinal, uint16_t ext, uint16_t *index, bool use_index,
1056    uint8_t search_opt, uint32_t *data_length, uint32_t *item_length,
1057    uint32_t *fw_ver)
1058{
1059	struct hwrm_nvm_find_dir_entry_input req = {0};
1060	struct hwrm_nvm_find_dir_entry_output *resp =
1061	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1062	int	rc = 0;
1063	uint32_t old_timeo;
1064
1065	MPASS(ordinal);
1066
1067	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_FIND_DIR_ENTRY);
1068	if (use_index) {
1069		req.enables = htole32(
1070		    HWRM_NVM_FIND_DIR_ENTRY_INPUT_ENABLES_DIR_IDX_VALID);
1071		req.dir_idx = htole16(*index);
1072	}
1073	req.dir_type = htole16(type);
1074	req.dir_ordinal = htole16(*ordinal);
1075	req.dir_ext = htole16(ext);
1076	req.opt_ordinal = search_opt;
1077
1078	BNXT_HWRM_LOCK(softc);
1079	old_timeo = softc->hwrm_cmd_timeo;
1080	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1081	rc = _hwrm_send_message(softc, &req, sizeof(req));
1082	softc->hwrm_cmd_timeo = old_timeo;
1083	if (rc)
1084		goto exit;
1085
1086	if (item_length)
1087		*item_length = le32toh(resp->dir_item_length);
1088	if (data_length)
1089		*data_length = le32toh(resp->dir_data_length);
1090	if (fw_ver)
1091		*fw_ver = le32toh(resp->fw_ver);
1092	*ordinal = le16toh(resp->dir_ordinal);
1093	if (index)
1094		*index = le16toh(resp->dir_idx);
1095
1096exit:
1097	BNXT_HWRM_UNLOCK(softc);
1098	return (rc);
1099}
1100
1101int
1102bnxt_hwrm_nvm_read(struct bnxt_softc *softc, uint16_t index, uint32_t offset,
1103    uint32_t length, struct iflib_dma_info *data)
1104{
1105	struct hwrm_nvm_read_input req = {0};
1106	int rc;
1107	uint32_t old_timeo;
1108
1109	if (length > data->idi_size) {
1110		rc = EINVAL;
1111		goto exit;
1112	}
1113	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_READ);
1114	req.host_dest_addr = htole64(data->idi_paddr);
1115	req.dir_idx = htole16(index);
1116	req.offset = htole32(offset);
1117	req.len = htole32(length);
1118	BNXT_HWRM_LOCK(softc);
1119	old_timeo = softc->hwrm_cmd_timeo;
1120	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1121	rc = _hwrm_send_message(softc, &req, sizeof(req));
1122	softc->hwrm_cmd_timeo = old_timeo;
1123	BNXT_HWRM_UNLOCK(softc);
1124	if (rc)
1125		goto exit;
1126	bus_dmamap_sync(data->idi_tag, data->idi_map, BUS_DMASYNC_POSTREAD);
1127
1128	goto exit;
1129
1130exit:
1131	return rc;
1132}
1133
1134int
1135bnxt_hwrm_nvm_modify(struct bnxt_softc *softc, uint16_t index, uint32_t offset,
1136    void *data, bool cpyin, uint32_t length)
1137{
1138	struct hwrm_nvm_modify_input req = {0};
1139	struct iflib_dma_info dma_data;
1140	int rc;
1141	uint32_t old_timeo;
1142
1143	if (length == 0 || !data)
1144		return EINVAL;
1145	rc = iflib_dma_alloc(softc->ctx, length, &dma_data,
1146	    BUS_DMA_NOWAIT);
1147	if (rc)
1148		return ENOMEM;
1149	if (cpyin) {
1150		rc = copyin(data, dma_data.idi_vaddr, length);
1151		if (rc)
1152			goto exit;
1153	}
1154	else
1155		memcpy(dma_data.idi_vaddr, data, length);
1156	bus_dmamap_sync(dma_data.idi_tag, dma_data.idi_map,
1157	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1158
1159	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_MODIFY);
1160	req.host_src_addr = htole64(dma_data.idi_paddr);
1161	req.dir_idx = htole16(index);
1162	req.offset = htole32(offset);
1163	req.len = htole32(length);
1164	BNXT_HWRM_LOCK(softc);
1165	old_timeo = softc->hwrm_cmd_timeo;
1166	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1167	rc = _hwrm_send_message(softc, &req, sizeof(req));
1168	softc->hwrm_cmd_timeo = old_timeo;
1169	BNXT_HWRM_UNLOCK(softc);
1170
1171exit:
1172	iflib_dma_free(&dma_data);
1173	return rc;
1174}
1175
1176int
1177bnxt_hwrm_fw_reset(struct bnxt_softc *softc, uint8_t processor,
1178    uint8_t *selfreset)
1179{
1180	struct hwrm_fw_reset_input req = {0};
1181	struct hwrm_fw_reset_output *resp =
1182	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1183	int rc;
1184
1185	MPASS(selfreset);
1186
1187	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_RESET);
1188	req.embedded_proc_type = processor;
1189	req.selfrst_status = *selfreset;
1190
1191	BNXT_HWRM_LOCK(softc);
1192	rc = _hwrm_send_message(softc, &req, sizeof(req));
1193	if (rc)
1194		goto exit;
1195	*selfreset = resp->selfrst_status;
1196
1197exit:
1198	BNXT_HWRM_UNLOCK(softc);
1199	return rc;
1200}
1201
1202int
1203bnxt_hwrm_fw_qstatus(struct bnxt_softc *softc, uint8_t type, uint8_t *selfreset)
1204{
1205	struct hwrm_fw_qstatus_input req = {0};
1206	struct hwrm_fw_qstatus_output *resp =
1207	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1208	int rc;
1209
1210	MPASS(selfreset);
1211
1212	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_QSTATUS);
1213	req.embedded_proc_type = type;
1214
1215	BNXT_HWRM_LOCK(softc);
1216	rc = _hwrm_send_message(softc, &req, sizeof(req));
1217	if (rc)
1218		goto exit;
1219	*selfreset = resp->selfrst_status;
1220
1221exit:
1222	BNXT_HWRM_UNLOCK(softc);
1223	return rc;
1224}
1225
1226int
1227bnxt_hwrm_nvm_write(struct bnxt_softc *softc, void *data, bool cpyin,
1228    uint16_t type, uint16_t ordinal, uint16_t ext, uint16_t attr,
1229    uint16_t option, uint32_t data_length, bool keep, uint32_t *item_length,
1230    uint16_t *index)
1231{
1232	struct hwrm_nvm_write_input req = {0};
1233	struct hwrm_nvm_write_output *resp =
1234	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1235	struct iflib_dma_info dma_data;
1236	int rc;
1237	uint32_t old_timeo;
1238
1239	if (data_length) {
1240		rc = iflib_dma_alloc(softc->ctx, data_length, &dma_data,
1241		    BUS_DMA_NOWAIT);
1242		if (rc)
1243			return ENOMEM;
1244		if (cpyin) {
1245			rc = copyin(data, dma_data.idi_vaddr, data_length);
1246			if (rc)
1247				goto early_exit;
1248		}
1249		else
1250			memcpy(dma_data.idi_vaddr, data, data_length);
1251		bus_dmamap_sync(dma_data.idi_tag, dma_data.idi_map,
1252		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1253	}
1254	else
1255		dma_data.idi_paddr = 0;
1256
1257	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_WRITE);
1258
1259	req.host_src_addr = htole64(dma_data.idi_paddr);
1260	req.dir_type = htole16(type);
1261	req.dir_ordinal = htole16(ordinal);
1262	req.dir_ext = htole16(ext);
1263	req.dir_attr = htole16(attr);
1264	req.dir_data_length = htole32(data_length);
1265	req.option = htole16(option);
1266	if (keep) {
1267		req.flags =
1268		    htole16(HWRM_NVM_WRITE_INPUT_FLAGS_KEEP_ORIG_ACTIVE_IMG);
1269	}
1270	if (item_length)
1271		req.dir_item_length = htole32(*item_length);
1272
1273	BNXT_HWRM_LOCK(softc);
1274	old_timeo = softc->hwrm_cmd_timeo;
1275	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1276	rc = _hwrm_send_message(softc, &req, sizeof(req));
1277	softc->hwrm_cmd_timeo = old_timeo;
1278	if (rc)
1279		goto exit;
1280	if (item_length)
1281		*item_length = le32toh(resp->dir_item_length);
1282	if (index)
1283		*index = le16toh(resp->dir_idx);
1284
1285exit:
1286	BNXT_HWRM_UNLOCK(softc);
1287early_exit:
1288	if (data_length)
1289		iflib_dma_free(&dma_data);
1290	return rc;
1291}
1292
1293int
1294bnxt_hwrm_nvm_erase_dir_entry(struct bnxt_softc *softc, uint16_t index)
1295{
1296	struct hwrm_nvm_erase_dir_entry_input req = {0};
1297	uint32_t old_timeo;
1298	int rc;
1299
1300	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_ERASE_DIR_ENTRY);
1301	req.dir_idx = htole16(index);
1302	BNXT_HWRM_LOCK(softc);
1303	old_timeo = softc->hwrm_cmd_timeo;
1304	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1305	rc = _hwrm_send_message(softc, &req, sizeof(req));
1306	softc->hwrm_cmd_timeo = old_timeo;
1307	BNXT_HWRM_UNLOCK(softc);
1308	return rc;
1309}
1310
1311int
1312bnxt_hwrm_nvm_get_dir_info(struct bnxt_softc *softc, uint32_t *entries,
1313    uint32_t *entry_length)
1314{
1315	struct hwrm_nvm_get_dir_info_input req = {0};
1316	struct hwrm_nvm_get_dir_info_output *resp =
1317	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1318	int rc;
1319	uint32_t old_timeo;
1320
1321	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DIR_INFO);
1322
1323	BNXT_HWRM_LOCK(softc);
1324	old_timeo = softc->hwrm_cmd_timeo;
1325	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1326	rc = _hwrm_send_message(softc, &req, sizeof(req));
1327	softc->hwrm_cmd_timeo = old_timeo;
1328	if (rc)
1329		goto exit;
1330
1331	if (entries)
1332		*entries = le32toh(resp->entries);
1333	if (entry_length)
1334		*entry_length = le32toh(resp->entry_length);
1335
1336exit:
1337	BNXT_HWRM_UNLOCK(softc);
1338	return rc;
1339}
1340
1341int
1342bnxt_hwrm_nvm_get_dir_entries(struct bnxt_softc *softc, uint32_t *entries,
1343    uint32_t *entry_length, struct iflib_dma_info *dma_data)
1344{
1345	struct hwrm_nvm_get_dir_entries_input req = {0};
1346	uint32_t ent;
1347	uint32_t ent_len;
1348	int rc;
1349	uint32_t old_timeo;
1350
1351	if (!entries)
1352		entries = &ent;
1353	if (!entry_length)
1354		entry_length = &ent_len;
1355
1356	rc = bnxt_hwrm_nvm_get_dir_info(softc, entries, entry_length);
1357	if (rc)
1358		goto exit;
1359	if (*entries * *entry_length > dma_data->idi_size) {
1360		rc = EINVAL;
1361		goto exit;
1362	}
1363
1364	/*
1365	 * TODO: There's a race condition here that could blow up DMA memory...
1366	 *	 we need to allocate the max size, not the currently in use
1367	 *	 size.  The command should totally have a max size here.
1368	 */
1369	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DIR_ENTRIES);
1370	req.host_dest_addr = htole64(dma_data->idi_paddr);
1371	BNXT_HWRM_LOCK(softc);
1372	old_timeo = softc->hwrm_cmd_timeo;
1373	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1374	rc = _hwrm_send_message(softc, &req, sizeof(req));
1375	softc->hwrm_cmd_timeo = old_timeo;
1376	BNXT_HWRM_UNLOCK(softc);
1377	if (rc)
1378		goto exit;
1379	bus_dmamap_sync(dma_data->idi_tag, dma_data->idi_map,
1380	    BUS_DMASYNC_POSTWRITE);
1381
1382exit:
1383	return rc;
1384}
1385
1386int
1387bnxt_hwrm_nvm_get_dev_info(struct bnxt_softc *softc, uint16_t *mfg_id,
1388    uint16_t *device_id, uint32_t *sector_size, uint32_t *nvram_size,
1389    uint32_t *reserved_size, uint32_t *available_size)
1390{
1391	struct hwrm_nvm_get_dev_info_input req = {0};
1392	struct hwrm_nvm_get_dev_info_output *resp =
1393	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1394	int rc;
1395	uint32_t old_timeo;
1396
1397	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DEV_INFO);
1398
1399	BNXT_HWRM_LOCK(softc);
1400	old_timeo = softc->hwrm_cmd_timeo;
1401	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1402	rc = _hwrm_send_message(softc, &req, sizeof(req));
1403	softc->hwrm_cmd_timeo = old_timeo;
1404	if (rc)
1405		goto exit;
1406
1407	if (mfg_id)
1408		*mfg_id = le16toh(resp->manufacturer_id);
1409	if (device_id)
1410		*device_id = le16toh(resp->device_id);
1411	if (sector_size)
1412		*sector_size = le32toh(resp->sector_size);
1413	if (nvram_size)
1414		*nvram_size = le32toh(resp->nvram_size);
1415	if (reserved_size)
1416		*reserved_size = le32toh(resp->reserved_size);
1417	if (available_size)
1418		*available_size = le32toh(resp->available_size);
1419
1420exit:
1421	BNXT_HWRM_UNLOCK(softc);
1422	return rc;
1423}
1424
1425int
1426bnxt_hwrm_nvm_install_update(struct bnxt_softc *softc,
1427    uint32_t install_type, uint64_t *installed_items, uint8_t *result,
1428    uint8_t *problem_item, uint8_t *reset_required)
1429{
1430	struct hwrm_nvm_install_update_input req = {0};
1431	struct hwrm_nvm_install_update_output *resp =
1432	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1433	int rc;
1434	uint32_t old_timeo;
1435
1436	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_INSTALL_UPDATE);
1437	req.install_type = htole32(install_type);
1438
1439	BNXT_HWRM_LOCK(softc);
1440	old_timeo = softc->hwrm_cmd_timeo;
1441	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1442	rc = _hwrm_send_message(softc, &req, sizeof(req));
1443	softc->hwrm_cmd_timeo = old_timeo;
1444	if (rc)
1445		goto exit;
1446
1447	if (installed_items)
1448		*installed_items = le32toh(resp->installed_items);
1449	if (result)
1450		*result = resp->result;
1451	if (problem_item)
1452		*problem_item = resp->problem_item;
1453	if (reset_required)
1454		*reset_required = resp->reset_required;
1455
1456exit:
1457	BNXT_HWRM_UNLOCK(softc);
1458	return rc;
1459}
1460
1461int
1462bnxt_hwrm_nvm_verify_update(struct bnxt_softc *softc, uint16_t type,
1463    uint16_t ordinal, uint16_t ext)
1464{
1465	struct hwrm_nvm_verify_update_input req = {0};
1466	uint32_t old_timeo;
1467	int rc;
1468
1469	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_VERIFY_UPDATE);
1470
1471	req.dir_type = htole16(type);
1472	req.dir_ordinal = htole16(ordinal);
1473	req.dir_ext = htole16(ext);
1474
1475	BNXT_HWRM_LOCK(softc);
1476	old_timeo = softc->hwrm_cmd_timeo;
1477	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1478	rc = _hwrm_send_message(softc, &req, sizeof(req));
1479	softc->hwrm_cmd_timeo = old_timeo;
1480	BNXT_HWRM_UNLOCK(softc);
1481	return rc;
1482}
1483
1484int
1485bnxt_hwrm_fw_get_time(struct bnxt_softc *softc, uint16_t *year, uint8_t *month,
1486    uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second,
1487    uint16_t *millisecond, uint16_t *zone)
1488{
1489	struct hwrm_fw_get_time_input req = {0};
1490	struct hwrm_fw_get_time_output *resp =
1491	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1492	int rc;
1493
1494	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_GET_TIME);
1495
1496	BNXT_HWRM_LOCK(softc);
1497	rc = _hwrm_send_message(softc, &req, sizeof(req));
1498	if (rc)
1499		goto exit;
1500
1501	if (year)
1502		*year = le16toh(resp->year);
1503	if (month)
1504		*month = resp->month;
1505	if (day)
1506		*day = resp->day;
1507	if (hour)
1508		*hour = resp->hour;
1509	if (minute)
1510		*minute = resp->minute;
1511	if (second)
1512		*second = resp->second;
1513	if (millisecond)
1514		*millisecond = le16toh(resp->millisecond);
1515	if (zone)
1516		*zone = le16toh(resp->zone);
1517
1518exit:
1519	BNXT_HWRM_UNLOCK(softc);
1520	return rc;
1521}
1522
1523int
1524bnxt_hwrm_fw_set_time(struct bnxt_softc *softc, uint16_t year, uint8_t month,
1525    uint8_t day, uint8_t hour, uint8_t minute, uint8_t second,
1526    uint16_t millisecond, uint16_t zone)
1527{
1528	struct hwrm_fw_set_time_input req = {0};
1529
1530	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_SET_TIME);
1531
1532	req.year = htole16(year);
1533	req.month = month;
1534	req.day = day;
1535	req.hour = hour;
1536	req.minute = minute;
1537	req.second = second;
1538	req.millisecond = htole16(millisecond);
1539	req.zone = htole16(zone);
1540	return hwrm_send_message(softc, &req, sizeof(req));
1541}
1542
1543int
1544bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *softc)
1545{
1546	struct bnxt_link_info *link_info = &softc->link_info;
1547	struct hwrm_port_phy_qcfg_input req = {0};
1548	struct hwrm_port_phy_qcfg_output *resp =
1549	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1550	int rc = 0;
1551
1552	BNXT_HWRM_LOCK(softc);
1553	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_QCFG);
1554
1555	rc = _hwrm_send_message(softc, &req, sizeof(req));
1556	if (rc)
1557		goto exit;
1558
1559	link_info->phy_link_status = resp->link;
1560	link_info->duplex =  resp->duplex_cfg;
1561	link_info->auto_mode = resp->auto_mode;
1562
1563        /*
1564         * When AUTO_PAUSE_AUTONEG_PAUSE bit is set to 1,
1565         * the advertisement of pause is enabled.
1566         * 1. When the auto_mode is not set to none and this flag is set to 1,
1567         *    then the auto_pause bits on this port are being advertised and
1568         *    autoneg pause results are being interpreted.
1569         * 2. When the auto_mode is not set to none and this flag is set to 0,
1570         *    the pause is forced as indicated in force_pause, and also
1571	 *    advertised as auto_pause bits, but the autoneg results are not
1572	 *    interpreted since the pause configuration is being forced.
1573         * 3. When the auto_mode is set to none and this flag is set to 1,
1574         *    auto_pause bits should be ignored and should be set to 0.
1575         */
1576
1577	link_info->flow_ctrl.autoneg = false;
1578	link_info->flow_ctrl.tx = false;
1579	link_info->flow_ctrl.rx = false;
1580
1581	if ((resp->auto_mode) &&
1582            (resp->auto_pause & BNXT_AUTO_PAUSE_AUTONEG_PAUSE)) {
1583			link_info->flow_ctrl.autoneg = true;
1584	}
1585
1586	if (link_info->flow_ctrl.autoneg) {
1587		if (resp->auto_pause & BNXT_PAUSE_TX)
1588			link_info->flow_ctrl.tx = true;
1589		if (resp->auto_pause & BNXT_PAUSE_RX)
1590			link_info->flow_ctrl.rx = true;
1591	} else {
1592		if (resp->force_pause & BNXT_PAUSE_TX)
1593			link_info->flow_ctrl.tx = true;
1594		if (resp->force_pause & BNXT_PAUSE_RX)
1595			link_info->flow_ctrl.rx = true;
1596	}
1597
1598	link_info->duplex_setting = resp->duplex_cfg;
1599	if (link_info->phy_link_status == HWRM_PORT_PHY_QCFG_OUTPUT_LINK_LINK)
1600		link_info->link_speed = le16toh(resp->link_speed);
1601	else
1602		link_info->link_speed = 0;
1603	link_info->force_link_speed = le16toh(resp->force_link_speed);
1604	link_info->auto_link_speed = le16toh(resp->auto_link_speed);
1605	link_info->support_speeds = le16toh(resp->support_speeds);
1606	link_info->auto_link_speeds = le16toh(resp->auto_link_speed_mask);
1607	link_info->preemphasis = le32toh(resp->preemphasis);
1608	link_info->phy_ver[0] = resp->phy_maj;
1609	link_info->phy_ver[1] = resp->phy_min;
1610	link_info->phy_ver[2] = resp->phy_bld;
1611	snprintf(softc->ver_info->phy_ver, sizeof(softc->ver_info->phy_ver),
1612	    "%d.%d.%d", link_info->phy_ver[0], link_info->phy_ver[1],
1613	    link_info->phy_ver[2]);
1614	strlcpy(softc->ver_info->phy_vendor, resp->phy_vendor_name,
1615	    BNXT_NAME_SIZE);
1616	strlcpy(softc->ver_info->phy_partnumber, resp->phy_vendor_partnumber,
1617	    BNXT_NAME_SIZE);
1618	link_info->media_type = resp->media_type;
1619	link_info->phy_type = resp->phy_type;
1620	link_info->transceiver = resp->xcvr_pkg_type;
1621	link_info->phy_addr = resp->eee_config_phy_addr &
1622	    HWRM_PORT_PHY_QCFG_OUTPUT_PHY_ADDR_MASK;
1623
1624exit:
1625	BNXT_HWRM_UNLOCK(softc);
1626	return rc;
1627}
1628
1629uint16_t
1630bnxt_hwrm_get_wol_fltrs(struct bnxt_softc *softc, uint16_t handle)
1631{
1632	struct hwrm_wol_filter_qcfg_input req = {0};
1633	struct hwrm_wol_filter_qcfg_output *resp =
1634			(void *)softc->hwrm_cmd_resp.idi_vaddr;
1635	uint16_t next_handle = 0;
1636	int rc;
1637
1638	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_WOL_FILTER_QCFG);
1639	req.port_id = htole16(softc->pf.port_id);
1640	req.handle = htole16(handle);
1641	rc = hwrm_send_message(softc, &req, sizeof(req));
1642	if (!rc) {
1643		next_handle = le16toh(resp->next_handle);
1644		if (next_handle != 0) {
1645			if (resp->wol_type ==
1646				HWRM_WOL_FILTER_ALLOC_INPUT_WOL_TYPE_MAGICPKT) {
1647				softc->wol = 1;
1648				softc->wol_filter_id = resp->wol_filter_id;
1649			}
1650		}
1651	}
1652	return next_handle;
1653}
1654
1655int
1656bnxt_hwrm_alloc_wol_fltr(struct bnxt_softc *softc)
1657{
1658	struct hwrm_wol_filter_alloc_input req = {0};
1659	struct hwrm_wol_filter_alloc_output *resp =
1660		(void *)softc->hwrm_cmd_resp.idi_vaddr;
1661	int rc;
1662
1663	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_WOL_FILTER_ALLOC);
1664	req.port_id = htole16(softc->pf.port_id);
1665	req.wol_type = HWRM_WOL_FILTER_ALLOC_INPUT_WOL_TYPE_MAGICPKT;
1666	req.enables =
1667		htole32(HWRM_WOL_FILTER_ALLOC_INPUT_ENABLES_MAC_ADDRESS);
1668	memcpy(req.mac_address, softc->func.mac_addr, ETHER_ADDR_LEN);
1669	rc = hwrm_send_message(softc, &req, sizeof(req));
1670	if (!rc)
1671		softc->wol_filter_id = resp->wol_filter_id;
1672
1673	return rc;
1674}
1675
1676int
1677bnxt_hwrm_free_wol_fltr(struct bnxt_softc *softc)
1678{
1679	struct hwrm_wol_filter_free_input req = {0};
1680
1681	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_WOL_FILTER_FREE);
1682	req.port_id = htole16(softc->pf.port_id);
1683	req.enables =
1684		htole32(HWRM_WOL_FILTER_FREE_INPUT_ENABLES_WOL_FILTER_ID);
1685	req.wol_filter_id = softc->wol_filter_id;
1686	return hwrm_send_message(softc, &req, sizeof(req));
1687}
1688
1689static void bnxt_hwrm_set_coal_params(struct bnxt_softc *softc, uint32_t max_frames,
1690        uint32_t buf_tmrs, uint16_t flags,
1691        struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req)
1692{
1693        req->flags = htole16(flags);
1694        req->num_cmpl_dma_aggr = htole16((uint16_t)max_frames);
1695        req->num_cmpl_dma_aggr_during_int = htole16(max_frames >> 16);
1696        req->cmpl_aggr_dma_tmr = htole16((uint16_t)buf_tmrs);
1697        req->cmpl_aggr_dma_tmr_during_int = htole16(buf_tmrs >> 16);
1698        /* Minimum time between 2 interrupts set to buf_tmr x 2 */
1699        req->int_lat_tmr_min = htole16((uint16_t)buf_tmrs * 2);
1700        req->int_lat_tmr_max = htole16((uint16_t)buf_tmrs * 4);
1701        req->num_cmpl_aggr_int = htole16((uint16_t)max_frames * 4);
1702}
1703
1704
1705int bnxt_hwrm_set_coal(struct bnxt_softc *softc)
1706{
1707        int i, rc = 0;
1708        struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req_rx = {0},
1709                                                           req_tx = {0}, *req;
1710        uint16_t max_buf, max_buf_irq;
1711        uint16_t buf_tmr, buf_tmr_irq;
1712        uint32_t flags;
1713
1714        bnxt_hwrm_cmd_hdr_init(softc, &req_rx,
1715                               HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS);
1716        bnxt_hwrm_cmd_hdr_init(softc, &req_tx,
1717                               HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS);
1718
1719        /* Each rx completion (2 records) should be DMAed immediately.
1720         * DMA 1/4 of the completion buffers at a time.
1721         */
1722        max_buf = min_t(uint16_t, softc->rx_coal_frames / 4, 2);
1723        /* max_buf must not be zero */
1724        max_buf = clamp_t(uint16_t, max_buf, 1, 63);
1725        max_buf_irq = clamp_t(uint16_t, softc->rx_coal_frames_irq, 1, 63);
1726        buf_tmr = BNXT_USEC_TO_COAL_TIMER(softc->rx_coal_usecs);
1727        /* buf timer set to 1/4 of interrupt timer */
1728        buf_tmr = max_t(uint16_t, buf_tmr / 4, 1);
1729        buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(softc->rx_coal_usecs_irq);
1730        buf_tmr_irq = max_t(uint16_t, buf_tmr_irq, 1);
1731
1732        flags = HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET;
1733
1734        /* RING_IDLE generates more IRQs for lower latency.  Enable it only
1735         * if coal_usecs is less than 25 us.
1736         */
1737        if (softc->rx_coal_usecs < 25)
1738                flags |= HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_RING_IDLE;
1739
1740        bnxt_hwrm_set_coal_params(softc, max_buf_irq << 16 | max_buf,
1741                                  buf_tmr_irq << 16 | buf_tmr, flags, &req_rx);
1742
1743        /* max_buf must not be zero */
1744        max_buf = clamp_t(uint16_t, softc->tx_coal_frames, 1, 63);
1745        max_buf_irq = clamp_t(uint16_t, softc->tx_coal_frames_irq, 1, 63);
1746        buf_tmr = BNXT_USEC_TO_COAL_TIMER(softc->tx_coal_usecs);
1747        /* buf timer set to 1/4 of interrupt timer */
1748        buf_tmr = max_t(uint16_t, buf_tmr / 4, 1);
1749        buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(softc->tx_coal_usecs_irq);
1750        buf_tmr_irq = max_t(uint16_t, buf_tmr_irq, 1);
1751        flags = HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS_INPUT_FLAGS_TIMER_RESET;
1752        bnxt_hwrm_set_coal_params(softc, max_buf_irq << 16 | max_buf,
1753                                  buf_tmr_irq << 16 | buf_tmr, flags, &req_tx);
1754
1755        for (i = 0; i < softc->nrxqsets; i++) {
1756
1757
1758		req = &req_rx;
1759                /*
1760                 * TBD:
1761		 *      Check if Tx also needs to be done
1762                 *      So far, Tx processing has been done in softirq contest
1763                 *
1764		 * req = &req_tx;
1765		 */
1766		req->ring_id = htole16(softc->grp_info[i].cp_ring_id);
1767
1768                rc = hwrm_send_message(softc, req, sizeof(*req));
1769                if (rc)
1770                        break;
1771        }
1772        return rc;
1773}
1774
1775
1776
1777int bnxt_hwrm_func_rgtr_async_events(struct bnxt_softc *softc, unsigned long *bmap,
1778                                     int bmap_size)
1779{
1780	struct hwrm_func_drv_rgtr_input req = {0};
1781	bitstr_t *async_events_bmap;
1782	uint32_t *events;
1783	int i;
1784
1785	async_events_bmap = bit_alloc(256, M_DEVBUF, M_WAITOK|M_ZERO);
1786	events = (uint32_t *)async_events_bmap;
1787
1788	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR);
1789
1790	req.enables =
1791		htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_ASYNC_EVENT_FWD);
1792
1793	memset(async_events_bmap, 0, sizeof(256 / 8));
1794
1795	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE);
1796	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD);
1797	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED);
1798	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE);
1799	bit_set(async_events_bmap, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE);
1800
1801	if (bmap && bmap_size) {
1802		for (i = 0; i < bmap_size; i++) {
1803			if (bit_test(bmap, i))
1804				bit_set(async_events_bmap, i);
1805		}
1806	}
1807
1808	for (i = 0; i < 8; i++)
1809		req.async_event_fwd[i] |= htole32(events[i]);
1810
1811	free(async_events_bmap, M_DEVBUF);
1812
1813	return hwrm_send_message(softc, &req, sizeof(req));
1814}
1815