bnxt_hwrm.c revision 309377
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 309377 2016-12-01 23:37:17Z shurd $");
31
32#include <sys/endian.h>
33
34#include "bnxt.h"
35#include "bnxt_hwrm.h"
36#include "hsi_struct_def.h"
37
38static int bnxt_hwrm_err_map(uint16_t err);
39static inline int _is_valid_ether_addr(uint8_t *);
40static inline void get_random_ether_addr(uint8_t *);
41static void	bnxt_hwrm_set_link_common(struct bnxt_softc *softc,
42		    struct hwrm_port_phy_cfg_input *req);
43static void	bnxt_hwrm_set_pause_common(struct bnxt_softc *softc,
44		    struct hwrm_port_phy_cfg_input *req);
45static void	bnxt_hwrm_set_eee(struct bnxt_softc *softc,
46		    struct hwrm_port_phy_cfg_input *req);
47static int	_hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
48static int	hwrm_send_message(struct bnxt_softc *, void *, uint32_t);
49static void bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *, void *, uint16_t);
50
51/* NVRam stuff has a five minute timeout */
52#define BNXT_NVM_TIMEO	(5 * 60 * 1000)
53
54static int
55bnxt_hwrm_err_map(uint16_t err)
56{
57	int rc;
58
59	switch (err) {
60	case HWRM_ERR_CODE_SUCCESS:
61		return 0;
62	case HWRM_ERR_CODE_INVALID_PARAMS:
63	case HWRM_ERR_CODE_INVALID_FLAGS:
64	case HWRM_ERR_CODE_INVALID_ENABLES:
65		return EINVAL;
66	case HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED:
67		return EACCES;
68	case HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR:
69		return ENOMEM;
70	case HWRM_ERR_CODE_CMD_NOT_SUPPORTED:
71		return ENOSYS;
72	case HWRM_ERR_CODE_FAIL:
73		return EIO;
74	case HWRM_ERR_CODE_HWRM_ERROR:
75	case HWRM_ERR_CODE_UNKNOWN_ERR:
76	default:
77		return EDOOFUS;
78	}
79
80	return rc;
81}
82
83int
84bnxt_alloc_hwrm_dma_mem(struct bnxt_softc *softc)
85{
86	int rc;
87
88	rc = iflib_dma_alloc(softc->ctx, PAGE_SIZE, &softc->hwrm_cmd_resp,
89	    BUS_DMA_NOWAIT);
90	return rc;
91}
92
93void
94bnxt_free_hwrm_dma_mem(struct bnxt_softc *softc)
95{
96	if (softc->hwrm_cmd_resp.idi_vaddr)
97		iflib_dma_free(&softc->hwrm_cmd_resp);
98	softc->hwrm_cmd_resp.idi_vaddr = NULL;
99	return;
100}
101
102static void
103bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *softc, void *request,
104    uint16_t req_type)
105{
106	struct input *req = request;
107
108	req->req_type = htole16(req_type);
109	req->cmpl_ring = 0xffff;
110	req->target_id = 0xffff;
111	req->resp_addr = htole64(softc->hwrm_cmd_resp.idi_paddr);
112}
113
114static int
115_hwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len)
116{
117	struct input *req = msg;
118	struct hwrm_err_output *resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
119	uint32_t *data = msg;
120	int i;
121	uint16_t cp_ring_id;
122	uint8_t *valid;
123	uint16_t err;
124
125	/* TODO: DMASYNC in here. */
126	req->seq_id = htole16(softc->hwrm_cmd_seq++);
127	memset(resp, 0, PAGE_SIZE);
128	cp_ring_id = le16toh(req->cmpl_ring);
129
130	/* Write request msg to hwrm channel */
131	for (i = 0; i < msg_len; i += 4) {
132		bus_space_write_4(softc->hwrm_bar.tag,
133				  softc->hwrm_bar.handle,
134				  i, *data);
135		data++;
136	}
137
138	/* Clear to the end of the request buffer */
139	for (i = msg_len; i < HWRM_MAX_REQ_LEN; i += 4)
140		bus_space_write_4(softc->hwrm_bar.tag, softc->hwrm_bar.handle,
141		    i, 0);
142
143	/* Ring channel doorbell */
144	bus_space_write_4(softc->hwrm_bar.tag,
145			  softc->hwrm_bar.handle,
146			  0x100, htole32(1));
147
148	/* Check if response len is updated */
149	for (i = 0; i < softc->hwrm_cmd_timeo; i++) {
150		if (resp->resp_len && resp->resp_len <= 4096)
151			break;
152		DELAY(1000);
153	}
154	if (i >= softc->hwrm_cmd_timeo) {
155		device_printf(softc->dev,
156		    "Timeout sending %s: (timeout: %u) seq: %d\n",
157		    GET_HWRM_REQ_TYPE(req->req_type), softc->hwrm_cmd_timeo,
158		    le16toh(req->seq_id));
159		return ETIMEDOUT;
160	}
161	/* Last byte of resp contains the valid key */
162	valid = (uint8_t *)resp + resp->resp_len - 1;
163	for (i = 0; i < softc->hwrm_cmd_timeo; i++) {
164		if (*valid == HWRM_RESP_VALID_KEY)
165			break;
166		DELAY(1000);
167	}
168	if (i >= softc->hwrm_cmd_timeo) {
169		device_printf(softc->dev, "Timeout sending %s: "
170		    "(timeout: %u) msg {0x%x 0x%x} len:%d v: %d\n",
171		    GET_HWRM_REQ_TYPE(req->req_type),
172		    softc->hwrm_cmd_timeo, le16toh(req->req_type),
173		    le16toh(req->seq_id), msg_len,
174		    *valid);
175		return ETIMEDOUT;
176	}
177
178	err = le16toh(resp->error_code);
179	if (err) {
180		/* HWRM_ERR_CODE_FAIL is a "normal" error, don't log */
181		if (err != HWRM_ERR_CODE_FAIL) {
182			device_printf(softc->dev,
183			    "%s command returned %s error.\n",
184			    GET_HWRM_REQ_TYPE(req->req_type),
185			    GET_HWRM_ERROR_CODE(err));
186		}
187		return bnxt_hwrm_err_map(err);
188	}
189
190	return 0;
191}
192
193static int
194hwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len)
195{
196	int rc;
197
198	BNXT_HWRM_LOCK(softc);
199	rc = _hwrm_send_message(softc, msg, msg_len);
200	BNXT_HWRM_UNLOCK(softc);
201	return rc;
202}
203
204int
205bnxt_hwrm_queue_qportcfg(struct bnxt_softc *softc)
206{
207	struct hwrm_queue_qportcfg_input req = {0};
208	struct hwrm_queue_qportcfg_output *resp =
209	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
210
211	int	rc = 0;
212	uint8_t	*qptr;
213
214	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_QPORTCFG);
215
216	BNXT_HWRM_LOCK(softc);
217	rc = _hwrm_send_message(softc, &req, sizeof(req));
218	if (rc)
219		goto qportcfg_exit;
220
221	if (!resp->max_configurable_queues) {
222		rc = -EINVAL;
223		goto qportcfg_exit;
224	}
225	softc->max_tc = resp->max_configurable_queues;
226	if (softc->max_tc > BNXT_MAX_QUEUE)
227		softc->max_tc = BNXT_MAX_QUEUE;
228
229	qptr = &resp->queue_id0;
230	for (int i = 0; i < softc->max_tc; i++) {
231		softc->q_info[i].id = *qptr++;
232		softc->q_info[i].profile = *qptr++;
233	}
234
235qportcfg_exit:
236	BNXT_HWRM_UNLOCK(softc);
237	return (rc);
238}
239
240
241int
242bnxt_hwrm_ver_get(struct bnxt_softc *softc)
243{
244	struct hwrm_ver_get_input	req = {0};
245	struct hwrm_ver_get_output	*resp =
246	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
247	int				rc;
248	const char nastr[] = "<not installed>";
249	const char naver[] = "<N/A>";
250
251	softc->hwrm_max_req_len = HWRM_MAX_REQ_LEN;
252	softc->hwrm_cmd_timeo = 1000;
253	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VER_GET);
254
255	req.hwrm_intf_maj = HWRM_VERSION_MAJOR;
256	req.hwrm_intf_min = HWRM_VERSION_MINOR;
257	req.hwrm_intf_upd = HWRM_VERSION_UPDATE;
258
259	BNXT_HWRM_LOCK(softc);
260	rc = _hwrm_send_message(softc, &req, sizeof(req));
261	if (rc)
262		goto fail;
263
264	snprintf(softc->ver_info->hwrm_if_ver, BNXT_VERSTR_SIZE, "%d.%d.%d",
265	    resp->hwrm_intf_maj, resp->hwrm_intf_min, resp->hwrm_intf_upd);
266	softc->ver_info->hwrm_if_major = resp->hwrm_intf_maj;
267	softc->ver_info->hwrm_if_minor = resp->hwrm_intf_min;
268	softc->ver_info->hwrm_if_update = resp->hwrm_intf_upd;
269	snprintf(softc->ver_info->hwrm_fw_ver, BNXT_VERSTR_SIZE, "%d.%d.%d",
270	    resp->hwrm_fw_maj, resp->hwrm_fw_min, resp->hwrm_fw_bld);
271	strlcpy(softc->ver_info->driver_hwrm_if_ver, HWRM_VERSION_STR,
272	    BNXT_VERSTR_SIZE);
273	strlcpy(softc->ver_info->hwrm_fw_name, resp->hwrm_fw_name,
274	    BNXT_NAME_SIZE);
275
276	if (resp->mgmt_fw_maj == 0 && resp->mgmt_fw_min == 0 &&
277	    resp->mgmt_fw_bld == 0) {
278		strlcpy(softc->ver_info->mgmt_fw_ver, naver, BNXT_VERSTR_SIZE);
279		strlcpy(softc->ver_info->mgmt_fw_name, nastr, BNXT_NAME_SIZE);
280	}
281	else {
282		snprintf(softc->ver_info->mgmt_fw_ver, BNXT_VERSTR_SIZE,
283		    "%d.%d.%d", resp->mgmt_fw_maj, resp->mgmt_fw_min,
284		    resp->mgmt_fw_bld);
285		strlcpy(softc->ver_info->mgmt_fw_name, resp->mgmt_fw_name,
286		    BNXT_NAME_SIZE);
287	}
288	if (resp->netctrl_fw_maj == 0 && resp->netctrl_fw_min == 0 &&
289	    resp->netctrl_fw_bld == 0) {
290		strlcpy(softc->ver_info->netctrl_fw_ver, naver,
291		    BNXT_VERSTR_SIZE);
292		strlcpy(softc->ver_info->netctrl_fw_name, nastr,
293		    BNXT_NAME_SIZE);
294	}
295	else {
296		snprintf(softc->ver_info->netctrl_fw_ver, BNXT_VERSTR_SIZE,
297		    "%d.%d.%d", resp->netctrl_fw_maj, resp->netctrl_fw_min,
298		    resp->netctrl_fw_bld);
299		strlcpy(softc->ver_info->netctrl_fw_name, resp->netctrl_fw_name,
300		    BNXT_NAME_SIZE);
301	}
302	if (resp->roce_fw_maj == 0 && resp->roce_fw_min == 0 &&
303	    resp->roce_fw_bld == 0) {
304		strlcpy(softc->ver_info->roce_fw_ver, naver, BNXT_VERSTR_SIZE);
305		strlcpy(softc->ver_info->roce_fw_name, nastr, BNXT_NAME_SIZE);
306	}
307	else {
308		snprintf(softc->ver_info->roce_fw_ver, BNXT_VERSTR_SIZE,
309		    "%d.%d.%d", resp->roce_fw_maj, resp->roce_fw_min,
310		    resp->roce_fw_bld);
311		strlcpy(softc->ver_info->roce_fw_name, resp->roce_fw_name,
312		    BNXT_NAME_SIZE);
313	}
314	softc->ver_info->chip_num = le16toh(resp->chip_num);
315	softc->ver_info->chip_rev = resp->chip_rev;
316	softc->ver_info->chip_metal = resp->chip_metal;
317	softc->ver_info->chip_bond_id = resp->chip_bond_id;
318	softc->ver_info->chip_type = resp->chip_platform_type;
319
320	if (resp->max_req_win_len)
321		softc->hwrm_max_req_len = le16toh(resp->max_req_win_len);
322	if (resp->def_req_timeout)
323		softc->hwrm_cmd_timeo = le16toh(resp->def_req_timeout);
324
325fail:
326	BNXT_HWRM_UNLOCK(softc);
327	return rc;
328}
329
330int
331bnxt_hwrm_func_drv_rgtr(struct bnxt_softc *softc)
332{
333	struct hwrm_func_drv_rgtr_input req = {0};
334
335	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR);
336
337	req.enables = htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_VER |
338	    HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_OS_TYPE);
339	req.os_type = htole16(HWRM_FUNC_DRV_RGTR_INPUT_OS_TYPE_FREEBSD);
340
341	req.ver_maj = __FreeBSD_version / 100000;
342	req.ver_min = (__FreeBSD_version / 1000) % 100;
343	req.ver_upd = (__FreeBSD_version / 100) % 10;
344
345	return hwrm_send_message(softc, &req, sizeof(req));
346}
347
348
349int
350bnxt_hwrm_func_drv_unrgtr(struct bnxt_softc *softc, bool shutdown)
351{
352	struct hwrm_func_drv_unrgtr_input req = {0};
353
354	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_UNRGTR);
355	if (shutdown == true)
356		req.flags |=
357		    HWRM_FUNC_DRV_UNRGTR_INPUT_FLAGS_PREPARE_FOR_SHUTDOWN;
358	return hwrm_send_message(softc, &req, sizeof(req));
359}
360
361
362static inline int
363_is_valid_ether_addr(uint8_t *addr)
364{
365	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
366
367	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
368		return (FALSE);
369
370	return (TRUE);
371}
372
373static inline void
374get_random_ether_addr(uint8_t *addr)
375{
376	uint8_t temp[ETHER_ADDR_LEN];
377
378	arc4rand(&temp, sizeof(temp), 0);
379	temp[0] &= 0xFE;
380	temp[0] |= 0x02;
381	bcopy(temp, addr, sizeof(temp));
382}
383
384int
385bnxt_hwrm_func_qcaps(struct bnxt_softc *softc)
386{
387	int rc = 0;
388	struct hwrm_func_qcaps_input req = {0};
389	struct hwrm_func_qcaps_output *resp =
390	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
391	struct bnxt_func_info *func = &softc->func;
392
393	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCAPS);
394	req.fid = htole16(0xffff);
395
396	BNXT_HWRM_LOCK(softc);
397	rc = _hwrm_send_message(softc, &req, sizeof(req));
398	if (rc)
399		goto fail;
400
401	func->fw_fid = le16toh(resp->fid);
402	memcpy(func->mac_addr, resp->mac_address, ETHER_ADDR_LEN);
403	func->max_rsscos_ctxs = le16toh(resp->max_rsscos_ctx);
404	func->max_cp_rings = le16toh(resp->max_cmpl_rings);
405	func->max_tx_rings = le16toh(resp->max_tx_rings);
406	func->max_rx_rings = le16toh(resp->max_rx_rings);
407	func->max_hw_ring_grps = le32toh(resp->max_hw_ring_grps);
408	if (!func->max_hw_ring_grps)
409		func->max_hw_ring_grps = func->max_tx_rings;
410	func->max_l2_ctxs = le16toh(resp->max_l2_ctxs);
411	func->max_vnics = le16toh(resp->max_vnics);
412	func->max_stat_ctxs = le16toh(resp->max_stat_ctx);
413	if (BNXT_PF(softc)) {
414		struct bnxt_pf_info *pf = &softc->pf;
415
416		pf->port_id = le16toh(resp->port_id);
417		pf->first_vf_id = le16toh(resp->first_vf_id);
418		pf->max_vfs = le16toh(resp->max_vfs);
419		pf->max_encap_records = le32toh(resp->max_encap_records);
420		pf->max_decap_records = le32toh(resp->max_decap_records);
421		pf->max_tx_em_flows = le32toh(resp->max_tx_em_flows);
422		pf->max_tx_wm_flows = le32toh(resp->max_tx_wm_flows);
423		pf->max_rx_em_flows = le32toh(resp->max_rx_em_flows);
424		pf->max_rx_wm_flows = le32toh(resp->max_rx_wm_flows);
425	}
426	if (!_is_valid_ether_addr(func->mac_addr)) {
427		device_printf(softc->dev, "Invalid ethernet address, generating random locally administered address\n");
428		get_random_ether_addr(func->mac_addr);
429	}
430
431fail:
432	BNXT_HWRM_UNLOCK(softc);
433	return rc;
434}
435
436int
437bnxt_hwrm_func_reset(struct bnxt_softc *softc)
438{
439	struct hwrm_func_reset_input req = {0};
440
441	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_RESET);
442	req.enables = 0;
443
444	return hwrm_send_message(softc, &req, sizeof(req));
445}
446
447static void
448bnxt_hwrm_set_link_common(struct bnxt_softc *softc,
449    struct hwrm_port_phy_cfg_input *req)
450{
451	uint8_t autoneg = softc->link_info.autoneg;
452	uint16_t fw_link_speed = softc->link_info.req_link_speed;
453
454	if (autoneg & BNXT_AUTONEG_SPEED) {
455		req->auto_mode |=
456		    HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_ALL_SPEEDS;
457
458		req->enables |=
459		    htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE);
460		req->flags |=
461		    htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG);
462	} else {
463		req->force_link_speed = htole16(fw_link_speed);
464		req->flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE);
465	}
466
467	/* tell chimp that the setting takes effect immediately */
468	req->flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESET_PHY);
469}
470
471
472static void
473bnxt_hwrm_set_pause_common(struct bnxt_softc *softc,
474    struct hwrm_port_phy_cfg_input *req)
475{
476	if (softc->link_info.autoneg & BNXT_AUTONEG_FLOW_CTRL) {
477		req->auto_pause =
478		    HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_AUTONEG_PAUSE;
479		if (softc->link_info.req_flow_ctrl &
480		    HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX)
481			req->auto_pause |=
482			    HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_RX;
483		if (softc->link_info.req_flow_ctrl &
484		    HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX)
485			req->auto_pause |=
486			    HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_RX;
487		req->enables |=
488		    htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_PAUSE);
489	} else {
490		if (softc->link_info.req_flow_ctrl &
491		    HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX)
492			req->force_pause |=
493			    HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_RX;
494		if (softc->link_info.req_flow_ctrl &
495		    HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX)
496			req->force_pause |=
497			    HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_TX;
498		req->enables |=
499			htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_FORCE_PAUSE);
500		req->auto_pause = req->force_pause;
501		req->enables |= htole32(
502		    HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_PAUSE);
503	}
504}
505
506
507/* JFV this needs interface connection */
508static void
509bnxt_hwrm_set_eee(struct bnxt_softc *softc, struct hwrm_port_phy_cfg_input *req)
510{
511	/* struct ethtool_eee *eee = &softc->eee; */
512	bool	eee_enabled = false;
513
514	if (eee_enabled) {
515#if 0
516		uint16_t eee_speeds;
517		uint32_t flags = HWRM_PORT_PHY_CFG_INPUT_FLAGS_EEE_ENABLE;
518
519		if (eee->tx_lpi_enabled)
520			flags |= HWRM_PORT_PHY_CFG_INPUT_FLAGS_EEE_TX_LPI;
521
522		req->flags |= htole32(flags);
523		eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised);
524		req->eee_link_speed_mask = htole16(eee_speeds);
525		req->tx_lpi_timer = htole32(eee->tx_lpi_timer);
526#endif
527	} else {
528		req->flags |=
529		    htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_EEE_DISABLE);
530	}
531}
532
533
534int
535bnxt_hwrm_set_link_setting(struct bnxt_softc *softc, bool set_pause,
536    bool set_eee)
537{
538	struct hwrm_port_phy_cfg_input req = {0};
539
540	if (softc->flags & BNXT_FLAG_NPAR)
541		return ENOTSUP;
542
543	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_CFG);
544	if (set_pause)
545		bnxt_hwrm_set_pause_common(softc, &req);
546
547	bnxt_hwrm_set_link_common(softc, &req);
548	if (set_eee)
549		bnxt_hwrm_set_eee(softc, &req);
550	return hwrm_send_message(softc, &req, sizeof(req));
551}
552
553
554int
555bnxt_hwrm_set_pause(struct bnxt_softc *softc)
556{
557	struct hwrm_port_phy_cfg_input req = {0};
558	int rc;
559
560	if (softc->flags & BNXT_FLAG_NPAR)
561		return ENOTSUP;
562
563	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_CFG);
564	bnxt_hwrm_set_pause_common(softc, &req);
565
566	if (softc->link_info.autoneg & BNXT_AUTONEG_FLOW_CTRL)
567		bnxt_hwrm_set_link_common(softc, &req);
568
569	BNXT_HWRM_LOCK(softc);
570	rc = _hwrm_send_message(softc, &req, sizeof(req));
571	if (!rc && !(softc->link_info.autoneg & BNXT_AUTONEG_FLOW_CTRL)) {
572		/* since changing of pause setting doesn't trigger any link
573		 * change event, the driver needs to update the current pause
574		 * result upon successfully return of the phy_cfg command */
575		softc->link_info.pause =
576		softc->link_info.force_pause = softc->link_info.req_flow_ctrl;
577		softc->link_info.auto_pause = 0;
578		bnxt_report_link(softc);
579	}
580	BNXT_HWRM_UNLOCK(softc);
581	return rc;
582}
583
584int
585bnxt_hwrm_vnic_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
586{
587	struct hwrm_vnic_cfg_input req = {0};
588	struct hwrm_vnic_cfg_output *resp;
589
590	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
591	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_CFG);
592
593	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
594		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_DEFAULT);
595	if (vnic->flags & BNXT_VNIC_FLAG_BD_STALL)
596		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_BD_STALL_MODE);
597	if (vnic->flags & BNXT_VNIC_FLAG_VLAN_STRIP)
598		req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_VLAN_STRIP_MODE);
599	req.enables = htole32(HWRM_VNIC_CFG_INPUT_ENABLES_DFLT_RING_GRP |
600	    HWRM_VNIC_CFG_INPUT_ENABLES_RSS_RULE |
601	    HWRM_VNIC_CFG_INPUT_ENABLES_MRU);
602	req.vnic_id = htole16(vnic->id);
603	req.dflt_ring_grp = htole16(vnic->def_ring_grp);
604	req.rss_rule = htole16(vnic->rss_id);
605	req.cos_rule = htole16(vnic->cos_rule);
606	req.lb_rule = htole16(vnic->lb_rule);
607	req.mru = htole16(vnic->mru);
608
609	return hwrm_send_message(softc, &req, sizeof(req));
610}
611
612int
613bnxt_hwrm_vnic_alloc(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
614{
615	struct hwrm_vnic_alloc_input req = {0};
616	struct hwrm_vnic_alloc_output *resp =
617	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
618	int rc;
619
620	if (vnic->id != (uint16_t)HWRM_NA_SIGNATURE) {
621		device_printf(softc->dev,
622		    "Attempt to re-allocate vnic %04x\n", vnic->id);
623		return EDOOFUS;
624	}
625
626	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_ALLOC);
627
628	if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT)
629		req.flags = htole32(HWRM_VNIC_ALLOC_INPUT_FLAGS_DEFAULT);
630
631	BNXT_HWRM_LOCK(softc);
632	rc = _hwrm_send_message(softc, &req, sizeof(req));
633	if (rc)
634		goto fail;
635
636	vnic->id = le32toh(resp->vnic_id);
637
638fail:
639	BNXT_HWRM_UNLOCK(softc);
640	return (rc);
641}
642
643int
644bnxt_hwrm_vnic_ctx_alloc(struct bnxt_softc *softc, uint16_t *ctx_id)
645{
646	struct hwrm_vnic_rss_cos_lb_ctx_alloc_input req = {0};
647	struct hwrm_vnic_rss_cos_lb_ctx_alloc_output *resp =
648	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
649	int rc;
650
651	if (*ctx_id != (uint16_t)HWRM_NA_SIGNATURE) {
652		device_printf(softc->dev,
653		    "Attempt to re-allocate vnic ctx %04x\n", *ctx_id);
654		return EDOOFUS;
655	}
656
657	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_COS_LB_CTX_ALLOC);
658
659	BNXT_HWRM_LOCK(softc);
660	rc = _hwrm_send_message(softc, &req, sizeof(req));
661	if (rc)
662		goto fail;
663
664	*ctx_id = le32toh(resp->rss_cos_lb_ctx_id);
665
666fail:
667	BNXT_HWRM_UNLOCK(softc);
668	return (rc);
669}
670
671int
672bnxt_hwrm_ring_grp_alloc(struct bnxt_softc *softc, struct bnxt_grp_info *grp)
673{
674	struct hwrm_ring_grp_alloc_input req = {0};
675	struct hwrm_ring_grp_alloc_output *resp;
676	int rc = 0;
677
678	if (grp->grp_id != (uint16_t)HWRM_NA_SIGNATURE) {
679		device_printf(softc->dev,
680		    "Attempt to re-allocate ring group %04x\n", grp->grp_id);
681		return EDOOFUS;
682	}
683
684	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
685	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_GRP_ALLOC);
686	req.cr = htole16(grp->cp_ring_id);
687	req.rr = htole16(grp->rx_ring_id);
688	req.ar = htole16(grp->ag_ring_id);
689	req.sc = htole16(grp->stats_ctx);
690
691	BNXT_HWRM_LOCK(softc);
692	rc = _hwrm_send_message(softc, &req, sizeof(req));
693	if (rc)
694		goto fail;
695
696	grp->grp_id = le32toh(resp->ring_group_id);
697
698fail:
699	BNXT_HWRM_UNLOCK(softc);
700	return rc;
701}
702
703/*
704 * Ring allocation message to the firmware
705 */
706int
707bnxt_hwrm_ring_alloc(struct bnxt_softc *softc, uint8_t type,
708    struct bnxt_ring *ring, uint16_t cmpl_ring_id, uint32_t stat_ctx_id,
709    bool irq)
710{
711	struct hwrm_ring_alloc_input req = {0};
712	struct hwrm_ring_alloc_output *resp;
713	int rc;
714
715	if (ring->phys_id != (uint16_t)HWRM_NA_SIGNATURE) {
716		device_printf(softc->dev,
717		    "Attempt to re-allocate ring %04x\n", ring->phys_id);
718		return EDOOFUS;
719	}
720
721	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
722	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_ALLOC);
723	req.enables = htole32(0);
724	req.fbo = htole32(0);
725
726	if (stat_ctx_id != HWRM_NA_SIGNATURE) {
727		req.enables |= htole32(
728		    HWRM_RING_ALLOC_INPUT_ENABLES_STAT_CTX_ID_VALID);
729		req.stat_ctx_id = htole32(stat_ctx_id);
730	}
731	req.ring_type = type;
732	req.page_tbl_addr = htole64(ring->paddr);
733	req.length = htole32(ring->ring_size);
734	req.logical_id = htole16(ring->id);
735	req.cmpl_ring_id = htole16(cmpl_ring_id);
736	req.queue_id = htole16(softc->q_info[0].id);
737#if 0
738	/* MODE_POLL appears to crash the firmware */
739	if (irq)
740		req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX;
741	else
742		req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_POLL;
743#else
744	req.int_mode = HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX;
745#endif
746	BNXT_HWRM_LOCK(softc);
747	rc = _hwrm_send_message(softc, &req, sizeof(req));
748	if (rc)
749		goto fail;
750
751	ring->phys_id = le16toh(resp->ring_id);
752
753fail:
754	BNXT_HWRM_UNLOCK(softc);
755	return rc;
756}
757
758int
759bnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr,
760    uint64_t paddr)
761{
762	struct hwrm_stat_ctx_alloc_input req = {0};
763	struct hwrm_stat_ctx_alloc_output *resp;
764	int rc = 0;
765
766	if (cpr->stats_ctx_id != HWRM_NA_SIGNATURE) {
767		device_printf(softc->dev,
768		    "Attempt to re-allocate stats ctx %08x\n",
769		    cpr->stats_ctx_id);
770		return EDOOFUS;
771	}
772
773	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
774	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_STAT_CTX_ALLOC);
775
776	req.update_period_ms = htole32(1000);
777	req.stats_dma_addr = htole64(paddr);
778
779	BNXT_HWRM_LOCK(softc);
780	rc = _hwrm_send_message(softc, &req, sizeof(req));
781	if (rc)
782		goto fail;
783
784	cpr->stats_ctx_id = le32toh(resp->stat_ctx_id);
785
786fail:
787	BNXT_HWRM_UNLOCK(softc);
788
789	return rc;
790}
791
792int
793bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt_softc *softc,
794    struct bnxt_vnic_info *vnic)
795{
796	struct hwrm_cfa_l2_set_rx_mask_input req = {0};
797	struct bnxt_vlan_tag *tag;
798	uint32_t *tags;
799	uint32_t num_vlan_tags = 0;;
800	uint32_t i;
801	uint32_t mask = vnic->rx_mask;
802	int rc;
803
804	SLIST_FOREACH(tag, &vnic->vlan_tags, next)
805		num_vlan_tags++;
806
807	if (num_vlan_tags) {
808		if (!(mask &
809		    HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ANYVLAN_NONVLAN)) {
810			if (!vnic->vlan_only)
811				mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLAN_NONVLAN;
812			else
813				mask |=
814				    HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_VLANONLY;
815		}
816		if (vnic->vlan_tag_list.idi_vaddr) {
817			iflib_dma_free(&vnic->vlan_tag_list);
818			vnic->vlan_tag_list.idi_vaddr = NULL;
819		}
820		rc = iflib_dma_alloc(softc->ctx, 4 * num_vlan_tags,
821		    &vnic->vlan_tag_list, BUS_DMA_NOWAIT);
822		if (rc)
823			return rc;
824		tags = (uint32_t *)vnic->vlan_tag_list.idi_vaddr;
825
826		i = 0;
827		SLIST_FOREACH(tag, &vnic->vlan_tags, next) {
828			tags[i] = htole32((tag->tpid << 16) | tag->tag);
829			i++;
830		}
831	}
832	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_SET_RX_MASK);
833
834	req.vnic_id = htole32(vnic->id);
835	req.mask = htole32(mask);
836	req.mc_tbl_addr = htole64(vnic->mc_list.idi_paddr);
837	req.num_mc_entries = htole32(vnic->mc_list_count);
838	req.vlan_tag_tbl_addr = htole64(vnic->vlan_tag_list.idi_paddr);
839	req.num_vlan_tags = htole32(num_vlan_tags);
840	return hwrm_send_message(softc, &req, sizeof(req));
841}
842
843
844int
845bnxt_hwrm_set_filter(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic)
846{
847	struct hwrm_cfa_l2_filter_alloc_input	req = {0};
848	struct hwrm_cfa_l2_filter_alloc_output	*resp;
849	uint32_t enables = 0;
850	int rc = 0;
851
852	if (vnic->filter_id != -1) {
853		device_printf(softc->dev,
854		    "Attempt to re-allocate l2 ctx filter\n");
855		return EDOOFUS;
856	}
857
858	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
859	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_FILTER_ALLOC);
860
861	req.flags = htole32(HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX);
862	enables = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR
863	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR_MASK
864	    | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_DST_ID;
865	req.enables = htole32(enables);
866	req.dst_id = htole16(vnic->id);
867	memcpy(req.l2_addr, if_getlladdr(iflib_get_ifp(softc->ctx)),
868	    ETHER_ADDR_LEN);
869	memset(&req.l2_addr_mask, 0xff, sizeof(req.l2_addr_mask));
870
871	BNXT_HWRM_LOCK(softc);
872	rc = _hwrm_send_message(softc, &req, sizeof(req));
873	if (rc)
874		goto fail;
875
876	vnic->filter_id = le64toh(resp->l2_filter_id);
877	vnic->flow_id = le64toh(resp->flow_id);
878
879fail:
880	BNXT_HWRM_UNLOCK(softc);
881	return (rc);
882}
883
884int
885bnxt_hwrm_rss_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic,
886    uint32_t hash_type)
887{
888	struct hwrm_vnic_rss_cfg_input	req = {0};
889	struct hwrm_vnic_rss_cfg_output	*resp;
890
891	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
892	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_CFG);
893
894	req.hash_type = htole32(hash_type);
895	req.ring_grp_tbl_addr = htole64(vnic->rss_grp_tbl.idi_paddr);
896	req.hash_key_tbl_addr = htole64(vnic->rss_hash_key_tbl.idi_paddr);
897	req.rss_ctx_idx = htole16(vnic->rss_id);
898
899	return hwrm_send_message(softc, &req, sizeof(req));
900}
901
902int
903bnxt_hwrm_func_cfg(struct bnxt_softc *softc)
904{
905	struct hwrm_func_cfg_input req = {0};
906
907	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
908
909	req.fid = 0xffff;
910	req.enables = htole32(HWRM_FUNC_CFG_INPUT_ENABLES_ASYNC_EVENT_CR);
911
912	req.async_event_cr = softc->def_cp_ring.ring.phys_id;
913
914	return hwrm_send_message(softc, &req, sizeof(req));
915}
916
917int
918bnxt_hwrm_vnic_tpa_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic,
919    uint32_t flags)
920{
921	struct hwrm_vnic_tpa_cfg_input req = {0};
922
923	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_TPA_CFG);
924
925	req.flags = htole32(flags);
926	req.vnic_id = htole16(vnic->id);
927	req.enables = htole32(HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGG_SEGS |
928	    HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGGS |
929	    /* HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGG_TIMER | */
930	    HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MIN_AGG_LEN);
931	/* TODO: Calculate this based on ring size? */
932	req.max_agg_segs = htole16(3);
933	/* Base this in the allocated TPA start size... */
934	req.max_aggs = htole16(2);
935	/*
936	 * TODO: max_agg_timer?
937	 * req.mag_agg_timer = htole32(XXX);
938	 */
939	req.min_agg_len = htole32(0);
940
941	return hwrm_send_message(softc, &req, sizeof(req));
942}
943
944int
945bnxt_hwrm_nvm_find_dir_entry(struct bnxt_softc *softc, uint16_t type,
946    uint16_t *ordinal, uint16_t ext, uint16_t *index, bool use_index,
947    uint8_t search_opt, uint32_t *data_length, uint32_t *item_length,
948    uint32_t *fw_ver)
949{
950	struct hwrm_nvm_find_dir_entry_input req = {0};
951	struct hwrm_nvm_find_dir_entry_output *resp =
952	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
953	int	rc = 0;
954	uint32_t old_timeo;
955
956	MPASS(ordinal);
957
958	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_FIND_DIR_ENTRY);
959	if (use_index) {
960		req.enables = htole32(
961		    HWRM_NVM_FIND_DIR_ENTRY_INPUT_ENABLES_DIR_IDX_VALID);
962		req.dir_idx = htole16(*index);
963	}
964	req.dir_type = htole16(type);
965	req.dir_ordinal = htole16(*ordinal);
966	req.dir_ext = htole16(ext);
967	req.opt_ordinal = search_opt;
968
969	BNXT_HWRM_LOCK(softc);
970	old_timeo = softc->hwrm_cmd_timeo;
971	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
972	rc = _hwrm_send_message(softc, &req, sizeof(req));
973	softc->hwrm_cmd_timeo = old_timeo;
974	if (rc)
975		goto exit;
976
977	if (item_length)
978		*item_length = le32toh(resp->dir_item_length);
979	if (data_length)
980		*data_length = le32toh(resp->dir_data_length);
981	if (fw_ver)
982		*fw_ver = le32toh(resp->fw_ver);
983	*ordinal = le16toh(resp->dir_ordinal);
984	if (index)
985		*index = le16toh(resp->dir_idx);
986
987exit:
988	BNXT_HWRM_UNLOCK(softc);
989	return (rc);
990}
991
992int
993bnxt_hwrm_nvm_read(struct bnxt_softc *softc, uint16_t index, uint32_t offset,
994    uint32_t length, struct iflib_dma_info *data)
995{
996	struct hwrm_nvm_read_input req = {0};
997	int rc;
998	uint32_t old_timeo;
999
1000	if (length > data->idi_size) {
1001		rc = EINVAL;
1002		goto exit;
1003	}
1004	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_READ);
1005	req.host_dest_addr = htole64(data->idi_paddr);
1006	req.dir_idx = htole16(index);
1007	req.offset = htole32(offset);
1008	req.len = htole32(length);
1009	BNXT_HWRM_LOCK(softc);
1010	old_timeo = softc->hwrm_cmd_timeo;
1011	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1012	rc = _hwrm_send_message(softc, &req, sizeof(req));
1013	softc->hwrm_cmd_timeo = old_timeo;
1014	BNXT_HWRM_UNLOCK(softc);
1015	if (rc)
1016		goto exit;
1017	bus_dmamap_sync(data->idi_tag, data->idi_map, BUS_DMASYNC_POSTREAD);
1018
1019	goto exit;
1020
1021exit:
1022	return rc;
1023}
1024
1025int
1026bnxt_hwrm_nvm_modify(struct bnxt_softc *softc, uint16_t index, uint32_t offset,
1027    void *data, bool cpyin, uint32_t length)
1028{
1029	struct hwrm_nvm_modify_input req = {0};
1030	struct iflib_dma_info dma_data;
1031	int rc;
1032	uint32_t old_timeo;
1033
1034	if (length == 0 || !data)
1035		return EINVAL;
1036	rc = iflib_dma_alloc(softc->ctx, length, &dma_data,
1037	    BUS_DMA_NOWAIT);
1038	if (rc)
1039		return ENOMEM;
1040	if (cpyin) {
1041		rc = copyin(data, dma_data.idi_vaddr, length);
1042		if (rc)
1043			goto exit;
1044	}
1045	else
1046		memcpy(dma_data.idi_vaddr, data, length);
1047	bus_dmamap_sync(dma_data.idi_tag, dma_data.idi_map,
1048	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1049
1050	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_MODIFY);
1051	req.host_src_addr = htole64(dma_data.idi_paddr);
1052	req.dir_idx = htole16(index);
1053	req.offset = htole32(offset);
1054	req.len = htole32(length);
1055	BNXT_HWRM_LOCK(softc);
1056	old_timeo = softc->hwrm_cmd_timeo;
1057	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1058	rc = _hwrm_send_message(softc, &req, sizeof(req));
1059	softc->hwrm_cmd_timeo = old_timeo;
1060	BNXT_HWRM_UNLOCK(softc);
1061
1062exit:
1063	iflib_dma_free(&dma_data);
1064	return rc;
1065}
1066
1067int
1068bnxt_hwrm_fw_reset(struct bnxt_softc *softc, uint8_t processor,
1069    uint8_t *selfreset)
1070{
1071	struct hwrm_fw_reset_input req = {0};
1072	struct hwrm_fw_reset_output *resp =
1073	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1074	int rc;
1075
1076	MPASS(selfreset);
1077
1078	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_RESET);
1079	req.embedded_proc_type = processor;
1080	req.selfrst_status = *selfreset;
1081
1082	BNXT_HWRM_LOCK(softc);
1083	rc = _hwrm_send_message(softc, &req, sizeof(req));
1084	if (rc)
1085		goto exit;
1086	*selfreset = resp->selfrst_status;
1087
1088exit:
1089	BNXT_HWRM_UNLOCK(softc);
1090	return rc;
1091}
1092
1093int
1094bnxt_hwrm_fw_qstatus(struct bnxt_softc *softc, uint8_t type, uint8_t *selfreset)
1095{
1096	struct hwrm_fw_qstatus_input req = {0};
1097	struct hwrm_fw_qstatus_output *resp =
1098	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1099	int rc;
1100
1101	MPASS(selfreset);
1102
1103	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_QSTATUS);
1104	req.embedded_proc_type = type;
1105
1106	BNXT_HWRM_LOCK(softc);
1107	rc = _hwrm_send_message(softc, &req, sizeof(req));
1108	if (rc)
1109		goto exit;
1110	*selfreset = resp->selfrst_status;
1111
1112exit:
1113	BNXT_HWRM_UNLOCK(softc);
1114	return rc;
1115}
1116
1117int
1118bnxt_hwrm_nvm_write(struct bnxt_softc *softc, void *data, bool cpyin,
1119    uint16_t type, uint16_t ordinal, uint16_t ext, uint16_t attr,
1120    uint16_t option, uint32_t data_length, bool keep, uint32_t *item_length,
1121    uint16_t *index)
1122{
1123	struct hwrm_nvm_write_input req = {0};
1124	struct hwrm_nvm_write_output *resp =
1125	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1126	struct iflib_dma_info dma_data;
1127	int rc;
1128	uint32_t old_timeo;
1129
1130	if (data_length) {
1131		rc = iflib_dma_alloc(softc->ctx, data_length, &dma_data,
1132		    BUS_DMA_NOWAIT);
1133		if (rc)
1134			return ENOMEM;
1135		if (cpyin) {
1136			rc = copyin(data, dma_data.idi_vaddr, data_length);
1137			if (rc)
1138				goto early_exit;
1139		}
1140		else
1141			memcpy(dma_data.idi_vaddr, data, data_length);
1142		bus_dmamap_sync(dma_data.idi_tag, dma_data.idi_map,
1143		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1144	}
1145	else
1146		dma_data.idi_paddr = 0;
1147
1148	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_WRITE);
1149
1150	req.host_src_addr = htole64(dma_data.idi_paddr);
1151	req.dir_type = htole16(type);
1152	req.dir_ordinal = htole16(ordinal);
1153	req.dir_ext = htole16(ext);
1154	req.dir_attr = htole16(attr);
1155	req.dir_data_length = htole32(data_length);
1156	req.option = htole16(option);
1157	if (keep) {
1158		req.flags =
1159		    htole16(HWRM_NVM_WRITE_INPUT_FLAGS_KEEP_ORIG_ACTIVE_IMG);
1160	}
1161	if (item_length)
1162		req.dir_item_length = htole32(*item_length);
1163
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	if (rc)
1170		goto exit;
1171	if (item_length)
1172		*item_length = le32toh(resp->dir_item_length);
1173	if (index)
1174		*index = le16toh(resp->dir_idx);
1175
1176exit:
1177	BNXT_HWRM_UNLOCK(softc);
1178early_exit:
1179	if (data_length)
1180		iflib_dma_free(&dma_data);
1181	return rc;
1182}
1183
1184int
1185bnxt_hwrm_nvm_erase_dir_entry(struct bnxt_softc *softc, uint16_t index)
1186{
1187	struct hwrm_nvm_erase_dir_entry_input req = {0};
1188	uint32_t old_timeo;
1189	int rc;
1190
1191	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_ERASE_DIR_ENTRY);
1192	req.dir_idx = htole16(index);
1193	BNXT_HWRM_LOCK(softc);
1194	old_timeo = softc->hwrm_cmd_timeo;
1195	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1196	rc = _hwrm_send_message(softc, &req, sizeof(req));
1197	softc->hwrm_cmd_timeo = old_timeo;
1198	BNXT_HWRM_UNLOCK(softc);
1199	return rc;
1200}
1201
1202int
1203bnxt_hwrm_nvm_get_dir_info(struct bnxt_softc *softc, uint32_t *entries,
1204    uint32_t *entry_length)
1205{
1206	struct hwrm_nvm_get_dir_info_input req = {0};
1207	struct hwrm_nvm_get_dir_info_output *resp =
1208	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1209	int rc;
1210	uint32_t old_timeo;
1211
1212	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DIR_INFO);
1213
1214	BNXT_HWRM_LOCK(softc);
1215	old_timeo = softc->hwrm_cmd_timeo;
1216	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1217	rc = _hwrm_send_message(softc, &req, sizeof(req));
1218	softc->hwrm_cmd_timeo = old_timeo;
1219	if (rc)
1220		goto exit;
1221
1222	if (entries)
1223		*entries = le32toh(resp->entries);
1224	if (entry_length)
1225		*entry_length = le32toh(resp->entry_length);
1226
1227exit:
1228	BNXT_HWRM_UNLOCK(softc);
1229	return rc;
1230}
1231
1232int
1233bnxt_hwrm_nvm_get_dir_entries(struct bnxt_softc *softc, uint32_t *entries,
1234    uint32_t *entry_length, struct iflib_dma_info *dma_data)
1235{
1236	struct hwrm_nvm_get_dir_entries_input req = {0};
1237	uint32_t ent;
1238	uint32_t ent_len;
1239	int rc;
1240	uint32_t old_timeo;
1241
1242	if (!entries)
1243		entries = &ent;
1244	if (!entry_length)
1245		entry_length = &ent_len;
1246
1247	rc = bnxt_hwrm_nvm_get_dir_info(softc, entries, entry_length);
1248	if (rc)
1249		goto exit;
1250	if (*entries * *entry_length > dma_data->idi_size) {
1251		rc = EINVAL;
1252		goto exit;
1253	}
1254
1255	/*
1256	 * TODO: There's a race condition here that could blow up DMA memory...
1257	 *	 we need to allocate the max size, not the currently in use
1258	 *	 size.  The command should totally have a max size here.
1259	 */
1260	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DIR_ENTRIES);
1261	req.host_dest_addr = htole64(dma_data->idi_paddr);
1262	BNXT_HWRM_LOCK(softc);
1263	old_timeo = softc->hwrm_cmd_timeo;
1264	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1265	rc = _hwrm_send_message(softc, &req, sizeof(req));
1266	softc->hwrm_cmd_timeo = old_timeo;
1267	BNXT_HWRM_UNLOCK(softc);
1268	if (rc)
1269		goto exit;
1270	bus_dmamap_sync(dma_data->idi_tag, dma_data->idi_map,
1271	    BUS_DMASYNC_POSTWRITE);
1272
1273exit:
1274	return rc;
1275}
1276
1277int
1278bnxt_hwrm_nvm_get_dev_info(struct bnxt_softc *softc, uint16_t *mfg_id,
1279    uint16_t *device_id, uint32_t *sector_size, uint32_t *nvram_size,
1280    uint32_t *reserved_size, uint32_t *available_size)
1281{
1282	struct hwrm_nvm_get_dev_info_input req = {0};
1283	struct hwrm_nvm_get_dev_info_output *resp =
1284	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1285	int rc;
1286	uint32_t old_timeo;
1287
1288	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DEV_INFO);
1289
1290	BNXT_HWRM_LOCK(softc);
1291	old_timeo = softc->hwrm_cmd_timeo;
1292	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1293	rc = _hwrm_send_message(softc, &req, sizeof(req));
1294	softc->hwrm_cmd_timeo = old_timeo;
1295	if (rc)
1296		goto exit;
1297
1298	if (mfg_id)
1299		*mfg_id = le16toh(resp->manufacturer_id);
1300	if (device_id)
1301		*device_id = le16toh(resp->device_id);
1302	if (sector_size)
1303		*sector_size = le32toh(resp->sector_size);
1304	if (nvram_size)
1305		*nvram_size = le32toh(resp->nvram_size);
1306	if (reserved_size)
1307		*reserved_size = le32toh(resp->reserved_size);
1308	if (available_size)
1309		*available_size = le32toh(resp->available_size);
1310
1311exit:
1312	BNXT_HWRM_UNLOCK(softc);
1313	return rc;
1314}
1315
1316int
1317bnxt_hwrm_nvm_install_update(struct bnxt_softc *softc,
1318    uint32_t install_type, uint64_t *installed_items, uint8_t *result,
1319    uint8_t *problem_item, uint8_t *reset_required)
1320{
1321	struct hwrm_nvm_install_update_input req = {0};
1322	struct hwrm_nvm_install_update_output *resp =
1323	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1324	int rc;
1325	uint32_t old_timeo;
1326
1327	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_INSTALL_UPDATE);
1328	req.install_type = htole32(install_type);
1329
1330	BNXT_HWRM_LOCK(softc);
1331	old_timeo = softc->hwrm_cmd_timeo;
1332	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1333	rc = _hwrm_send_message(softc, &req, sizeof(req));
1334	softc->hwrm_cmd_timeo = old_timeo;
1335	if (rc)
1336		goto exit;
1337
1338	if (installed_items)
1339		*installed_items = le32toh(resp->installed_items);
1340	if (result)
1341		*result = resp->result;
1342	if (problem_item)
1343		*problem_item = resp->problem_item;
1344	if (reset_required)
1345		*reset_required = resp->reset_required;
1346
1347exit:
1348	BNXT_HWRM_UNLOCK(softc);
1349	return rc;
1350}
1351
1352int
1353bnxt_hwrm_nvm_verify_update(struct bnxt_softc *softc, uint16_t type,
1354    uint16_t ordinal, uint16_t ext)
1355{
1356	struct hwrm_nvm_verify_update_input req = {0};
1357	uint32_t old_timeo;
1358	int rc;
1359
1360	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_VERIFY_UPDATE);
1361
1362	req.dir_type = htole16(type);
1363	req.dir_ordinal = htole16(ordinal);
1364	req.dir_ext = htole16(ext);
1365
1366	BNXT_HWRM_LOCK(softc);
1367	old_timeo = softc->hwrm_cmd_timeo;
1368	softc->hwrm_cmd_timeo = BNXT_NVM_TIMEO;
1369	rc = _hwrm_send_message(softc, &req, sizeof(req));
1370	softc->hwrm_cmd_timeo = old_timeo;
1371	BNXT_HWRM_UNLOCK(softc);
1372	return rc;
1373}
1374
1375int
1376bnxt_hwrm_fw_get_time(struct bnxt_softc *softc, uint16_t *year, uint8_t *month,
1377    uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second,
1378    uint16_t *millisecond, uint16_t *zone)
1379{
1380	struct hwrm_fw_get_time_input req = {0};
1381	struct hwrm_fw_get_time_output *resp =
1382	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1383	int rc;
1384
1385	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_GET_TIME);
1386
1387	BNXT_HWRM_LOCK(softc);
1388	rc = _hwrm_send_message(softc, &req, sizeof(req));
1389	if (rc)
1390		goto exit;
1391
1392	if (year)
1393		*year = le16toh(resp->year);
1394	if (month)
1395		*month = resp->month;
1396	if (day)
1397		*day = resp->day;
1398	if (hour)
1399		*hour = resp->hour;
1400	if (minute)
1401		*minute = resp->minute;
1402	if (second)
1403		*second = resp->second;
1404	if (millisecond)
1405		*millisecond = le16toh(resp->millisecond);
1406	if (zone)
1407		*zone = le16toh(resp->zone);
1408
1409exit:
1410	BNXT_HWRM_UNLOCK(softc);
1411	return rc;
1412}
1413
1414int
1415bnxt_hwrm_fw_set_time(struct bnxt_softc *softc, uint16_t year, uint8_t month,
1416    uint8_t day, uint8_t hour, uint8_t minute, uint8_t second,
1417    uint16_t millisecond, uint16_t zone)
1418{
1419	struct hwrm_fw_set_time_input req = {0};
1420
1421	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_SET_TIME);
1422
1423	req.year = htole16(year);
1424	req.month = month;
1425	req.day = day;
1426	req.hour = hour;
1427	req.minute = minute;
1428	req.second = second;
1429	req.millisecond = htole16(millisecond);
1430	req.zone = htole16(zone);
1431	return hwrm_send_message(softc, &req, sizeof(req));
1432}
1433
1434int
1435bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *softc)
1436{
1437	struct bnxt_link_info *link_info = &softc->link_info;
1438	struct hwrm_port_phy_qcfg_input req = {0};
1439	struct hwrm_port_phy_qcfg_output *resp =
1440	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
1441	int rc = 0;
1442
1443	BNXT_HWRM_LOCK(softc);
1444	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_QCFG);
1445
1446	rc = _hwrm_send_message(softc, &req, sizeof(req));
1447	if (rc)
1448		goto exit;
1449
1450	link_info->phy_link_status = resp->link;
1451	link_info->duplex =  resp->duplex;
1452	link_info->pause = resp->pause;
1453	link_info->auto_mode = resp->auto_mode;
1454	link_info->auto_pause = resp->auto_pause;
1455	link_info->force_pause = resp->force_pause;
1456	link_info->duplex_setting = resp->duplex;
1457	if (link_info->phy_link_status == HWRM_PORT_PHY_QCFG_OUTPUT_LINK_LINK)
1458		link_info->link_speed = le16toh(resp->link_speed);
1459	else
1460		link_info->link_speed = 0;
1461	link_info->force_link_speed = le16toh(resp->force_link_speed);
1462	link_info->auto_link_speed = le16toh(resp->auto_link_speed);
1463	link_info->support_speeds = le16toh(resp->support_speeds);
1464	link_info->auto_link_speeds = le16toh(resp->auto_link_speed_mask);
1465	link_info->preemphasis = le32toh(resp->preemphasis);
1466	link_info->phy_ver[0] = resp->phy_maj;
1467	link_info->phy_ver[1] = resp->phy_min;
1468	link_info->phy_ver[2] = resp->phy_bld;
1469	snprintf(softc->ver_info->phy_ver, sizeof(softc->ver_info->phy_ver),
1470	    "%d.%d.%d", link_info->phy_ver[0], link_info->phy_ver[1],
1471	    link_info->phy_ver[2]);
1472	strlcpy(softc->ver_info->phy_vendor, resp->phy_vendor_name,
1473	    BNXT_NAME_SIZE);
1474	strlcpy(softc->ver_info->phy_partnumber, resp->phy_vendor_partnumber,
1475	    BNXT_NAME_SIZE);
1476	link_info->media_type = resp->media_type;
1477	link_info->phy_type = resp->phy_type;
1478	link_info->transceiver = resp->xcvr_pkg_type;
1479	link_info->phy_addr = resp->eee_config_phy_addr &
1480	    HWRM_PORT_PHY_QCFG_OUTPUT_PHY_ADDR_MASK;
1481
1482exit:
1483	BNXT_HWRM_UNLOCK(softc);
1484	return rc;
1485}
1486