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