1*2783188aSjmatthew /* $OpenBSD: if_bnxt.c,v 1.52 2024/10/06 23:43:18 jmatthew Exp $ */ 2a7c0060aSjmatthew /*- 3a7c0060aSjmatthew * Broadcom NetXtreme-C/E network driver. 4a7c0060aSjmatthew * 5a7c0060aSjmatthew * Copyright (c) 2016 Broadcom, All Rights Reserved. 6a7c0060aSjmatthew * The term Broadcom refers to Broadcom Limited and/or its subsidiaries 7a7c0060aSjmatthew * 8a7c0060aSjmatthew * Redistribution and use in source and binary forms, with or without 9a7c0060aSjmatthew * modification, are permitted provided that the following conditions 10a7c0060aSjmatthew * are met: 11a7c0060aSjmatthew * 1. Redistributions of source code must retain the above copyright 12a7c0060aSjmatthew * notice, this list of conditions and the following disclaimer. 13a7c0060aSjmatthew * 2. Redistributions in binary form must reproduce the above copyright 14a7c0060aSjmatthew * notice, this list of conditions and the following disclaimer in the 15a7c0060aSjmatthew * documentation and/or other materials provided with the distribution. 16a7c0060aSjmatthew * 17a7c0060aSjmatthew * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' 18a7c0060aSjmatthew * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19a7c0060aSjmatthew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20a7c0060aSjmatthew * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21a7c0060aSjmatthew * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22a7c0060aSjmatthew * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23a7c0060aSjmatthew * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24a7c0060aSjmatthew * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25a7c0060aSjmatthew * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26a7c0060aSjmatthew * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27a7c0060aSjmatthew * THE POSSIBILITY OF SUCH DAMAGE. 28a7c0060aSjmatthew */ 29a7c0060aSjmatthew 30a7c0060aSjmatthew /* 31a7c0060aSjmatthew * Copyright (c) 2018 Jonathan Matthew <jmatthew@openbsd.org> 32a7c0060aSjmatthew * 33a7c0060aSjmatthew * Permission to use, copy, modify, and distribute this software for any 34a7c0060aSjmatthew * purpose with or without fee is hereby granted, provided that the above 35a7c0060aSjmatthew * copyright notice and this permission notice appear in all copies. 36a7c0060aSjmatthew * 37a7c0060aSjmatthew * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 38a7c0060aSjmatthew * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 39a7c0060aSjmatthew * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 40a7c0060aSjmatthew * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 41a7c0060aSjmatthew * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 42a7c0060aSjmatthew * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 43a7c0060aSjmatthew * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 44a7c0060aSjmatthew */ 45a7c0060aSjmatthew 46a7c0060aSjmatthew 47a7c0060aSjmatthew #include "bpfilter.h" 48af7e9c1bSjmatthew #include "vlan.h" 49a7c0060aSjmatthew 50a7c0060aSjmatthew #include <sys/param.h> 51a7c0060aSjmatthew #include <sys/systm.h> 52a7c0060aSjmatthew #include <sys/mbuf.h> 53a7c0060aSjmatthew #include <sys/malloc.h> 54a7c0060aSjmatthew #include <sys/device.h> 55a7c0060aSjmatthew #include <sys/stdint.h> 56a7c0060aSjmatthew #include <sys/sockio.h> 57a7c0060aSjmatthew #include <sys/atomic.h> 58d160d8f0Sjmatthew #include <sys/intrmap.h> 59a7c0060aSjmatthew 60a7c0060aSjmatthew #include <machine/bus.h> 61a7c0060aSjmatthew 62a7c0060aSjmatthew #include <dev/pci/pcivar.h> 63a7c0060aSjmatthew #include <dev/pci/pcidevs.h> 64a7c0060aSjmatthew 65a7c0060aSjmatthew #include <dev/pci/if_bnxtreg.h> 66a7c0060aSjmatthew 67a7c0060aSjmatthew #include <net/if.h> 68a7c0060aSjmatthew #include <net/if_media.h> 698a756155Sjmatthew #include <net/route.h> 70d160d8f0Sjmatthew #include <net/toeplitz.h> 71a7c0060aSjmatthew 72a7c0060aSjmatthew #if NBPFILTER > 0 73a7c0060aSjmatthew #include <net/bpf.h> 74a7c0060aSjmatthew #endif 75a7c0060aSjmatthew 76a7c0060aSjmatthew #include <netinet/in.h> 77a7c0060aSjmatthew #include <netinet/if_ether.h> 788a756155Sjmatthew #include <netinet/tcp.h> 798a756155Sjmatthew #include <netinet/tcp_timer.h> 808a756155Sjmatthew #include <netinet/tcp_var.h> 81a7c0060aSjmatthew 82a7c0060aSjmatthew #define BNXT_HWRM_BAR 0x10 83a7c0060aSjmatthew #define BNXT_DOORBELL_BAR 0x18 84a7c0060aSjmatthew 85765dc391Sjmatthew #define BNXT_MAX_QUEUES 8 86765dc391Sjmatthew 87765dc391Sjmatthew #define BNXT_CP_RING_ID_BASE 0 88765dc391Sjmatthew #define BNXT_RX_RING_ID_BASE (BNXT_MAX_QUEUES + 1) 89765dc391Sjmatthew #define BNXT_AG_RING_ID_BASE ((BNXT_MAX_QUEUES * 2) + 1) 90765dc391Sjmatthew #define BNXT_TX_RING_ID_BASE ((BNXT_MAX_QUEUES * 3) + 1) 91a7c0060aSjmatthew 92270601a5Sjmatthew #define BNXT_MAX_MTU 9500 93c4f53494Sjmatthew #define BNXT_AG_BUFFER_SIZE 8192 94c4f53494Sjmatthew 95c4f53494Sjmatthew #define BNXT_CP_PAGES 4 96a7c0060aSjmatthew 978490bd92Sjmatthew #define BNXT_MAX_TX_SEGS 31 98af7e9c1bSjmatthew #define BNXT_TX_SLOTS(bs) (bs->bs_map->dm_nsegs + 1) 99a7c0060aSjmatthew 100a7c0060aSjmatthew #define BNXT_HWRM_SHORT_REQ_LEN sizeof(struct hwrm_short_input) 101a7c0060aSjmatthew 102a7c0060aSjmatthew #define BNXT_HWRM_LOCK_INIT(_sc, _name) \ 103a7c0060aSjmatthew mtx_init_flags(&sc->sc_lock, IPL_NET, _name, 0) 104a7c0060aSjmatthew #define BNXT_HWRM_LOCK(_sc) mtx_enter(&_sc->sc_lock) 105a7c0060aSjmatthew #define BNXT_HWRM_UNLOCK(_sc) mtx_leave(&_sc->sc_lock) 106a7c0060aSjmatthew #define BNXT_HWRM_LOCK_DESTROY(_sc) /* nothing */ 107a7c0060aSjmatthew #define BNXT_HWRM_LOCK_ASSERT(_sc) MUTEX_ASSERT_LOCKED(&_sc->sc_lock) 108a7c0060aSjmatthew 109a7c0060aSjmatthew #define BNXT_FLAG_VF 0x0001 110a7c0060aSjmatthew #define BNXT_FLAG_NPAR 0x0002 111a7c0060aSjmatthew #define BNXT_FLAG_WOL_CAP 0x0004 112a7c0060aSjmatthew #define BNXT_FLAG_SHORT_CMD 0x0008 11361ed761cSsf #define BNXT_FLAG_MSIX 0x0010 114a7c0060aSjmatthew 1150c45b53cSjmatthew /* NVRam stuff has a five minute timeout */ 1160c45b53cSjmatthew #define BNXT_NVM_TIMEO (5 * 60 * 1000) 1170c45b53cSjmatthew 118a7c0060aSjmatthew #define NEXT_CP_CONS_V(_ring, _cons, _v_bit) \ 119a7c0060aSjmatthew do { \ 120a7c0060aSjmatthew if (++(_cons) == (_ring)->ring_size) \ 121a7c0060aSjmatthew ((_cons) = 0, (_v_bit) = !_v_bit); \ 122a7c0060aSjmatthew } while (0); 123a7c0060aSjmatthew 124a7c0060aSjmatthew struct bnxt_ring { 125a7c0060aSjmatthew uint64_t paddr; 126a7c0060aSjmatthew uint64_t doorbell; 127a7c0060aSjmatthew caddr_t vaddr; 128a7c0060aSjmatthew uint32_t ring_size; 129a7c0060aSjmatthew uint16_t id; 130a7c0060aSjmatthew uint16_t phys_id; 131a7c0060aSjmatthew }; 132a7c0060aSjmatthew 133a7c0060aSjmatthew struct bnxt_cp_ring { 134a7c0060aSjmatthew struct bnxt_ring ring; 135a7c0060aSjmatthew void *irq; 136a7c0060aSjmatthew struct bnxt_softc *softc; 137a7c0060aSjmatthew uint32_t cons; 138a7c0060aSjmatthew int v_bit; 139c4f53494Sjmatthew uint32_t commit_cons; 140c4f53494Sjmatthew int commit_v_bit; 141a7c0060aSjmatthew struct ctx_hw_stats *stats; 142a7c0060aSjmatthew uint32_t stats_ctx_id; 143765dc391Sjmatthew struct bnxt_dmamem *ring_mem; 144a7c0060aSjmatthew }; 145a7c0060aSjmatthew 146a7c0060aSjmatthew struct bnxt_grp_info { 147a7c0060aSjmatthew uint32_t grp_id; 148a7c0060aSjmatthew uint16_t stats_ctx; 149a7c0060aSjmatthew uint16_t rx_ring_id; 150a7c0060aSjmatthew uint16_t cp_ring_id; 151a7c0060aSjmatthew uint16_t ag_ring_id; 152a7c0060aSjmatthew }; 153a7c0060aSjmatthew 154a7c0060aSjmatthew struct bnxt_vnic_info { 155a7c0060aSjmatthew uint16_t id; 156a7c0060aSjmatthew uint16_t def_ring_grp; 157a7c0060aSjmatthew uint16_t cos_rule; 158a7c0060aSjmatthew uint16_t lb_rule; 159a7c0060aSjmatthew uint16_t mru; 160a7c0060aSjmatthew 161a7c0060aSjmatthew uint32_t flags; 162a7c0060aSjmatthew #define BNXT_VNIC_FLAG_DEFAULT 0x01 163a7c0060aSjmatthew #define BNXT_VNIC_FLAG_BD_STALL 0x02 164a7c0060aSjmatthew #define BNXT_VNIC_FLAG_VLAN_STRIP 0x04 165a7c0060aSjmatthew 166a7c0060aSjmatthew uint64_t filter_id; 167a7c0060aSjmatthew uint32_t flow_id; 168a7c0060aSjmatthew 169a7c0060aSjmatthew uint16_t rss_id; 170a7c0060aSjmatthew }; 171a7c0060aSjmatthew 172a7c0060aSjmatthew struct bnxt_slot { 173a7c0060aSjmatthew bus_dmamap_t bs_map; 174a7c0060aSjmatthew struct mbuf *bs_m; 175a7c0060aSjmatthew }; 176a7c0060aSjmatthew 177a7c0060aSjmatthew struct bnxt_dmamem { 178a7c0060aSjmatthew bus_dmamap_t bdm_map; 179a7c0060aSjmatthew bus_dma_segment_t bdm_seg; 180a7c0060aSjmatthew size_t bdm_size; 181a7c0060aSjmatthew caddr_t bdm_kva; 182a7c0060aSjmatthew }; 183a7c0060aSjmatthew #define BNXT_DMA_MAP(_bdm) ((_bdm)->bdm_map) 184a7c0060aSjmatthew #define BNXT_DMA_LEN(_bdm) ((_bdm)->bdm_size) 185a7c0060aSjmatthew #define BNXT_DMA_DVA(_bdm) ((u_int64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr) 186a7c0060aSjmatthew #define BNXT_DMA_KVA(_bdm) ((void *)(_bdm)->bdm_kva) 187a7c0060aSjmatthew 188765dc391Sjmatthew struct bnxt_rx_queue { 189765dc391Sjmatthew struct bnxt_softc *rx_softc; 190765dc391Sjmatthew struct ifiqueue *rx_ifiq; 191765dc391Sjmatthew struct bnxt_dmamem *rx_ring_mem; /* rx and ag */ 192765dc391Sjmatthew struct bnxt_ring rx_ring; 193765dc391Sjmatthew struct bnxt_ring rx_ag_ring; 194765dc391Sjmatthew struct if_rxring rxr[2]; 195765dc391Sjmatthew struct bnxt_slot *rx_slots; 196765dc391Sjmatthew struct bnxt_slot *rx_ag_slots; 197765dc391Sjmatthew int rx_prod; 198765dc391Sjmatthew int rx_cons; 199765dc391Sjmatthew int rx_ag_prod; 200765dc391Sjmatthew int rx_ag_cons; 201765dc391Sjmatthew struct timeout rx_refill; 202765dc391Sjmatthew }; 203765dc391Sjmatthew 204765dc391Sjmatthew struct bnxt_tx_queue { 205765dc391Sjmatthew struct bnxt_softc *tx_softc; 206765dc391Sjmatthew struct ifqueue *tx_ifq; 207765dc391Sjmatthew struct bnxt_dmamem *tx_ring_mem; 208765dc391Sjmatthew struct bnxt_ring tx_ring; 209765dc391Sjmatthew struct bnxt_slot *tx_slots; 210765dc391Sjmatthew int tx_prod; 211765dc391Sjmatthew int tx_cons; 212765dc391Sjmatthew int tx_ring_prod; 213765dc391Sjmatthew int tx_ring_cons; 214765dc391Sjmatthew }; 215765dc391Sjmatthew 216765dc391Sjmatthew struct bnxt_queue { 217765dc391Sjmatthew char q_name[8]; 218765dc391Sjmatthew int q_index; 219765dc391Sjmatthew void *q_ihc; 220765dc391Sjmatthew struct bnxt_softc *q_sc; 221765dc391Sjmatthew struct bnxt_cp_ring q_cp; 222765dc391Sjmatthew struct bnxt_rx_queue q_rx; 223765dc391Sjmatthew struct bnxt_tx_queue q_tx; 224765dc391Sjmatthew struct bnxt_grp_info q_rg; 225765dc391Sjmatthew }; 226765dc391Sjmatthew 227a7c0060aSjmatthew struct bnxt_softc { 228a7c0060aSjmatthew struct device sc_dev; 229a7c0060aSjmatthew struct arpcom sc_ac; 230a7c0060aSjmatthew struct ifmedia sc_media; 231a7c0060aSjmatthew 232a7c0060aSjmatthew struct mutex sc_lock; 233a7c0060aSjmatthew 234a7c0060aSjmatthew pci_chipset_tag_t sc_pc; 235a7c0060aSjmatthew pcitag_t sc_tag; 236a7c0060aSjmatthew bus_dma_tag_t sc_dmat; 237a7c0060aSjmatthew 238a7c0060aSjmatthew bus_space_tag_t sc_hwrm_t; 239a7c0060aSjmatthew bus_space_handle_t sc_hwrm_h; 240a7c0060aSjmatthew bus_size_t sc_hwrm_s; 241a7c0060aSjmatthew 242a7c0060aSjmatthew struct bnxt_dmamem *sc_cmd_resp; 243a7c0060aSjmatthew uint16_t sc_cmd_seq; 244a7c0060aSjmatthew uint16_t sc_max_req_len; 245a7c0060aSjmatthew uint32_t sc_cmd_timeo; 246a7c0060aSjmatthew uint32_t sc_flags; 247a7c0060aSjmatthew 248a7c0060aSjmatthew bus_space_tag_t sc_db_t; 249a7c0060aSjmatthew bus_space_handle_t sc_db_h; 250a7c0060aSjmatthew bus_size_t sc_db_s; 251a7c0060aSjmatthew 252a7c0060aSjmatthew void *sc_ih; 253a7c0060aSjmatthew 25492586e53Sjmatthew int sc_hwrm_ver; 255d460f6dcSjmatthew int sc_tx_queue_id; 256a7c0060aSjmatthew 257a7c0060aSjmatthew struct bnxt_vnic_info sc_vnic; 258a7c0060aSjmatthew struct bnxt_dmamem *sc_stats_ctx_mem; 259d160d8f0Sjmatthew struct bnxt_dmamem *sc_rx_cfg; 260a7c0060aSjmatthew 261a7c0060aSjmatthew struct bnxt_cp_ring sc_cp_ring; 262a7c0060aSjmatthew 263765dc391Sjmatthew int sc_nqueues; 264765dc391Sjmatthew struct intrmap *sc_intrmap; 265765dc391Sjmatthew struct bnxt_queue sc_queues[BNXT_MAX_QUEUES]; 266a7c0060aSjmatthew }; 267a7c0060aSjmatthew #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) 268a7c0060aSjmatthew 269a7c0060aSjmatthew const struct pci_matchid bnxt_devices[] = { 270a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57301 }, 271a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57302 }, 272a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57304 }, 273a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57311 }, 274a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57312 }, 275a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57314 }, 276a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57402 }, 277a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57404 }, 278a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57406 }, 279a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57407 }, 280a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57412 }, 281a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57414 }, 282a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57416 }, 283a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57416_SFP }, 284a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57417 }, 285a7c0060aSjmatthew { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57417_SFP } 286a7c0060aSjmatthew }; 287a7c0060aSjmatthew 288a7c0060aSjmatthew int bnxt_match(struct device *, void *, void *); 289a7c0060aSjmatthew void bnxt_attach(struct device *, struct device *, void *); 290a7c0060aSjmatthew 291a7c0060aSjmatthew void bnxt_up(struct bnxt_softc *); 292a7c0060aSjmatthew void bnxt_down(struct bnxt_softc *); 293a7c0060aSjmatthew void bnxt_iff(struct bnxt_softc *); 294a7c0060aSjmatthew int bnxt_ioctl(struct ifnet *, u_long, caddr_t); 295a7c0060aSjmatthew int bnxt_rxrinfo(struct bnxt_softc *, struct if_rxrinfo *); 296a7c0060aSjmatthew void bnxt_start(struct ifqueue *); 297d160d8f0Sjmatthew int bnxt_admin_intr(void *); 298a7c0060aSjmatthew int bnxt_intr(void *); 299a7c0060aSjmatthew void bnxt_watchdog(struct ifnet *); 300a7c0060aSjmatthew void bnxt_media_status(struct ifnet *, struct ifmediareq *); 301a7c0060aSjmatthew int bnxt_media_change(struct ifnet *); 302c6900e6bSjmatthew int bnxt_media_autonegotiate(struct bnxt_softc *); 303a7c0060aSjmatthew 304c4f53494Sjmatthew struct cmpl_base *bnxt_cpr_next_cmpl(struct bnxt_softc *, struct bnxt_cp_ring *); 305c4f53494Sjmatthew void bnxt_cpr_commit(struct bnxt_softc *, struct bnxt_cp_ring *); 306c4f53494Sjmatthew void bnxt_cpr_rollback(struct bnxt_softc *, struct bnxt_cp_ring *); 307c4f53494Sjmatthew 308a7c0060aSjmatthew void bnxt_mark_cpr_invalid(struct bnxt_cp_ring *); 309a7c0060aSjmatthew void bnxt_write_cp_doorbell(struct bnxt_softc *, struct bnxt_ring *, 310a7c0060aSjmatthew int); 311a7c0060aSjmatthew void bnxt_write_cp_doorbell_index(struct bnxt_softc *, 312a7c0060aSjmatthew struct bnxt_ring *, uint32_t, int); 313a7c0060aSjmatthew void bnxt_write_rx_doorbell(struct bnxt_softc *, struct bnxt_ring *, 314a7c0060aSjmatthew int); 315a7c0060aSjmatthew void bnxt_write_tx_doorbell(struct bnxt_softc *, struct bnxt_ring *, 316a7c0060aSjmatthew int); 317a7c0060aSjmatthew 318765dc391Sjmatthew int bnxt_rx_fill(struct bnxt_queue *); 319*2783188aSjmatthew int bnxt_rx_fill_ag(struct bnxt_queue *); 320c4f53494Sjmatthew u_int bnxt_rx_fill_slots(struct bnxt_softc *, struct bnxt_ring *, void *, 321c4f53494Sjmatthew struct bnxt_slot *, uint *, int, uint16_t, u_int); 322a7c0060aSjmatthew void bnxt_refill(void *); 323765dc391Sjmatthew int bnxt_rx(struct bnxt_softc *, struct bnxt_rx_queue *, 324765dc391Sjmatthew struct bnxt_cp_ring *, struct mbuf_list *, int *, int *, 325765dc391Sjmatthew struct cmpl_base *); 326a7c0060aSjmatthew 327765dc391Sjmatthew void bnxt_txeof(struct bnxt_softc *, struct bnxt_tx_queue *, int *, 328765dc391Sjmatthew struct cmpl_base *); 329765dc391Sjmatthew 330765dc391Sjmatthew int bnxt_set_cp_ring_aggint(struct bnxt_softc *, struct bnxt_cp_ring *); 331a7c0060aSjmatthew 3320c45b53cSjmatthew int _hwrm_send_message(struct bnxt_softc *, void *, uint32_t); 3330c45b53cSjmatthew int hwrm_send_message(struct bnxt_softc *, void *, uint32_t); 3340c45b53cSjmatthew void bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *, void *, uint16_t); 3350c45b53cSjmatthew int bnxt_hwrm_err_map(uint16_t err); 336a7c0060aSjmatthew 337a7c0060aSjmatthew /* HWRM Function Prototypes */ 338a7c0060aSjmatthew int bnxt_hwrm_ring_alloc(struct bnxt_softc *, uint8_t, 339a7c0060aSjmatthew struct bnxt_ring *, uint16_t, uint32_t, int); 340a7c0060aSjmatthew int bnxt_hwrm_ring_free(struct bnxt_softc *, uint8_t, 341a7c0060aSjmatthew struct bnxt_ring *); 342a7c0060aSjmatthew int bnxt_hwrm_ver_get(struct bnxt_softc *); 343a7c0060aSjmatthew int bnxt_hwrm_queue_qportcfg(struct bnxt_softc *); 344a7c0060aSjmatthew int bnxt_hwrm_func_drv_rgtr(struct bnxt_softc *); 345a7c0060aSjmatthew int bnxt_hwrm_func_qcaps(struct bnxt_softc *); 346a7c0060aSjmatthew int bnxt_hwrm_func_qcfg(struct bnxt_softc *); 347a7c0060aSjmatthew int bnxt_hwrm_func_reset(struct bnxt_softc *); 348a7c0060aSjmatthew int bnxt_hwrm_vnic_ctx_alloc(struct bnxt_softc *, uint16_t *); 349a7c0060aSjmatthew int bnxt_hwrm_vnic_ctx_free(struct bnxt_softc *, uint16_t *); 350a7c0060aSjmatthew int bnxt_hwrm_vnic_cfg(struct bnxt_softc *, 351a7c0060aSjmatthew struct bnxt_vnic_info *); 352c4f53494Sjmatthew int bnxt_hwrm_vnic_cfg_placement(struct bnxt_softc *, 353c4f53494Sjmatthew struct bnxt_vnic_info *vnic); 354a7c0060aSjmatthew int bnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *, 355a7c0060aSjmatthew struct bnxt_cp_ring *, uint64_t); 356a7c0060aSjmatthew int bnxt_hwrm_stat_ctx_free(struct bnxt_softc *, 357a7c0060aSjmatthew struct bnxt_cp_ring *); 358a7c0060aSjmatthew int bnxt_hwrm_ring_grp_alloc(struct bnxt_softc *, 359a7c0060aSjmatthew struct bnxt_grp_info *); 360a7c0060aSjmatthew int bnxt_hwrm_ring_grp_free(struct bnxt_softc *, 361a7c0060aSjmatthew struct bnxt_grp_info *); 362a7c0060aSjmatthew int bnxt_hwrm_vnic_alloc(struct bnxt_softc *, 363a7c0060aSjmatthew struct bnxt_vnic_info *); 364a7c0060aSjmatthew int bnxt_hwrm_vnic_free(struct bnxt_softc *, 365a7c0060aSjmatthew struct bnxt_vnic_info *); 366a7c0060aSjmatthew int bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt_softc *, 367b12ece3dSjmatthew uint32_t, uint32_t, uint64_t, uint32_t); 368a7c0060aSjmatthew int bnxt_hwrm_set_filter(struct bnxt_softc *, 369a7c0060aSjmatthew struct bnxt_vnic_info *); 370a7c0060aSjmatthew int bnxt_hwrm_free_filter(struct bnxt_softc *, 371a7c0060aSjmatthew struct bnxt_vnic_info *); 372d160d8f0Sjmatthew int bnxt_hwrm_vnic_rss_cfg(struct bnxt_softc *, 373d160d8f0Sjmatthew struct bnxt_vnic_info *, uint32_t, daddr_t, daddr_t); 374765dc391Sjmatthew int bnxt_cfg_async_cr(struct bnxt_softc *, struct bnxt_cp_ring *); 375a7c0060aSjmatthew int bnxt_hwrm_nvm_get_dev_info(struct bnxt_softc *, uint16_t *, 376a7c0060aSjmatthew uint16_t *, uint32_t *, uint32_t *, uint32_t *, uint32_t *); 377a7c0060aSjmatthew int bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *, 378a7c0060aSjmatthew struct ifmediareq *); 379a7c0060aSjmatthew int bnxt_hwrm_func_rgtr_async_events(struct bnxt_softc *); 38040247284Sjmatthew int bnxt_get_sffpage(struct bnxt_softc *, struct if_sffpage *); 381a7c0060aSjmatthew 382a7c0060aSjmatthew /* not used yet: */ 383a7c0060aSjmatthew #if 0 384a7c0060aSjmatthew int bnxt_hwrm_func_drv_unrgtr(struct bnxt_softc *softc, bool shutdown); 385a7c0060aSjmatthew 386a7c0060aSjmatthew int bnxt_hwrm_port_qstats(struct bnxt_softc *softc); 387a7c0060aSjmatthew 388a7c0060aSjmatthew 389a7c0060aSjmatthew int bnxt_hwrm_vnic_tpa_cfg(struct bnxt_softc *softc); 390a7c0060aSjmatthew void bnxt_validate_hw_lro_settings(struct bnxt_softc *softc); 391a7c0060aSjmatthew int bnxt_hwrm_fw_reset(struct bnxt_softc *softc, uint8_t processor, 392a7c0060aSjmatthew uint8_t *selfreset); 393a7c0060aSjmatthew int bnxt_hwrm_fw_qstatus(struct bnxt_softc *softc, uint8_t type, 394a7c0060aSjmatthew uint8_t *selfreset); 395a7c0060aSjmatthew int bnxt_hwrm_fw_get_time(struct bnxt_softc *softc, uint16_t *year, 396a7c0060aSjmatthew uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute, 397a7c0060aSjmatthew uint8_t *second, uint16_t *millisecond, uint16_t *zone); 398a7c0060aSjmatthew int bnxt_hwrm_fw_set_time(struct bnxt_softc *softc, uint16_t year, 399a7c0060aSjmatthew uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, 400a7c0060aSjmatthew uint16_t millisecond, uint16_t zone); 401a7c0060aSjmatthew 402a7c0060aSjmatthew #endif 403a7c0060aSjmatthew 404a7c0060aSjmatthew 4058d2c75e4Smpi const struct cfattach bnxt_ca = { 406a7c0060aSjmatthew sizeof(struct bnxt_softc), bnxt_match, bnxt_attach 407a7c0060aSjmatthew }; 408a7c0060aSjmatthew 409a7c0060aSjmatthew struct cfdriver bnxt_cd = { 410a7c0060aSjmatthew NULL, "bnxt", DV_IFNET 411a7c0060aSjmatthew }; 412a7c0060aSjmatthew 413a7c0060aSjmatthew struct bnxt_dmamem * 414a7c0060aSjmatthew bnxt_dmamem_alloc(struct bnxt_softc *sc, size_t size) 415a7c0060aSjmatthew { 416a7c0060aSjmatthew struct bnxt_dmamem *m; 417a7c0060aSjmatthew int nsegs; 418a7c0060aSjmatthew 419a7c0060aSjmatthew m = malloc(sizeof(*m), M_DEVBUF, M_NOWAIT | M_ZERO); 420a7c0060aSjmatthew if (m == NULL) 421a7c0060aSjmatthew return (NULL); 422a7c0060aSjmatthew 423a7c0060aSjmatthew m->bdm_size = size; 424a7c0060aSjmatthew 425a7c0060aSjmatthew if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 426a7c0060aSjmatthew BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &m->bdm_map) != 0) 427a7c0060aSjmatthew goto bdmfree; 428a7c0060aSjmatthew 429a7c0060aSjmatthew if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &m->bdm_seg, 1, 430a7c0060aSjmatthew &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0) 431a7c0060aSjmatthew goto destroy; 432a7c0060aSjmatthew 433a7c0060aSjmatthew if (bus_dmamem_map(sc->sc_dmat, &m->bdm_seg, nsegs, size, &m->bdm_kva, 434a7c0060aSjmatthew BUS_DMA_NOWAIT) != 0) 435a7c0060aSjmatthew goto free; 436a7c0060aSjmatthew 437a7c0060aSjmatthew if (bus_dmamap_load(sc->sc_dmat, m->bdm_map, m->bdm_kva, size, NULL, 438a7c0060aSjmatthew BUS_DMA_NOWAIT) != 0) 439a7c0060aSjmatthew goto unmap; 440a7c0060aSjmatthew 441a7c0060aSjmatthew return (m); 442a7c0060aSjmatthew 443a7c0060aSjmatthew unmap: 444a7c0060aSjmatthew bus_dmamem_unmap(sc->sc_dmat, m->bdm_kva, m->bdm_size); 445a7c0060aSjmatthew free: 446a7c0060aSjmatthew bus_dmamem_free(sc->sc_dmat, &m->bdm_seg, 1); 447a7c0060aSjmatthew destroy: 448a7c0060aSjmatthew bus_dmamap_destroy(sc->sc_dmat, m->bdm_map); 449a7c0060aSjmatthew bdmfree: 450a7c0060aSjmatthew free(m, M_DEVBUF, sizeof *m); 451a7c0060aSjmatthew 452a7c0060aSjmatthew return (NULL); 453a7c0060aSjmatthew } 454a7c0060aSjmatthew 455a7c0060aSjmatthew void 456a7c0060aSjmatthew bnxt_dmamem_free(struct bnxt_softc *sc, struct bnxt_dmamem *m) 457a7c0060aSjmatthew { 4588dd611f8Sdlg bus_dmamap_unload(sc->sc_dmat, m->bdm_map); 459a7c0060aSjmatthew bus_dmamem_unmap(sc->sc_dmat, m->bdm_kva, m->bdm_size); 460a7c0060aSjmatthew bus_dmamem_free(sc->sc_dmat, &m->bdm_seg, 1); 461a7c0060aSjmatthew bus_dmamap_destroy(sc->sc_dmat, m->bdm_map); 462a7c0060aSjmatthew free(m, M_DEVBUF, sizeof *m); 463a7c0060aSjmatthew } 464a7c0060aSjmatthew 465a7c0060aSjmatthew int 466a7c0060aSjmatthew bnxt_match(struct device *parent, void *match, void *aux) 467a7c0060aSjmatthew { 468a7c0060aSjmatthew return (pci_matchbyid(aux, bnxt_devices, nitems(bnxt_devices))); 469a7c0060aSjmatthew } 470a7c0060aSjmatthew 471a7c0060aSjmatthew void 472a7c0060aSjmatthew bnxt_attach(struct device *parent, struct device *self, void *aux) 473a7c0060aSjmatthew { 474a7c0060aSjmatthew struct bnxt_softc *sc = (struct bnxt_softc *)self; 475a7c0060aSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 476a7c0060aSjmatthew struct pci_attach_args *pa = aux; 477765dc391Sjmatthew struct bnxt_cp_ring *cpr; 478a7c0060aSjmatthew pci_intr_handle_t ih; 479a7c0060aSjmatthew const char *intrstr; 480a7c0060aSjmatthew u_int memtype; 481765dc391Sjmatthew int i; 482a7c0060aSjmatthew 483a7c0060aSjmatthew sc->sc_pc = pa->pa_pc; 484a7c0060aSjmatthew sc->sc_tag = pa->pa_tag; 485a7c0060aSjmatthew sc->sc_dmat = pa->pa_dmat; 486a7c0060aSjmatthew 487a7c0060aSjmatthew memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BNXT_HWRM_BAR); 488a7c0060aSjmatthew if (pci_mapreg_map(pa, BNXT_HWRM_BAR, memtype, 0, &sc->sc_hwrm_t, 489a7c0060aSjmatthew &sc->sc_hwrm_h, NULL, &sc->sc_hwrm_s, 0)) { 490a7c0060aSjmatthew printf(": failed to map hwrm\n"); 491a7c0060aSjmatthew return; 492a7c0060aSjmatthew } 493a7c0060aSjmatthew 494a7c0060aSjmatthew memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BNXT_DOORBELL_BAR); 495a7c0060aSjmatthew if (pci_mapreg_map(pa, BNXT_DOORBELL_BAR, memtype, 0, &sc->sc_db_t, 496a7c0060aSjmatthew &sc->sc_db_h, NULL, &sc->sc_db_s, 0)) { 497a7c0060aSjmatthew printf(": failed to map doorbell\n"); 498a7c0060aSjmatthew goto unmap_1; 499a7c0060aSjmatthew } 500a7c0060aSjmatthew 501a7c0060aSjmatthew BNXT_HWRM_LOCK_INIT(sc, DEVNAME(sc)); 502a7c0060aSjmatthew sc->sc_cmd_resp = bnxt_dmamem_alloc(sc, PAGE_SIZE); 503a7c0060aSjmatthew if (sc->sc_cmd_resp == NULL) { 504a7c0060aSjmatthew printf(": failed to allocate command response buffer\n"); 505a7c0060aSjmatthew goto unmap_2; 506a7c0060aSjmatthew } 507a7c0060aSjmatthew 508a7c0060aSjmatthew if (bnxt_hwrm_ver_get(sc) != 0) { 509a7c0060aSjmatthew printf(": failed to query version info\n"); 510a7c0060aSjmatthew goto free_resp; 511a7c0060aSjmatthew } 512a7c0060aSjmatthew 513a7c0060aSjmatthew if (bnxt_hwrm_nvm_get_dev_info(sc, NULL, NULL, NULL, NULL, NULL, NULL) 514a7c0060aSjmatthew != 0) { 515a7c0060aSjmatthew printf(": failed to get nvram info\n"); 516a7c0060aSjmatthew goto free_resp; 517a7c0060aSjmatthew } 518a7c0060aSjmatthew 519a7c0060aSjmatthew if (bnxt_hwrm_func_drv_rgtr(sc) != 0) { 520a7c0060aSjmatthew printf(": failed to register driver with firmware\n"); 521a7c0060aSjmatthew goto free_resp; 522a7c0060aSjmatthew } 523a7c0060aSjmatthew 524a7c0060aSjmatthew if (bnxt_hwrm_func_rgtr_async_events(sc) != 0) { 525a7c0060aSjmatthew printf(": failed to register async events\n"); 526a7c0060aSjmatthew goto free_resp; 527a7c0060aSjmatthew } 528a7c0060aSjmatthew 529a7c0060aSjmatthew if (bnxt_hwrm_func_qcaps(sc) != 0) { 530a7c0060aSjmatthew printf(": failed to get queue capabilities\n"); 531a7c0060aSjmatthew goto free_resp; 532a7c0060aSjmatthew } 533a7c0060aSjmatthew 534a7c0060aSjmatthew /* 535a7c0060aSjmatthew * devices advertise msi support, but there's no way to tell a 536a7c0060aSjmatthew * completion queue to use msi mode, only legacy or msi-x. 537a7c0060aSjmatthew */ 53861ed761cSsf if (pci_intr_map_msix(pa, 0, &ih) == 0) { 539d160d8f0Sjmatthew int nmsix; 540d160d8f0Sjmatthew 54161ed761cSsf sc->sc_flags |= BNXT_FLAG_MSIX; 542d160d8f0Sjmatthew intrstr = pci_intr_string(sc->sc_pc, ih); 543d160d8f0Sjmatthew 544bc8858ceSjmatthew nmsix = pci_intr_msix_count(pa); 545d160d8f0Sjmatthew if (nmsix > 1) { 546d160d8f0Sjmatthew sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, 547d160d8f0Sjmatthew IPL_NET | IPL_MPSAFE, bnxt_admin_intr, sc, DEVNAME(sc)); 548d160d8f0Sjmatthew sc->sc_intrmap = intrmap_create(&sc->sc_dev, 549d160d8f0Sjmatthew nmsix - 1, BNXT_MAX_QUEUES, INTRMAP_POWEROF2); 550d160d8f0Sjmatthew sc->sc_nqueues = intrmap_count(sc->sc_intrmap); 551d160d8f0Sjmatthew KASSERT(sc->sc_nqueues > 0); 552d160d8f0Sjmatthew KASSERT(powerof2(sc->sc_nqueues)); 553d160d8f0Sjmatthew } else { 554d160d8f0Sjmatthew sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, 555d160d8f0Sjmatthew IPL_NET | IPL_MPSAFE, bnxt_intr, &sc->sc_queues[0], 556d160d8f0Sjmatthew DEVNAME(sc)); 557d160d8f0Sjmatthew sc->sc_nqueues = 1; 558a7c0060aSjmatthew } 559d160d8f0Sjmatthew } else if (pci_intr_map(pa, &ih) == 0) { 560a7c0060aSjmatthew intrstr = pci_intr_string(sc->sc_pc, ih); 561a7c0060aSjmatthew sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_NET | IPL_MPSAFE, 562765dc391Sjmatthew bnxt_intr, &sc->sc_queues[0], DEVNAME(sc)); 563d160d8f0Sjmatthew sc->sc_nqueues = 1; 564d160d8f0Sjmatthew } else { 565d160d8f0Sjmatthew printf(": unable to map interrupt\n"); 566d160d8f0Sjmatthew goto free_resp; 567d160d8f0Sjmatthew } 568a7c0060aSjmatthew if (sc->sc_ih == NULL) { 569a7c0060aSjmatthew printf(": unable to establish interrupt"); 570a7c0060aSjmatthew if (intrstr != NULL) 571a7c0060aSjmatthew printf(" at %s", intrstr); 572a7c0060aSjmatthew printf("\n"); 573a7c0060aSjmatthew goto deintr; 574a7c0060aSjmatthew } 575d160d8f0Sjmatthew printf("%s, %d queues, address %s\n", intrstr, sc->sc_nqueues, 576d160d8f0Sjmatthew ether_sprintf(sc->sc_ac.ac_enaddr)); 577a7c0060aSjmatthew 578a7c0060aSjmatthew if (bnxt_hwrm_func_qcfg(sc) != 0) { 579a7c0060aSjmatthew printf("%s: failed to query function config\n", DEVNAME(sc)); 580a7c0060aSjmatthew goto deintr; 581a7c0060aSjmatthew } 582a7c0060aSjmatthew 583a7c0060aSjmatthew if (bnxt_hwrm_queue_qportcfg(sc) != 0) { 584a7c0060aSjmatthew printf("%s: failed to query port config\n", DEVNAME(sc)); 585a7c0060aSjmatthew goto deintr; 586a7c0060aSjmatthew } 587a7c0060aSjmatthew 588a7c0060aSjmatthew if (bnxt_hwrm_func_reset(sc) != 0) { 589a7c0060aSjmatthew printf("%s: reset failed\n", DEVNAME(sc)); 590a7c0060aSjmatthew goto deintr; 591a7c0060aSjmatthew } 592a7c0060aSjmatthew 593e9c3085bSjmatthew if (sc->sc_intrmap == NULL) 594765dc391Sjmatthew cpr = &sc->sc_queues[0].q_cp; 595765dc391Sjmatthew else 596765dc391Sjmatthew cpr = &sc->sc_cp_ring; 597765dc391Sjmatthew 598765dc391Sjmatthew cpr->stats_ctx_id = HWRM_NA_SIGNATURE; 599765dc391Sjmatthew cpr->ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE; 600765dc391Sjmatthew cpr->softc = sc; 601765dc391Sjmatthew cpr->ring.id = 0; 602765dc391Sjmatthew cpr->ring.doorbell = cpr->ring.id * 0x80; 603765dc391Sjmatthew cpr->ring.ring_size = (PAGE_SIZE * BNXT_CP_PAGES) / 604c4f53494Sjmatthew sizeof(struct cmpl_base); 605765dc391Sjmatthew cpr->ring_mem = bnxt_dmamem_alloc(sc, PAGE_SIZE * 606765dc391Sjmatthew BNXT_CP_PAGES); 607765dc391Sjmatthew if (cpr->ring_mem == NULL) { 608a7c0060aSjmatthew printf("%s: failed to allocate completion queue memory\n", 609a7c0060aSjmatthew DEVNAME(sc)); 610a7c0060aSjmatthew goto deintr; 611a7c0060aSjmatthew } 612765dc391Sjmatthew cpr->ring.vaddr = BNXT_DMA_KVA(cpr->ring_mem); 613765dc391Sjmatthew cpr->ring.paddr = BNXT_DMA_DVA(cpr->ring_mem); 614765dc391Sjmatthew cpr->cons = UINT32_MAX; 615765dc391Sjmatthew cpr->v_bit = 1; 616765dc391Sjmatthew bnxt_mark_cpr_invalid(cpr); 617a7c0060aSjmatthew if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_L2_CMPL, 618765dc391Sjmatthew &cpr->ring, (uint16_t)HWRM_NA_SIGNATURE, 619a7c0060aSjmatthew HWRM_NA_SIGNATURE, 1) != 0) { 620a7c0060aSjmatthew printf("%s: failed to allocate completion queue\n", 621a7c0060aSjmatthew DEVNAME(sc)); 622a7c0060aSjmatthew goto free_cp_mem; 623a7c0060aSjmatthew } 624765dc391Sjmatthew if (bnxt_cfg_async_cr(sc, cpr) != 0) { 625a7c0060aSjmatthew printf("%s: failed to set async completion ring\n", 626a7c0060aSjmatthew DEVNAME(sc)); 627a7c0060aSjmatthew goto free_cp_mem; 628a7c0060aSjmatthew } 629765dc391Sjmatthew bnxt_write_cp_doorbell(sc, &cpr->ring, 1); 630a7c0060aSjmatthew 631765dc391Sjmatthew if (bnxt_set_cp_ring_aggint(sc, cpr) != 0) { 632765dc391Sjmatthew printf("%s: failed to set interrupt aggregation\n", 633765dc391Sjmatthew DEVNAME(sc)); 63416a10298Sjmatthew goto free_cp_mem; 635765dc391Sjmatthew } 63616a10298Sjmatthew 637a7c0060aSjmatthew strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 638a7c0060aSjmatthew ifp->if_softc = sc; 639a7c0060aSjmatthew ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; 640a7c0060aSjmatthew ifp->if_xflags = IFXF_MPSAFE; 641a7c0060aSjmatthew ifp->if_ioctl = bnxt_ioctl; 642a7c0060aSjmatthew ifp->if_qstart = bnxt_start; 643a7c0060aSjmatthew ifp->if_watchdog = bnxt_watchdog; 644a7c0060aSjmatthew ifp->if_hardmtu = BNXT_MAX_MTU; 645af7e9c1bSjmatthew ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_IPv4 | 646af7e9c1bSjmatthew IFCAP_CSUM_UDPv4 | IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv6 | 647af7e9c1bSjmatthew IFCAP_CSUM_TCPv6; 6488a756155Sjmatthew ifp->if_capabilities |= IFCAP_TSOv4 | IFCAP_TSOv6; 649af7e9c1bSjmatthew #if NVLAN > 0 650af7e9c1bSjmatthew ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 651af7e9c1bSjmatthew #endif 652cf96265bSbluhm ifq_init_maxlen(&ifp->if_snd, 1024); /* ? */ 653a7c0060aSjmatthew 654a7c0060aSjmatthew ifmedia_init(&sc->sc_media, IFM_IMASK, bnxt_media_change, 655a7c0060aSjmatthew bnxt_media_status); 656a7c0060aSjmatthew 657a7c0060aSjmatthew if_attach(ifp); 658a7c0060aSjmatthew ether_ifattach(ifp); 659a7c0060aSjmatthew 660765dc391Sjmatthew if_attach_iqueues(ifp, sc->sc_nqueues); 661765dc391Sjmatthew if_attach_queues(ifp, sc->sc_nqueues); 662765dc391Sjmatthew for (i = 0; i < sc->sc_nqueues; i++) { 663765dc391Sjmatthew struct ifiqueue *ifiq = ifp->if_iqs[i]; 664765dc391Sjmatthew struct ifqueue *ifq = ifp->if_ifqs[i]; 665765dc391Sjmatthew struct bnxt_queue *bq = &sc->sc_queues[i]; 666d160d8f0Sjmatthew struct bnxt_cp_ring *cp = &bq->q_cp; 667765dc391Sjmatthew struct bnxt_rx_queue *rx = &bq->q_rx; 668765dc391Sjmatthew struct bnxt_tx_queue *tx = &bq->q_tx; 669765dc391Sjmatthew 670765dc391Sjmatthew bq->q_index = i; 671765dc391Sjmatthew bq->q_sc = sc; 672765dc391Sjmatthew 673765dc391Sjmatthew rx->rx_softc = sc; 674765dc391Sjmatthew rx->rx_ifiq = ifiq; 675765dc391Sjmatthew timeout_set(&rx->rx_refill, bnxt_refill, bq); 676765dc391Sjmatthew ifiq->ifiq_softc = rx; 677765dc391Sjmatthew 678765dc391Sjmatthew tx->tx_softc = sc; 679765dc391Sjmatthew tx->tx_ifq = ifq; 680765dc391Sjmatthew ifq->ifq_softc = tx; 681d160d8f0Sjmatthew 682e9c3085bSjmatthew if (sc->sc_intrmap != NULL) { 683d160d8f0Sjmatthew cp->stats_ctx_id = HWRM_NA_SIGNATURE; 684d160d8f0Sjmatthew cp->ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE; 685d160d8f0Sjmatthew cp->ring.id = i + 1; /* first cp ring is async only */ 686d160d8f0Sjmatthew cp->softc = sc; 687d160d8f0Sjmatthew cp->ring.doorbell = bq->q_cp.ring.id * 0x80; 688d160d8f0Sjmatthew cp->ring.ring_size = (PAGE_SIZE * BNXT_CP_PAGES) / 689d160d8f0Sjmatthew sizeof(struct cmpl_base); 690d160d8f0Sjmatthew if (pci_intr_map_msix(pa, i + 1, &ih) != 0) { 691d160d8f0Sjmatthew printf("%s: unable to map queue interrupt %d\n", 692d160d8f0Sjmatthew DEVNAME(sc), i); 693d160d8f0Sjmatthew goto intrdisestablish; 694d160d8f0Sjmatthew } 695d160d8f0Sjmatthew snprintf(bq->q_name, sizeof(bq->q_name), "%s:%d", 696d160d8f0Sjmatthew DEVNAME(sc), i); 697d160d8f0Sjmatthew bq->q_ihc = pci_intr_establish_cpu(sc->sc_pc, ih, 698d160d8f0Sjmatthew IPL_NET | IPL_MPSAFE, intrmap_cpu(sc->sc_intrmap, i), 699d160d8f0Sjmatthew bnxt_intr, bq, bq->q_name); 700d160d8f0Sjmatthew if (bq->q_ihc == NULL) { 701d160d8f0Sjmatthew printf("%s: unable to establish interrupt %d\n", 702d160d8f0Sjmatthew DEVNAME(sc), i); 703d160d8f0Sjmatthew goto intrdisestablish; 704d160d8f0Sjmatthew } 705d160d8f0Sjmatthew } 706765dc391Sjmatthew } 707a7c0060aSjmatthew 708c6900e6bSjmatthew bnxt_media_autonegotiate(sc); 709a7c0060aSjmatthew bnxt_hwrm_port_phy_qcfg(sc, NULL); 710a7c0060aSjmatthew return; 711a7c0060aSjmatthew 712d160d8f0Sjmatthew intrdisestablish: 713d160d8f0Sjmatthew for (i = 0; i < sc->sc_nqueues; i++) { 714d160d8f0Sjmatthew struct bnxt_queue *bq = &sc->sc_queues[i]; 715d160d8f0Sjmatthew if (bq->q_ihc == NULL) 716d160d8f0Sjmatthew continue; 717d160d8f0Sjmatthew pci_intr_disestablish(sc->sc_pc, bq->q_ihc); 718d160d8f0Sjmatthew bq->q_ihc = NULL; 719d160d8f0Sjmatthew } 720a7c0060aSjmatthew free_cp_mem: 721765dc391Sjmatthew bnxt_dmamem_free(sc, cpr->ring_mem); 722a7c0060aSjmatthew deintr: 723d160d8f0Sjmatthew if (sc->sc_intrmap != NULL) { 724d160d8f0Sjmatthew intrmap_destroy(sc->sc_intrmap); 725d160d8f0Sjmatthew sc->sc_intrmap = NULL; 726d160d8f0Sjmatthew } 727a7c0060aSjmatthew pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 728a7c0060aSjmatthew sc->sc_ih = NULL; 729a7c0060aSjmatthew free_resp: 730a7c0060aSjmatthew bnxt_dmamem_free(sc, sc->sc_cmd_resp); 731a7c0060aSjmatthew unmap_2: 732a7c0060aSjmatthew bus_space_unmap(sc->sc_db_t, sc->sc_db_h, sc->sc_db_s); 733a7c0060aSjmatthew sc->sc_db_s = 0; 734416e388eSdenis unmap_1: 735416e388eSdenis bus_space_unmap(sc->sc_hwrm_t, sc->sc_hwrm_h, sc->sc_hwrm_s); 736416e388eSdenis sc->sc_hwrm_s = 0; 737a7c0060aSjmatthew } 738a7c0060aSjmatthew 739a7c0060aSjmatthew void 740a7c0060aSjmatthew bnxt_free_slots(struct bnxt_softc *sc, struct bnxt_slot *slots, int allocated, 741a7c0060aSjmatthew int total) 742a7c0060aSjmatthew { 743a7c0060aSjmatthew struct bnxt_slot *bs; 744a7c0060aSjmatthew 745a7c0060aSjmatthew int i = allocated; 746a7c0060aSjmatthew while (i-- > 0) { 747a7c0060aSjmatthew bs = &slots[i]; 748a7c0060aSjmatthew bus_dmamap_destroy(sc->sc_dmat, bs->bs_map); 74934df0755Sjmatthew if (bs->bs_m != NULL) 75034df0755Sjmatthew m_freem(bs->bs_m); 751a7c0060aSjmatthew } 752a7c0060aSjmatthew free(slots, M_DEVBUF, total * sizeof(*bs)); 753a7c0060aSjmatthew } 754a7c0060aSjmatthew 755765dc391Sjmatthew int 756765dc391Sjmatthew bnxt_set_cp_ring_aggint(struct bnxt_softc *sc, struct bnxt_cp_ring *cpr) 757765dc391Sjmatthew { 758765dc391Sjmatthew struct hwrm_ring_cmpl_ring_cfg_aggint_params_input aggint; 759765dc391Sjmatthew 760765dc391Sjmatthew /* 761765dc391Sjmatthew * set interrupt aggregation parameters for around 10k interrupts 762765dc391Sjmatthew * per second. the timers are in units of 80usec, and the counters 763765dc391Sjmatthew * are based on the minimum rx ring size of 32. 764765dc391Sjmatthew */ 765765dc391Sjmatthew memset(&aggint, 0, sizeof(aggint)); 766765dc391Sjmatthew bnxt_hwrm_cmd_hdr_init(sc, &aggint, 767765dc391Sjmatthew HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS); 768765dc391Sjmatthew aggint.ring_id = htole16(cpr->ring.phys_id); 769765dc391Sjmatthew aggint.num_cmpl_dma_aggr = htole16(32); 770765dc391Sjmatthew aggint.num_cmpl_dma_aggr_during_int = aggint.num_cmpl_dma_aggr; 771765dc391Sjmatthew aggint.cmpl_aggr_dma_tmr = htole16((1000000000 / 20000) / 80); 772765dc391Sjmatthew aggint.cmpl_aggr_dma_tmr_during_int = aggint.cmpl_aggr_dma_tmr; 773765dc391Sjmatthew aggint.int_lat_tmr_min = htole16((1000000000 / 20000) / 80); 774765dc391Sjmatthew aggint.int_lat_tmr_max = htole16((1000000000 / 10000) / 80); 775765dc391Sjmatthew aggint.num_cmpl_aggr_int = htole16(16); 776765dc391Sjmatthew return (hwrm_send_message(sc, &aggint, sizeof(aggint))); 777765dc391Sjmatthew } 778765dc391Sjmatthew 779765dc391Sjmatthew int 780765dc391Sjmatthew bnxt_queue_up(struct bnxt_softc *sc, struct bnxt_queue *bq) 781765dc391Sjmatthew { 782765dc391Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 783765dc391Sjmatthew struct bnxt_cp_ring *cp = &bq->q_cp; 784765dc391Sjmatthew struct bnxt_rx_queue *rx = &bq->q_rx; 785765dc391Sjmatthew struct bnxt_tx_queue *tx = &bq->q_tx; 786765dc391Sjmatthew struct bnxt_grp_info *rg = &bq->q_rg; 787765dc391Sjmatthew struct bnxt_slot *bs; 788765dc391Sjmatthew int i; 789765dc391Sjmatthew 790765dc391Sjmatthew tx->tx_ring_mem = bnxt_dmamem_alloc(sc, PAGE_SIZE); 791765dc391Sjmatthew if (tx->tx_ring_mem == NULL) { 792765dc391Sjmatthew printf("%s: failed to allocate tx ring %d\n", DEVNAME(sc), bq->q_index); 793765dc391Sjmatthew return ENOMEM; 794765dc391Sjmatthew } 795765dc391Sjmatthew 796765dc391Sjmatthew rx->rx_ring_mem = bnxt_dmamem_alloc(sc, PAGE_SIZE * 2); 797765dc391Sjmatthew if (rx->rx_ring_mem == NULL) { 798765dc391Sjmatthew printf("%s: failed to allocate rx ring %d\n", DEVNAME(sc), bq->q_index); 799765dc391Sjmatthew goto free_tx; 800765dc391Sjmatthew } 801765dc391Sjmatthew 802e9c3085bSjmatthew /* completion ring is already allocated if we're not using an intrmap */ 803e9c3085bSjmatthew if (sc->sc_intrmap != NULL) { 804765dc391Sjmatthew cp->ring_mem = bnxt_dmamem_alloc(sc, PAGE_SIZE * BNXT_CP_PAGES); 805765dc391Sjmatthew if (cp->ring_mem == NULL) { 806765dc391Sjmatthew printf("%s: failed to allocate completion ring %d mem\n", 807765dc391Sjmatthew DEVNAME(sc), bq->q_index); 808765dc391Sjmatthew goto free_rx; 809765dc391Sjmatthew } 810765dc391Sjmatthew cp->ring.vaddr = BNXT_DMA_KVA(cp->ring_mem); 811765dc391Sjmatthew cp->ring.paddr = BNXT_DMA_DVA(cp->ring_mem); 812765dc391Sjmatthew cp->cons = UINT32_MAX; 813765dc391Sjmatthew cp->v_bit = 1; 814765dc391Sjmatthew bnxt_mark_cpr_invalid(cp); 815765dc391Sjmatthew 816765dc391Sjmatthew if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_L2_CMPL, 817765dc391Sjmatthew &cp->ring, (uint16_t)HWRM_NA_SIGNATURE, 818765dc391Sjmatthew HWRM_NA_SIGNATURE, 1) != 0) { 819765dc391Sjmatthew printf("%s: failed to allocate completion queue %d\n", 820765dc391Sjmatthew DEVNAME(sc), bq->q_index); 821765dc391Sjmatthew goto free_rx; 822765dc391Sjmatthew } 823765dc391Sjmatthew 824765dc391Sjmatthew if (bnxt_set_cp_ring_aggint(sc, cp) != 0) { 825765dc391Sjmatthew printf("%s: failed to set interrupt %d aggregation\n", 826765dc391Sjmatthew DEVNAME(sc), bq->q_index); 827765dc391Sjmatthew goto free_rx; 828765dc391Sjmatthew } 829765dc391Sjmatthew bnxt_write_cp_doorbell(sc, &cp->ring, 1); 830b59ce775Sjmatthew } 831765dc391Sjmatthew 832765dc391Sjmatthew if (bnxt_hwrm_stat_ctx_alloc(sc, &bq->q_cp, 833765dc391Sjmatthew BNXT_DMA_DVA(sc->sc_stats_ctx_mem) + 834765dc391Sjmatthew (bq->q_index * sizeof(struct ctx_hw_stats))) != 0) { 835765dc391Sjmatthew printf("%s: failed to set up stats context\n", DEVNAME(sc)); 836765dc391Sjmatthew goto free_rx; 837765dc391Sjmatthew } 838765dc391Sjmatthew 839765dc391Sjmatthew tx->tx_ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE; 840765dc391Sjmatthew tx->tx_ring.id = BNXT_TX_RING_ID_BASE + bq->q_index; 841765dc391Sjmatthew tx->tx_ring.doorbell = tx->tx_ring.id * 0x80; 842765dc391Sjmatthew tx->tx_ring.ring_size = PAGE_SIZE / sizeof(struct tx_bd_short); 843765dc391Sjmatthew tx->tx_ring.vaddr = BNXT_DMA_KVA(tx->tx_ring_mem); 844765dc391Sjmatthew tx->tx_ring.paddr = BNXT_DMA_DVA(tx->tx_ring_mem); 845765dc391Sjmatthew if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_TX, 846765dc391Sjmatthew &tx->tx_ring, cp->ring.phys_id, HWRM_NA_SIGNATURE, 1) != 0) { 847765dc391Sjmatthew printf("%s: failed to set up tx ring\n", 848765dc391Sjmatthew DEVNAME(sc)); 849765dc391Sjmatthew goto dealloc_stats; 850765dc391Sjmatthew } 851765dc391Sjmatthew bnxt_write_tx_doorbell(sc, &tx->tx_ring, 0); 852765dc391Sjmatthew 853765dc391Sjmatthew rx->rx_ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE; 854765dc391Sjmatthew rx->rx_ring.id = BNXT_RX_RING_ID_BASE + bq->q_index; 855765dc391Sjmatthew rx->rx_ring.doorbell = rx->rx_ring.id * 0x80; 856765dc391Sjmatthew rx->rx_ring.ring_size = PAGE_SIZE / sizeof(struct rx_prod_pkt_bd); 857765dc391Sjmatthew rx->rx_ring.vaddr = BNXT_DMA_KVA(rx->rx_ring_mem); 858765dc391Sjmatthew rx->rx_ring.paddr = BNXT_DMA_DVA(rx->rx_ring_mem); 859765dc391Sjmatthew if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX, 860765dc391Sjmatthew &rx->rx_ring, cp->ring.phys_id, HWRM_NA_SIGNATURE, 1) != 0) { 861765dc391Sjmatthew printf("%s: failed to set up rx ring\n", 862765dc391Sjmatthew DEVNAME(sc)); 863765dc391Sjmatthew goto dealloc_tx; 864765dc391Sjmatthew } 865765dc391Sjmatthew bnxt_write_rx_doorbell(sc, &rx->rx_ring, 0); 866765dc391Sjmatthew 867765dc391Sjmatthew rx->rx_ag_ring.phys_id = (uint16_t)HWRM_NA_SIGNATURE; 868765dc391Sjmatthew rx->rx_ag_ring.id = BNXT_AG_RING_ID_BASE + bq->q_index; 869765dc391Sjmatthew rx->rx_ag_ring.doorbell = rx->rx_ag_ring.id * 0x80; 870765dc391Sjmatthew rx->rx_ag_ring.ring_size = PAGE_SIZE / sizeof(struct rx_prod_pkt_bd); 871765dc391Sjmatthew rx->rx_ag_ring.vaddr = BNXT_DMA_KVA(rx->rx_ring_mem) + PAGE_SIZE; 872765dc391Sjmatthew rx->rx_ag_ring.paddr = BNXT_DMA_DVA(rx->rx_ring_mem) + PAGE_SIZE; 873765dc391Sjmatthew if (bnxt_hwrm_ring_alloc(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX, 874765dc391Sjmatthew &rx->rx_ag_ring, cp->ring.phys_id, HWRM_NA_SIGNATURE, 1) != 0) { 875765dc391Sjmatthew printf("%s: failed to set up rx ag ring\n", 876765dc391Sjmatthew DEVNAME(sc)); 877765dc391Sjmatthew goto dealloc_rx; 878765dc391Sjmatthew } 879765dc391Sjmatthew bnxt_write_rx_doorbell(sc, &rx->rx_ag_ring, 0); 880765dc391Sjmatthew 881765dc391Sjmatthew rg->grp_id = HWRM_NA_SIGNATURE; 882765dc391Sjmatthew rg->stats_ctx = cp->stats_ctx_id; 883765dc391Sjmatthew rg->rx_ring_id = rx->rx_ring.phys_id; 884765dc391Sjmatthew rg->ag_ring_id = rx->rx_ag_ring.phys_id; 885765dc391Sjmatthew rg->cp_ring_id = cp->ring.phys_id; 886765dc391Sjmatthew if (bnxt_hwrm_ring_grp_alloc(sc, rg) != 0) { 887765dc391Sjmatthew printf("%s: failed to allocate ring group\n", 888765dc391Sjmatthew DEVNAME(sc)); 889765dc391Sjmatthew goto dealloc_ag; 890765dc391Sjmatthew } 891765dc391Sjmatthew 892765dc391Sjmatthew rx->rx_slots = mallocarray(sizeof(*bs), rx->rx_ring.ring_size, 893765dc391Sjmatthew M_DEVBUF, M_WAITOK | M_ZERO); 894765dc391Sjmatthew if (rx->rx_slots == NULL) { 895765dc391Sjmatthew printf("%s: failed to allocate rx slots\n", DEVNAME(sc)); 896765dc391Sjmatthew goto dealloc_ring_group; 897765dc391Sjmatthew } 898765dc391Sjmatthew 899765dc391Sjmatthew for (i = 0; i < rx->rx_ring.ring_size; i++) { 900765dc391Sjmatthew bs = &rx->rx_slots[i]; 901765dc391Sjmatthew if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, 902765dc391Sjmatthew BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bs->bs_map) != 0) { 903765dc391Sjmatthew printf("%s: failed to allocate rx dma maps\n", 904765dc391Sjmatthew DEVNAME(sc)); 905765dc391Sjmatthew goto destroy_rx_slots; 906765dc391Sjmatthew } 907765dc391Sjmatthew } 908765dc391Sjmatthew 909765dc391Sjmatthew rx->rx_ag_slots = mallocarray(sizeof(*bs), rx->rx_ag_ring.ring_size, 910765dc391Sjmatthew M_DEVBUF, M_WAITOK | M_ZERO); 911765dc391Sjmatthew if (rx->rx_ag_slots == NULL) { 912765dc391Sjmatthew printf("%s: failed to allocate rx ag slots\n", DEVNAME(sc)); 913765dc391Sjmatthew goto destroy_rx_slots; 914765dc391Sjmatthew } 915765dc391Sjmatthew 916765dc391Sjmatthew for (i = 0; i < rx->rx_ag_ring.ring_size; i++) { 917765dc391Sjmatthew bs = &rx->rx_ag_slots[i]; 918765dc391Sjmatthew if (bus_dmamap_create(sc->sc_dmat, BNXT_AG_BUFFER_SIZE, 1, 919765dc391Sjmatthew BNXT_AG_BUFFER_SIZE, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 920765dc391Sjmatthew &bs->bs_map) != 0) { 921765dc391Sjmatthew printf("%s: failed to allocate rx ag dma maps\n", 922765dc391Sjmatthew DEVNAME(sc)); 923765dc391Sjmatthew goto destroy_rx_ag_slots; 924765dc391Sjmatthew } 925765dc391Sjmatthew } 926765dc391Sjmatthew 927765dc391Sjmatthew tx->tx_slots = mallocarray(sizeof(*bs), tx->tx_ring.ring_size, 928765dc391Sjmatthew M_DEVBUF, M_WAITOK | M_ZERO); 929765dc391Sjmatthew if (tx->tx_slots == NULL) { 930765dc391Sjmatthew printf("%s: failed to allocate tx slots\n", DEVNAME(sc)); 931765dc391Sjmatthew goto destroy_rx_ag_slots; 932765dc391Sjmatthew } 933765dc391Sjmatthew 934765dc391Sjmatthew for (i = 0; i < tx->tx_ring.ring_size; i++) { 935765dc391Sjmatthew bs = &tx->tx_slots[i]; 9368a756155Sjmatthew if (bus_dmamap_create(sc->sc_dmat, MAXMCLBYTES, BNXT_MAX_TX_SEGS, 937765dc391Sjmatthew BNXT_MAX_MTU, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 938765dc391Sjmatthew &bs->bs_map) != 0) { 939765dc391Sjmatthew printf("%s: failed to allocate tx dma maps\n", 940765dc391Sjmatthew DEVNAME(sc)); 941765dc391Sjmatthew goto destroy_tx_slots; 942765dc391Sjmatthew } 943765dc391Sjmatthew } 944765dc391Sjmatthew 945765dc391Sjmatthew /* 946765dc391Sjmatthew * initially, the rx ring must be filled at least some distance beyond 947765dc391Sjmatthew * the current consumer index, as it looks like the firmware assumes the 948765dc391Sjmatthew * ring is full on creation, but doesn't prefetch the whole thing. 949765dc391Sjmatthew * once the whole ring has been used once, we should be able to back off 950765dc391Sjmatthew * to 2 or so slots, but we currently don't have a way of doing that. 951765dc391Sjmatthew */ 952765dc391Sjmatthew if_rxr_init(&rx->rxr[0], 32, rx->rx_ring.ring_size - 1); 953765dc391Sjmatthew if_rxr_init(&rx->rxr[1], 32, rx->rx_ag_ring.ring_size - 1); 954765dc391Sjmatthew rx->rx_prod = 0; 955765dc391Sjmatthew rx->rx_cons = 0; 956765dc391Sjmatthew rx->rx_ag_prod = 0; 957765dc391Sjmatthew rx->rx_ag_cons = 0; 958765dc391Sjmatthew bnxt_rx_fill(bq); 959*2783188aSjmatthew bnxt_rx_fill_ag(bq); 960765dc391Sjmatthew 961765dc391Sjmatthew tx->tx_cons = 0; 962765dc391Sjmatthew tx->tx_prod = 0; 963765dc391Sjmatthew tx->tx_ring_cons = 0; 964765dc391Sjmatthew tx->tx_ring_prod = 0; 965765dc391Sjmatthew ifq_clr_oactive(ifp->if_ifqs[bq->q_index]); 966765dc391Sjmatthew ifq_restart(ifp->if_ifqs[bq->q_index]); 967765dc391Sjmatthew return 0; 968765dc391Sjmatthew 969765dc391Sjmatthew destroy_tx_slots: 970765dc391Sjmatthew bnxt_free_slots(sc, tx->tx_slots, i, tx->tx_ring.ring_size); 971765dc391Sjmatthew tx->tx_slots = NULL; 972765dc391Sjmatthew 973765dc391Sjmatthew i = rx->rx_ag_ring.ring_size; 974765dc391Sjmatthew destroy_rx_ag_slots: 975765dc391Sjmatthew bnxt_free_slots(sc, rx->rx_ag_slots, i, rx->rx_ag_ring.ring_size); 976765dc391Sjmatthew rx->rx_ag_slots = NULL; 977765dc391Sjmatthew 978765dc391Sjmatthew i = rx->rx_ring.ring_size; 979765dc391Sjmatthew destroy_rx_slots: 980765dc391Sjmatthew bnxt_free_slots(sc, rx->rx_slots, i, rx->rx_ring.ring_size); 981765dc391Sjmatthew rx->rx_slots = NULL; 982765dc391Sjmatthew dealloc_ring_group: 983765dc391Sjmatthew bnxt_hwrm_ring_grp_free(sc, &bq->q_rg); 984765dc391Sjmatthew dealloc_ag: 985765dc391Sjmatthew bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX, 986765dc391Sjmatthew &rx->rx_ag_ring); 987765dc391Sjmatthew dealloc_tx: 988765dc391Sjmatthew bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_TX, 989765dc391Sjmatthew &tx->tx_ring); 990765dc391Sjmatthew dealloc_rx: 991765dc391Sjmatthew bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX, 992765dc391Sjmatthew &rx->rx_ring); 993765dc391Sjmatthew dealloc_stats: 994765dc391Sjmatthew bnxt_hwrm_stat_ctx_free(sc, cp); 995765dc391Sjmatthew free_rx: 996765dc391Sjmatthew bnxt_dmamem_free(sc, rx->rx_ring_mem); 997765dc391Sjmatthew rx->rx_ring_mem = NULL; 998765dc391Sjmatthew free_tx: 999765dc391Sjmatthew bnxt_dmamem_free(sc, tx->tx_ring_mem); 1000765dc391Sjmatthew tx->tx_ring_mem = NULL; 1001765dc391Sjmatthew return ENOMEM; 1002765dc391Sjmatthew } 1003765dc391Sjmatthew 1004765dc391Sjmatthew void 1005765dc391Sjmatthew bnxt_queue_down(struct bnxt_softc *sc, struct bnxt_queue *bq) 1006765dc391Sjmatthew { 1007765dc391Sjmatthew struct bnxt_cp_ring *cp = &bq->q_cp; 1008765dc391Sjmatthew struct bnxt_rx_queue *rx = &bq->q_rx; 1009765dc391Sjmatthew struct bnxt_tx_queue *tx = &bq->q_tx; 1010765dc391Sjmatthew 1011765dc391Sjmatthew bnxt_free_slots(sc, tx->tx_slots, tx->tx_ring.ring_size, 1012765dc391Sjmatthew tx->tx_ring.ring_size); 1013765dc391Sjmatthew tx->tx_slots = NULL; 1014765dc391Sjmatthew 1015765dc391Sjmatthew bnxt_free_slots(sc, rx->rx_ag_slots, rx->rx_ag_ring.ring_size, 1016765dc391Sjmatthew rx->rx_ag_ring.ring_size); 1017765dc391Sjmatthew rx->rx_ag_slots = NULL; 1018765dc391Sjmatthew 1019765dc391Sjmatthew bnxt_free_slots(sc, rx->rx_slots, rx->rx_ring.ring_size, 1020765dc391Sjmatthew rx->rx_ring.ring_size); 1021765dc391Sjmatthew rx->rx_slots = NULL; 1022765dc391Sjmatthew 1023765dc391Sjmatthew bnxt_hwrm_ring_grp_free(sc, &bq->q_rg); 1024765dc391Sjmatthew bnxt_hwrm_stat_ctx_free(sc, &bq->q_cp); 1025765dc391Sjmatthew 1026765dc391Sjmatthew /* may need to wait for 500ms here before we can free the rings */ 1027765dc391Sjmatthew 1028765dc391Sjmatthew bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_TX, 1029765dc391Sjmatthew &tx->tx_ring); 1030765dc391Sjmatthew bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX, 1031765dc391Sjmatthew &rx->rx_ag_ring); 1032765dc391Sjmatthew bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_RX, 1033765dc391Sjmatthew &rx->rx_ring); 1034b59ce775Sjmatthew 1035e9c3085bSjmatthew /* if no intrmap, leave cp ring in place for async events */ 1036e9c3085bSjmatthew if (sc->sc_intrmap != NULL) { 1037765dc391Sjmatthew bnxt_hwrm_ring_free(sc, HWRM_RING_ALLOC_INPUT_RING_TYPE_L2_CMPL, 1038765dc391Sjmatthew &cp->ring); 1039765dc391Sjmatthew 1040b59ce775Sjmatthew bnxt_dmamem_free(sc, cp->ring_mem); 1041b59ce775Sjmatthew cp->ring_mem = NULL; 1042b59ce775Sjmatthew } 1043b59ce775Sjmatthew 1044765dc391Sjmatthew bnxt_dmamem_free(sc, rx->rx_ring_mem); 1045765dc391Sjmatthew rx->rx_ring_mem = NULL; 1046765dc391Sjmatthew 1047765dc391Sjmatthew bnxt_dmamem_free(sc, tx->tx_ring_mem); 1048765dc391Sjmatthew tx->tx_ring_mem = NULL; 1049765dc391Sjmatthew } 1050765dc391Sjmatthew 1051a7c0060aSjmatthew void 1052a7c0060aSjmatthew bnxt_up(struct bnxt_softc *sc) 1053a7c0060aSjmatthew { 1054a7c0060aSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 1055a7c0060aSjmatthew int i; 1056a7c0060aSjmatthew 1057a7c0060aSjmatthew sc->sc_stats_ctx_mem = bnxt_dmamem_alloc(sc, 1058765dc391Sjmatthew sizeof(struct ctx_hw_stats) * sc->sc_nqueues); 1059a7c0060aSjmatthew if (sc->sc_stats_ctx_mem == NULL) { 1060a7c0060aSjmatthew printf("%s: failed to allocate stats contexts\n", DEVNAME(sc)); 1061a7c0060aSjmatthew return; 1062a7c0060aSjmatthew } 1063a7c0060aSjmatthew 1064d160d8f0Sjmatthew sc->sc_rx_cfg = bnxt_dmamem_alloc(sc, PAGE_SIZE * 2); 1065d160d8f0Sjmatthew if (sc->sc_rx_cfg == NULL) { 1066d160d8f0Sjmatthew printf("%s: failed to allocate rx config buffer\n", 1067765dc391Sjmatthew DEVNAME(sc)); 1068a7c0060aSjmatthew goto free_stats; 1069a7c0060aSjmatthew } 1070a7c0060aSjmatthew 1071765dc391Sjmatthew for (i = 0; i < sc->sc_nqueues; i++) { 1072765dc391Sjmatthew if (bnxt_queue_up(sc, &sc->sc_queues[i]) != 0) { 1073765dc391Sjmatthew goto down_queues; 1074a7c0060aSjmatthew } 1075a7c0060aSjmatthew } 1076a7c0060aSjmatthew 10777a844086Sjmatthew sc->sc_vnic.rss_id = (uint16_t)HWRM_NA_SIGNATURE; 1078a7c0060aSjmatthew if (bnxt_hwrm_vnic_ctx_alloc(sc, &sc->sc_vnic.rss_id) != 0) { 1079a7c0060aSjmatthew printf("%s: failed to allocate vnic rss context\n", 1080a7c0060aSjmatthew DEVNAME(sc)); 10819a5ce850Sjmatthew goto down_all_queues; 1082a7c0060aSjmatthew } 1083a7c0060aSjmatthew 10847a844086Sjmatthew sc->sc_vnic.id = (uint16_t)HWRM_NA_SIGNATURE; 1085765dc391Sjmatthew sc->sc_vnic.def_ring_grp = sc->sc_queues[0].q_rg.grp_id; 1086c4f53494Sjmatthew sc->sc_vnic.mru = BNXT_MAX_MTU; 1087a7c0060aSjmatthew sc->sc_vnic.cos_rule = (uint16_t)HWRM_NA_SIGNATURE; 1088a7c0060aSjmatthew sc->sc_vnic.lb_rule = (uint16_t)HWRM_NA_SIGNATURE; 1089870f5687Sjmatthew sc->sc_vnic.flags = BNXT_VNIC_FLAG_DEFAULT | 1090870f5687Sjmatthew BNXT_VNIC_FLAG_VLAN_STRIP; 1091a7c0060aSjmatthew if (bnxt_hwrm_vnic_alloc(sc, &sc->sc_vnic) != 0) { 1092a7c0060aSjmatthew printf("%s: failed to allocate vnic\n", DEVNAME(sc)); 1093a7c0060aSjmatthew goto dealloc_vnic_ctx; 1094a7c0060aSjmatthew } 1095a7c0060aSjmatthew 1096a7c0060aSjmatthew if (bnxt_hwrm_vnic_cfg(sc, &sc->sc_vnic) != 0) { 1097a7c0060aSjmatthew printf("%s: failed to configure vnic\n", DEVNAME(sc)); 1098a7c0060aSjmatthew goto dealloc_vnic; 1099a7c0060aSjmatthew } 1100a7c0060aSjmatthew 1101c4f53494Sjmatthew if (bnxt_hwrm_vnic_cfg_placement(sc, &sc->sc_vnic) != 0) { 1102c4f53494Sjmatthew printf("%s: failed to configure vnic placement mode\n", 1103c4f53494Sjmatthew DEVNAME(sc)); 1104c4f53494Sjmatthew goto dealloc_vnic; 1105c4f53494Sjmatthew } 1106c4f53494Sjmatthew 1107a7c0060aSjmatthew sc->sc_vnic.filter_id = -1; 1108a7c0060aSjmatthew if (bnxt_hwrm_set_filter(sc, &sc->sc_vnic) != 0) { 1109a7c0060aSjmatthew printf("%s: failed to set vnic filter\n", DEVNAME(sc)); 1110a7c0060aSjmatthew goto dealloc_vnic; 1111a7c0060aSjmatthew } 1112a7c0060aSjmatthew 1113d160d8f0Sjmatthew if (sc->sc_nqueues > 1) { 1114d160d8f0Sjmatthew uint16_t *rss_table = (BNXT_DMA_KVA(sc->sc_rx_cfg) + PAGE_SIZE); 1115d160d8f0Sjmatthew uint8_t *hash_key = (uint8_t *)(rss_table + HW_HASH_INDEX_SIZE); 1116d160d8f0Sjmatthew 1117d160d8f0Sjmatthew for (i = 0; i < HW_HASH_INDEX_SIZE; i++) { 1118d160d8f0Sjmatthew struct bnxt_queue *bq; 1119d160d8f0Sjmatthew 1120d160d8f0Sjmatthew bq = &sc->sc_queues[i % sc->sc_nqueues]; 1121d160d8f0Sjmatthew rss_table[i] = htole16(bq->q_rg.grp_id); 1122d160d8f0Sjmatthew } 1123d160d8f0Sjmatthew stoeplitz_to_key(hash_key, HW_HASH_KEY_SIZE); 1124d160d8f0Sjmatthew 1125d160d8f0Sjmatthew if (bnxt_hwrm_vnic_rss_cfg(sc, &sc->sc_vnic, 1126d160d8f0Sjmatthew HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_IPV4 | 1127d160d8f0Sjmatthew HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_TCP_IPV4 | 1128d160d8f0Sjmatthew HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_IPV6 | 1129d160d8f0Sjmatthew HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_TCP_IPV6, 1130d160d8f0Sjmatthew BNXT_DMA_DVA(sc->sc_rx_cfg) + PAGE_SIZE, 1131d160d8f0Sjmatthew BNXT_DMA_DVA(sc->sc_rx_cfg) + PAGE_SIZE + 1132d160d8f0Sjmatthew (HW_HASH_INDEX_SIZE * sizeof(uint16_t))) != 0) { 1133d160d8f0Sjmatthew printf("%s: failed to set RSS config\n", DEVNAME(sc)); 1134d160d8f0Sjmatthew goto dealloc_vnic; 1135d160d8f0Sjmatthew } 1136d160d8f0Sjmatthew } 1137d160d8f0Sjmatthew 1138a7c0060aSjmatthew bnxt_iff(sc); 1139a7c0060aSjmatthew SET(ifp->if_flags, IFF_RUNNING); 1140a7c0060aSjmatthew 1141a7c0060aSjmatthew return; 1142a7c0060aSjmatthew 1143a7c0060aSjmatthew dealloc_vnic: 1144a7c0060aSjmatthew bnxt_hwrm_vnic_free(sc, &sc->sc_vnic); 1145a7c0060aSjmatthew dealloc_vnic_ctx: 1146a7c0060aSjmatthew bnxt_hwrm_vnic_ctx_free(sc, &sc->sc_vnic.rss_id); 11479a5ce850Sjmatthew 11489a5ce850Sjmatthew down_all_queues: 11499a5ce850Sjmatthew i = sc->sc_nqueues; 1150765dc391Sjmatthew down_queues: 11519a5ce850Sjmatthew while (i-- > 0) 1152765dc391Sjmatthew bnxt_queue_down(sc, &sc->sc_queues[i]); 1153765dc391Sjmatthew 1154d160d8f0Sjmatthew bnxt_dmamem_free(sc, sc->sc_rx_cfg); 1155d160d8f0Sjmatthew sc->sc_rx_cfg = NULL; 1156a7c0060aSjmatthew free_stats: 1157a7c0060aSjmatthew bnxt_dmamem_free(sc, sc->sc_stats_ctx_mem); 1158a7c0060aSjmatthew sc->sc_stats_ctx_mem = NULL; 1159a7c0060aSjmatthew } 1160a7c0060aSjmatthew 1161a7c0060aSjmatthew void 1162a7c0060aSjmatthew bnxt_down(struct bnxt_softc *sc) 1163a7c0060aSjmatthew { 1164a7c0060aSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 1165765dc391Sjmatthew int i; 1166a7c0060aSjmatthew 1167a7c0060aSjmatthew CLR(ifp->if_flags, IFF_RUNNING); 1168a7c0060aSjmatthew 11692bbed9a6Sjmatthew intr_barrier(sc->sc_ih); 11702bbed9a6Sjmatthew 1171765dc391Sjmatthew for (i = 0; i < sc->sc_nqueues; i++) { 1172765dc391Sjmatthew ifq_clr_oactive(ifp->if_ifqs[i]); 1173765dc391Sjmatthew ifq_barrier(ifp->if_ifqs[i]); 1174a7c0060aSjmatthew 11752bbed9a6Sjmatthew timeout_del_barrier(&sc->sc_queues[i].q_rx.rx_refill); 11762bbed9a6Sjmatthew 11772bbed9a6Sjmatthew if (sc->sc_intrmap != NULL) 11782bbed9a6Sjmatthew intr_barrier(sc->sc_queues[i].q_ihc); 1179765dc391Sjmatthew } 1180a7c0060aSjmatthew 1181a7c0060aSjmatthew bnxt_hwrm_free_filter(sc, &sc->sc_vnic); 1182a7c0060aSjmatthew bnxt_hwrm_vnic_free(sc, &sc->sc_vnic); 1183a7c0060aSjmatthew bnxt_hwrm_vnic_ctx_free(sc, &sc->sc_vnic.rss_id); 1184a7c0060aSjmatthew 1185765dc391Sjmatthew for (i = 0; i < sc->sc_nqueues; i++) 1186765dc391Sjmatthew bnxt_queue_down(sc, &sc->sc_queues[i]); 1187a7c0060aSjmatthew 1188d160d8f0Sjmatthew bnxt_dmamem_free(sc, sc->sc_rx_cfg); 1189d160d8f0Sjmatthew sc->sc_rx_cfg = NULL; 1190b12ece3dSjmatthew 1191a7c0060aSjmatthew bnxt_dmamem_free(sc, sc->sc_stats_ctx_mem); 1192a7c0060aSjmatthew sc->sc_stats_ctx_mem = NULL; 1193a7c0060aSjmatthew } 1194a7c0060aSjmatthew 1195a7c0060aSjmatthew void 1196a7c0060aSjmatthew bnxt_iff(struct bnxt_softc *sc) 1197a7c0060aSjmatthew { 1198a7c0060aSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 1199b12ece3dSjmatthew struct ether_multi *enm; 1200b12ece3dSjmatthew struct ether_multistep step; 1201b12ece3dSjmatthew char *mc_list; 1202b12ece3dSjmatthew uint32_t rx_mask, mc_count; 1203a7c0060aSjmatthew 1204b12ece3dSjmatthew rx_mask = HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_BCAST 1205b12ece3dSjmatthew | HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_MCAST 1206b12ece3dSjmatthew | HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ANYVLAN_NONVLAN; 1207a7c0060aSjmatthew 1208d160d8f0Sjmatthew mc_list = BNXT_DMA_KVA(sc->sc_rx_cfg); 1209b12ece3dSjmatthew mc_count = 0; 1210a7c0060aSjmatthew 1211b12ece3dSjmatthew if (ifp->if_flags & IFF_PROMISC) { 1212b12ece3dSjmatthew SET(ifp->if_flags, IFF_ALLMULTI); 1213b12ece3dSjmatthew rx_mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_PROMISCUOUS; 1214b12ece3dSjmatthew } else if ((sc->sc_ac.ac_multirangecnt > 0) || 1215b12ece3dSjmatthew (sc->sc_ac.ac_multicnt > (PAGE_SIZE / ETHER_ADDR_LEN))) { 1216b12ece3dSjmatthew SET(ifp->if_flags, IFF_ALLMULTI); 1217b12ece3dSjmatthew rx_mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ALL_MCAST; 1218b12ece3dSjmatthew } else { 1219b12ece3dSjmatthew CLR(ifp->if_flags, IFF_ALLMULTI); 1220b12ece3dSjmatthew ETHER_FIRST_MULTI(step, &sc->sc_ac, enm); 1221b12ece3dSjmatthew while (enm != NULL) { 1222b12ece3dSjmatthew memcpy(mc_list, enm->enm_addrlo, ETHER_ADDR_LEN); 1223b12ece3dSjmatthew mc_list += ETHER_ADDR_LEN; 1224b12ece3dSjmatthew mc_count++; 1225b12ece3dSjmatthew 1226b12ece3dSjmatthew ETHER_NEXT_MULTI(step, enm); 1227b12ece3dSjmatthew } 1228b12ece3dSjmatthew } 1229b12ece3dSjmatthew 1230b12ece3dSjmatthew bnxt_hwrm_cfa_l2_set_rx_mask(sc, sc->sc_vnic.id, rx_mask, 1231d160d8f0Sjmatthew BNXT_DMA_DVA(sc->sc_rx_cfg), mc_count); 1232a7c0060aSjmatthew } 1233a7c0060aSjmatthew 1234a7c0060aSjmatthew int 1235a7c0060aSjmatthew bnxt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1236a7c0060aSjmatthew { 1237a7c0060aSjmatthew struct bnxt_softc *sc = (struct bnxt_softc *)ifp->if_softc; 1238a7c0060aSjmatthew struct ifreq *ifr = (struct ifreq *)data; 1239a7c0060aSjmatthew int s, error = 0; 1240a7c0060aSjmatthew 1241a7c0060aSjmatthew s = splnet(); 1242a7c0060aSjmatthew switch (cmd) { 1243a7c0060aSjmatthew case SIOCSIFADDR: 1244a7c0060aSjmatthew ifp->if_flags |= IFF_UP; 1245a7c0060aSjmatthew /* FALLTHROUGH */ 1246a7c0060aSjmatthew 1247a7c0060aSjmatthew case SIOCSIFFLAGS: 1248a7c0060aSjmatthew if (ISSET(ifp->if_flags, IFF_UP)) { 1249a7c0060aSjmatthew if (ISSET(ifp->if_flags, IFF_RUNNING)) 1250a7c0060aSjmatthew error = ENETRESET; 1251a7c0060aSjmatthew else 1252a7c0060aSjmatthew bnxt_up(sc); 1253a7c0060aSjmatthew } else { 1254a7c0060aSjmatthew if (ISSET(ifp->if_flags, IFF_RUNNING)) 1255a7c0060aSjmatthew bnxt_down(sc); 1256a7c0060aSjmatthew } 1257a7c0060aSjmatthew break; 1258a7c0060aSjmatthew 1259a7c0060aSjmatthew case SIOCGIFMEDIA: 1260a7c0060aSjmatthew case SIOCSIFMEDIA: 1261a7c0060aSjmatthew error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 1262a7c0060aSjmatthew break; 1263a7c0060aSjmatthew 1264a7c0060aSjmatthew case SIOCGIFRXR: 1265a7c0060aSjmatthew error = bnxt_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data); 1266a7c0060aSjmatthew break; 1267a7c0060aSjmatthew 126840247284Sjmatthew case SIOCGIFSFFPAGE: 126940247284Sjmatthew error = bnxt_get_sffpage(sc, (struct if_sffpage *)data); 127040247284Sjmatthew break; 127140247284Sjmatthew 1272a7c0060aSjmatthew default: 1273a7c0060aSjmatthew error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 1274a7c0060aSjmatthew } 1275a7c0060aSjmatthew 1276a7c0060aSjmatthew if (error == ENETRESET) { 1277a7c0060aSjmatthew if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 1278a7c0060aSjmatthew (IFF_UP | IFF_RUNNING)) 1279a7c0060aSjmatthew bnxt_iff(sc); 1280a7c0060aSjmatthew error = 0; 1281a7c0060aSjmatthew } 1282a7c0060aSjmatthew 1283a7c0060aSjmatthew splx(s); 1284a7c0060aSjmatthew 1285a7c0060aSjmatthew return (error); 1286a7c0060aSjmatthew } 1287a7c0060aSjmatthew 1288a7c0060aSjmatthew int 1289a7c0060aSjmatthew bnxt_rxrinfo(struct bnxt_softc *sc, struct if_rxrinfo *ifri) 1290a7c0060aSjmatthew { 1291765dc391Sjmatthew struct if_rxring_info *ifr; 1292765dc391Sjmatthew int i; 1293765dc391Sjmatthew int error; 1294a7c0060aSjmatthew 1295765dc391Sjmatthew ifr = mallocarray(sc->sc_nqueues * 2, sizeof(*ifr), M_TEMP, 1296765dc391Sjmatthew M_WAITOK | M_ZERO | M_CANFAIL); 1297765dc391Sjmatthew if (ifr == NULL) 1298765dc391Sjmatthew return (ENOMEM); 1299a7c0060aSjmatthew 1300765dc391Sjmatthew for (i = 0; i < sc->sc_nqueues; i++) { 1301765dc391Sjmatthew ifr[(i * 2)].ifr_size = MCLBYTES; 1302765dc391Sjmatthew ifr[(i * 2)].ifr_info = sc->sc_queues[i].q_rx.rxr[0]; 1303c4f53494Sjmatthew 1304765dc391Sjmatthew ifr[(i * 2) + 1].ifr_size = BNXT_AG_BUFFER_SIZE; 1305765dc391Sjmatthew ifr[(i * 2) + 1].ifr_info = sc->sc_queues[i].q_rx.rxr[1]; 1306765dc391Sjmatthew } 1307765dc391Sjmatthew 1308765dc391Sjmatthew error = if_rxr_info_ioctl(ifri, sc->sc_nqueues * 2, ifr); 1309765dc391Sjmatthew free(ifr, M_TEMP, sc->sc_nqueues * 2 * sizeof(*ifr)); 1310765dc391Sjmatthew 1311765dc391Sjmatthew return (error); 1312a7c0060aSjmatthew } 1313a7c0060aSjmatthew 1314a7c0060aSjmatthew int 1315a7c0060aSjmatthew bnxt_load_mbuf(struct bnxt_softc *sc, struct bnxt_slot *bs, struct mbuf *m) 1316a7c0060aSjmatthew { 1317a7c0060aSjmatthew switch (bus_dmamap_load_mbuf(sc->sc_dmat, bs->bs_map, m, 1318a7c0060aSjmatthew BUS_DMA_STREAMING | BUS_DMA_NOWAIT)) { 1319a7c0060aSjmatthew case 0: 1320a7c0060aSjmatthew break; 1321a7c0060aSjmatthew 1322a7c0060aSjmatthew case EFBIG: 1323a7c0060aSjmatthew if (m_defrag(m, M_DONTWAIT) == 0 && 1324a7c0060aSjmatthew bus_dmamap_load_mbuf(sc->sc_dmat, bs->bs_map, m, 1325a7c0060aSjmatthew BUS_DMA_STREAMING | BUS_DMA_NOWAIT) == 0) 1326a7c0060aSjmatthew break; 1327a7c0060aSjmatthew 1328a7c0060aSjmatthew default: 1329a7c0060aSjmatthew return (1); 1330a7c0060aSjmatthew } 1331a7c0060aSjmatthew 1332a7c0060aSjmatthew bs->bs_m = m; 1333a7c0060aSjmatthew return (0); 1334a7c0060aSjmatthew } 1335a7c0060aSjmatthew 1336a7c0060aSjmatthew void 1337a7c0060aSjmatthew bnxt_start(struct ifqueue *ifq) 1338a7c0060aSjmatthew { 1339a7c0060aSjmatthew struct ifnet *ifp = ifq->ifq_if; 1340a7c0060aSjmatthew struct tx_bd_short *txring; 1341af7e9c1bSjmatthew struct tx_bd_long_hi *txhi; 1342765dc391Sjmatthew struct bnxt_tx_queue *tx = ifq->ifq_softc; 1343765dc391Sjmatthew struct bnxt_softc *sc = tx->tx_softc; 1344a7c0060aSjmatthew struct bnxt_slot *bs; 13458a756155Sjmatthew struct ether_extracted ext; 1346a7c0060aSjmatthew bus_dmamap_t map; 1347a7c0060aSjmatthew struct mbuf *m; 1348058d3950Sjmatthew u_int idx, free, used, laststart; 13498a756155Sjmatthew uint16_t txflags, lflags; 13508a756155Sjmatthew int i, slen; 1351a7c0060aSjmatthew 1352765dc391Sjmatthew txring = (struct tx_bd_short *)BNXT_DMA_KVA(tx->tx_ring_mem); 1353a7c0060aSjmatthew 1354765dc391Sjmatthew idx = tx->tx_ring_prod; 1355765dc391Sjmatthew free = tx->tx_ring_cons; 1356a7c0060aSjmatthew if (free <= idx) 1357765dc391Sjmatthew free += tx->tx_ring.ring_size; 1358a7c0060aSjmatthew free -= idx; 1359a7c0060aSjmatthew 1360a7c0060aSjmatthew used = 0; 1361a7c0060aSjmatthew 1362a7c0060aSjmatthew for (;;) { 1363af7e9c1bSjmatthew /* +1 for tx_bd_long_hi */ 1364af7e9c1bSjmatthew if (used + BNXT_MAX_TX_SEGS + 1 > free) { 1365a7c0060aSjmatthew ifq_set_oactive(ifq); 1366a7c0060aSjmatthew break; 1367a7c0060aSjmatthew } 1368a7c0060aSjmatthew 1369a7c0060aSjmatthew m = ifq_dequeue(ifq); 1370a7c0060aSjmatthew if (m == NULL) 1371a7c0060aSjmatthew break; 1372a7c0060aSjmatthew 1373765dc391Sjmatthew bs = &tx->tx_slots[tx->tx_prod]; 1374a7c0060aSjmatthew if (bnxt_load_mbuf(sc, bs, m) != 0) { 1375a7c0060aSjmatthew m_freem(m); 1376a7c0060aSjmatthew ifp->if_oerrors++; 1377a7c0060aSjmatthew continue; 1378a7c0060aSjmatthew } 1379a7c0060aSjmatthew 1380a7c0060aSjmatthew #if NBPFILTER > 0 1381a7c0060aSjmatthew if (ifp->if_bpf) 1382a7c0060aSjmatthew bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 1383a7c0060aSjmatthew #endif 1384a7c0060aSjmatthew map = bs->bs_map; 1385a7c0060aSjmatthew bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1386a7c0060aSjmatthew BUS_DMASYNC_PREWRITE); 1387af7e9c1bSjmatthew used += BNXT_TX_SLOTS(bs); 1388af7e9c1bSjmatthew 1389af7e9c1bSjmatthew /* first segment */ 1390af7e9c1bSjmatthew laststart = idx; 1391af7e9c1bSjmatthew txring[idx].len = htole16(map->dm_segs[0].ds_len); 1392765dc391Sjmatthew txring[idx].opaque = tx->tx_prod; 1393af7e9c1bSjmatthew txring[idx].addr = htole64(map->dm_segs[0].ds_addr); 13948a756155Sjmatthew if (m->m_pkthdr.csum_flags & M_TCP_TSO) 13958a756155Sjmatthew slen = m->m_pkthdr.ph_mss; 13968a756155Sjmatthew else 13978a756155Sjmatthew slen = map->dm_mapsize; 1398a7c0060aSjmatthew 13998a756155Sjmatthew if (slen < 512) 1400af7e9c1bSjmatthew txflags = TX_BD_LONG_FLAGS_LHINT_LT512; 14018a756155Sjmatthew else if (slen < 1024) 1402af7e9c1bSjmatthew txflags = TX_BD_LONG_FLAGS_LHINT_LT1K; 14038a756155Sjmatthew else if (slen < 2048) 1404af7e9c1bSjmatthew txflags = TX_BD_LONG_FLAGS_LHINT_LT2K; 1405a7c0060aSjmatthew else 1406af7e9c1bSjmatthew txflags = TX_BD_LONG_FLAGS_LHINT_GTE2K; 1407af7e9c1bSjmatthew txflags |= TX_BD_LONG_TYPE_TX_BD_LONG | 14088490bd92Sjmatthew TX_BD_LONG_FLAGS_NO_CMPL; 14098490bd92Sjmatthew txflags |= (BNXT_TX_SLOTS(bs) << TX_BD_LONG_FLAGS_BD_CNT_SFT) & 14108490bd92Sjmatthew TX_BD_LONG_FLAGS_BD_CNT_MASK; 1411af7e9c1bSjmatthew if (map->dm_nsegs == 1) 1412af7e9c1bSjmatthew txflags |= TX_BD_SHORT_FLAGS_PACKET_END; 1413a7c0060aSjmatthew txring[idx].flags_type = htole16(txflags); 1414af7e9c1bSjmatthew 1415af7e9c1bSjmatthew idx++; 1416765dc391Sjmatthew if (idx == tx->tx_ring.ring_size) 1417af7e9c1bSjmatthew idx = 0; 1418af7e9c1bSjmatthew 1419af7e9c1bSjmatthew /* long tx descriptor */ 1420af7e9c1bSjmatthew txhi = (struct tx_bd_long_hi *)&txring[idx]; 1421af7e9c1bSjmatthew memset(txhi, 0, sizeof(*txhi)); 14228a756155Sjmatthew 14238a756155Sjmatthew lflags = 0; 14248a756155Sjmatthew if (m->m_pkthdr.csum_flags & M_TCP_TSO) { 14258a756155Sjmatthew uint16_t hdrsize; 14268a756155Sjmatthew uint32_t outlen; 14278a756155Sjmatthew uint32_t paylen; 14288a756155Sjmatthew 14298a756155Sjmatthew ether_extract_headers(m, &ext); 14307f8ccd64Sjan if (ext.tcp && m->m_pkthdr.ph_mss > 0) { 14318a756155Sjmatthew lflags |= TX_BD_LONG_LFLAGS_LSO; 14328a756155Sjmatthew hdrsize = sizeof(*ext.eh); 1433ac5f541aSbluhm if (ext.ip4 || ext.ip6) 1434ac5f541aSbluhm hdrsize += ext.iphlen; 14358a756155Sjmatthew else 14368a756155Sjmatthew tcpstat_inc(tcps_outbadtso); 14378a756155Sjmatthew 1438e78a66e5Sbluhm hdrsize += ext.tcphlen; 14398a756155Sjmatthew txhi->hdr_size = htole16(hdrsize / 2); 14408a756155Sjmatthew 14418a756155Sjmatthew outlen = m->m_pkthdr.ph_mss; 14428a756155Sjmatthew txhi->mss = htole32(outlen); 14438a756155Sjmatthew 14448a756155Sjmatthew paylen = m->m_pkthdr.len - hdrsize; 14458a756155Sjmatthew tcpstat_add(tcps_outpkttso, 14468a756155Sjmatthew (paylen + outlen + 1) / outlen); 14478a756155Sjmatthew } else { 14488a756155Sjmatthew tcpstat_inc(tcps_outbadtso); 14498a756155Sjmatthew } 14508a756155Sjmatthew } else { 14518a756155Sjmatthew if (m->m_pkthdr.csum_flags & (M_UDP_CSUM_OUT | 14528a756155Sjmatthew M_TCP_CSUM_OUT)) 14538a756155Sjmatthew lflags |= TX_BD_LONG_LFLAGS_TCP_UDP_CHKSUM; 1454af7e9c1bSjmatthew if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) 14558a756155Sjmatthew lflags |= TX_BD_LONG_LFLAGS_IP_CHKSUM; 14568a756155Sjmatthew } 14578a756155Sjmatthew txhi->lflags = htole16(lflags); 1458af7e9c1bSjmatthew 1459870f5687Sjmatthew #if NVLAN > 0 1460af7e9c1bSjmatthew if (m->m_flags & M_VLANTAG) { 1461af7e9c1bSjmatthew txhi->cfa_meta = htole32(m->m_pkthdr.ether_vtag | 1462af7e9c1bSjmatthew TX_BD_LONG_CFA_META_VLAN_TPID_TPID8100 | 1463af7e9c1bSjmatthew TX_BD_LONG_CFA_META_KEY_VLAN_TAG); 1464af7e9c1bSjmatthew } 1465870f5687Sjmatthew #endif 1466af7e9c1bSjmatthew 1467af7e9c1bSjmatthew idx++; 1468765dc391Sjmatthew if (idx == tx->tx_ring.ring_size) 1469af7e9c1bSjmatthew idx = 0; 1470af7e9c1bSjmatthew 1471af7e9c1bSjmatthew /* remaining segments */ 1472a7c0060aSjmatthew txflags = TX_BD_SHORT_TYPE_TX_BD_SHORT; 1473af7e9c1bSjmatthew for (i = 1; i < map->dm_nsegs; i++) { 1474af7e9c1bSjmatthew if (i == map->dm_nsegs - 1) 1475af7e9c1bSjmatthew txflags |= TX_BD_SHORT_FLAGS_PACKET_END; 1476af7e9c1bSjmatthew txring[idx].flags_type = htole16(txflags); 1477a7c0060aSjmatthew 1478a7c0060aSjmatthew txring[idx].len = 1479a7c0060aSjmatthew htole16(bs->bs_map->dm_segs[i].ds_len); 1480765dc391Sjmatthew txring[idx].opaque = tx->tx_prod; 1481a7c0060aSjmatthew txring[idx].addr = 1482a7c0060aSjmatthew htole64(bs->bs_map->dm_segs[i].ds_addr); 1483a7c0060aSjmatthew 1484a7c0060aSjmatthew idx++; 1485765dc391Sjmatthew if (idx == tx->tx_ring.ring_size) 1486a7c0060aSjmatthew idx = 0; 1487a7c0060aSjmatthew } 1488a7c0060aSjmatthew 1489765dc391Sjmatthew if (++tx->tx_prod >= tx->tx_ring.ring_size) 1490765dc391Sjmatthew tx->tx_prod = 0; 1491a7c0060aSjmatthew } 1492a7c0060aSjmatthew 1493058d3950Sjmatthew /* unset NO_CMPL on the first bd of the last packet */ 1494058d3950Sjmatthew if (used != 0) { 1495058d3950Sjmatthew txring[laststart].flags_type &= 1496058d3950Sjmatthew ~htole16(TX_BD_SHORT_FLAGS_NO_CMPL); 1497058d3950Sjmatthew } 1498058d3950Sjmatthew 1499765dc391Sjmatthew bnxt_write_tx_doorbell(sc, &tx->tx_ring, idx); 1500765dc391Sjmatthew tx->tx_ring_prod = idx; 1501a7c0060aSjmatthew } 1502a7c0060aSjmatthew 1503a7c0060aSjmatthew void 1504a7c0060aSjmatthew bnxt_handle_async_event(struct bnxt_softc *sc, struct cmpl_base *cmpl) 1505a7c0060aSjmatthew { 1506a7c0060aSjmatthew struct hwrm_async_event_cmpl *ae = (struct hwrm_async_event_cmpl *)cmpl; 1507a7c0060aSjmatthew uint16_t type = le16toh(ae->event_id); 1508a7c0060aSjmatthew 1509a7c0060aSjmatthew switch (type) { 1510a7c0060aSjmatthew case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE: 1511a7c0060aSjmatthew case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE: 1512a7c0060aSjmatthew case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE: 1513a7c0060aSjmatthew bnxt_hwrm_port_phy_qcfg(sc, NULL); 1514a7c0060aSjmatthew break; 1515a7c0060aSjmatthew 1516a7c0060aSjmatthew default: 1517a7c0060aSjmatthew printf("%s: unexpected async event %x\n", DEVNAME(sc), type); 1518a7c0060aSjmatthew break; 1519a7c0060aSjmatthew } 1520a7c0060aSjmatthew } 1521a7c0060aSjmatthew 1522c4f53494Sjmatthew struct cmpl_base * 1523c4f53494Sjmatthew bnxt_cpr_next_cmpl(struct bnxt_softc *sc, struct bnxt_cp_ring *cpr) 1524c4f53494Sjmatthew { 1525c4f53494Sjmatthew struct cmpl_base *cmpl; 1526c4f53494Sjmatthew uint32_t cons; 1527c4f53494Sjmatthew int v_bit; 1528c4f53494Sjmatthew 1529c4f53494Sjmatthew cons = cpr->cons + 1; 1530c4f53494Sjmatthew v_bit = cpr->v_bit; 1531c4f53494Sjmatthew if (cons == cpr->ring.ring_size) { 1532c4f53494Sjmatthew cons = 0; 1533c4f53494Sjmatthew v_bit = !v_bit; 1534c4f53494Sjmatthew } 1535c4f53494Sjmatthew cmpl = &((struct cmpl_base *)cpr->ring.vaddr)[cons]; 1536c4f53494Sjmatthew 1537c4f53494Sjmatthew if ((!!(cmpl->info3_v & htole32(CMPL_BASE_V))) != (!!v_bit)) 1538c4f53494Sjmatthew return (NULL); 1539c4f53494Sjmatthew 1540c4f53494Sjmatthew cpr->cons = cons; 1541c4f53494Sjmatthew cpr->v_bit = v_bit; 1542c4f53494Sjmatthew return (cmpl); 1543c4f53494Sjmatthew } 1544c4f53494Sjmatthew 1545c4f53494Sjmatthew void 1546c4f53494Sjmatthew bnxt_cpr_commit(struct bnxt_softc *sc, struct bnxt_cp_ring *cpr) 1547c4f53494Sjmatthew { 1548c4f53494Sjmatthew cpr->commit_cons = cpr->cons; 1549c4f53494Sjmatthew cpr->commit_v_bit = cpr->v_bit; 1550c4f53494Sjmatthew } 1551c4f53494Sjmatthew 1552c4f53494Sjmatthew void 1553c4f53494Sjmatthew bnxt_cpr_rollback(struct bnxt_softc *sc, struct bnxt_cp_ring *cpr) 1554c4f53494Sjmatthew { 1555c4f53494Sjmatthew cpr->cons = cpr->commit_cons; 1556c4f53494Sjmatthew cpr->v_bit = cpr->commit_v_bit; 1557c4f53494Sjmatthew } 1558c4f53494Sjmatthew 1559a7c0060aSjmatthew int 1560765dc391Sjmatthew bnxt_admin_intr(void *xsc) 1561a7c0060aSjmatthew { 1562a7c0060aSjmatthew struct bnxt_softc *sc = (struct bnxt_softc *)xsc; 1563a7c0060aSjmatthew struct bnxt_cp_ring *cpr = &sc->sc_cp_ring; 1564c4f53494Sjmatthew struct cmpl_base *cmpl; 1565765dc391Sjmatthew uint16_t type; 1566765dc391Sjmatthew 1567765dc391Sjmatthew bnxt_write_cp_doorbell(sc, &cpr->ring, 0); 1568765dc391Sjmatthew cmpl = bnxt_cpr_next_cmpl(sc, cpr); 1569765dc391Sjmatthew while (cmpl != NULL) { 1570765dc391Sjmatthew type = le16toh(cmpl->type) & CMPL_BASE_TYPE_MASK; 1571765dc391Sjmatthew switch (type) { 1572765dc391Sjmatthew case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT: 1573765dc391Sjmatthew bnxt_handle_async_event(sc, cmpl); 1574765dc391Sjmatthew break; 1575765dc391Sjmatthew default: 1576765dc391Sjmatthew printf("%s: unexpected completion type %u\n", 1577765dc391Sjmatthew DEVNAME(sc), type); 1578765dc391Sjmatthew } 1579765dc391Sjmatthew 1580765dc391Sjmatthew bnxt_cpr_commit(sc, cpr); 1581765dc391Sjmatthew cmpl = bnxt_cpr_next_cmpl(sc, cpr); 1582765dc391Sjmatthew } 1583765dc391Sjmatthew 1584765dc391Sjmatthew bnxt_write_cp_doorbell_index(sc, &cpr->ring, 1585765dc391Sjmatthew (cpr->commit_cons+1) % cpr->ring.ring_size, 1); 1586765dc391Sjmatthew return (1); 1587765dc391Sjmatthew } 1588765dc391Sjmatthew 1589765dc391Sjmatthew int 1590765dc391Sjmatthew bnxt_intr(void *xq) 1591765dc391Sjmatthew { 1592765dc391Sjmatthew struct bnxt_queue *q = (struct bnxt_queue *)xq; 1593765dc391Sjmatthew struct bnxt_softc *sc = q->q_sc; 159418f50744Sbluhm struct ifnet *ifp = &sc->sc_ac.ac_if; 1595765dc391Sjmatthew struct bnxt_cp_ring *cpr = &q->q_cp; 1596765dc391Sjmatthew struct bnxt_rx_queue *rx = &q->q_rx; 1597765dc391Sjmatthew struct bnxt_tx_queue *tx = &q->q_tx; 1598765dc391Sjmatthew struct cmpl_base *cmpl; 1599a7c0060aSjmatthew struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 1600a7c0060aSjmatthew uint16_t type; 1601c4f53494Sjmatthew int rxfree, txfree, agfree, rv, rollback; 1602a7c0060aSjmatthew 1603a7c0060aSjmatthew bnxt_write_cp_doorbell(sc, &cpr->ring, 0); 1604a7c0060aSjmatthew rxfree = 0; 1605a7c0060aSjmatthew txfree = 0; 1606c4f53494Sjmatthew agfree = 0; 160703373e89Sjmatthew rv = -1; 1608c4f53494Sjmatthew cmpl = bnxt_cpr_next_cmpl(sc, cpr); 1609c4f53494Sjmatthew while (cmpl != NULL) { 1610a7c0060aSjmatthew type = le16toh(cmpl->type) & CMPL_BASE_TYPE_MASK; 1611c4f53494Sjmatthew rollback = 0; 1612a7c0060aSjmatthew switch (type) { 1613a7c0060aSjmatthew case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT: 1614a7c0060aSjmatthew bnxt_handle_async_event(sc, cmpl); 1615a7c0060aSjmatthew break; 1616a7c0060aSjmatthew case CMPL_BASE_TYPE_RX_L2: 161718f50744Sbluhm if (ISSET(ifp->if_flags, IFF_RUNNING)) 161818f50744Sbluhm rollback = bnxt_rx(sc, rx, cpr, &ml, &rxfree, 161918f50744Sbluhm &agfree, cmpl); 1620a7c0060aSjmatthew break; 1621a7c0060aSjmatthew case CMPL_BASE_TYPE_TX_L2: 162218f50744Sbluhm if (ISSET(ifp->if_flags, IFF_RUNNING)) 1623765dc391Sjmatthew bnxt_txeof(sc, tx, &txfree, cmpl); 1624a7c0060aSjmatthew break; 1625a7c0060aSjmatthew default: 1626a7c0060aSjmatthew printf("%s: unexpected completion type %u\n", 1627a7c0060aSjmatthew DEVNAME(sc), type); 1628a7c0060aSjmatthew } 1629a7c0060aSjmatthew 1630c4f53494Sjmatthew if (rollback) { 1631c4f53494Sjmatthew bnxt_cpr_rollback(sc, cpr); 1632c4f53494Sjmatthew break; 1633c4f53494Sjmatthew } 1634c4f53494Sjmatthew rv = 1; 1635c4f53494Sjmatthew bnxt_cpr_commit(sc, cpr); 1636c4f53494Sjmatthew cmpl = bnxt_cpr_next_cmpl(sc, cpr); 1637c4f53494Sjmatthew } 1638a7c0060aSjmatthew 1639a7c0060aSjmatthew /* 1640a7c0060aSjmatthew * comments in bnxtreg.h suggest we should be writing cpr->cons here, 1641a7c0060aSjmatthew * but writing cpr->cons + 1 makes it stop interrupting. 1642a7c0060aSjmatthew */ 1643a7c0060aSjmatthew bnxt_write_cp_doorbell_index(sc, &cpr->ring, 1644c4f53494Sjmatthew (cpr->commit_cons+1) % cpr->ring.ring_size, 1); 1645a7c0060aSjmatthew 1646a7c0060aSjmatthew if (rxfree != 0) { 1647765dc391Sjmatthew rx->rx_cons += rxfree; 1648765dc391Sjmatthew if (rx->rx_cons >= rx->rx_ring.ring_size) 1649765dc391Sjmatthew rx->rx_cons -= rx->rx_ring.ring_size; 1650a7c0060aSjmatthew 1651765dc391Sjmatthew rx->rx_ag_cons += agfree; 1652765dc391Sjmatthew if (rx->rx_ag_cons >= rx->rx_ag_ring.ring_size) 1653765dc391Sjmatthew rx->rx_ag_cons -= rx->rx_ag_ring.ring_size; 1654c4f53494Sjmatthew 1655765dc391Sjmatthew if_rxr_put(&rx->rxr[0], rxfree); 1656765dc391Sjmatthew if_rxr_put(&rx->rxr[1], agfree); 1657a7c0060aSjmatthew 1658765dc391Sjmatthew if (ifiq_input(rx->rx_ifiq, &ml)) { 1659765dc391Sjmatthew if_rxr_livelocked(&rx->rxr[0]); 1660765dc391Sjmatthew if_rxr_livelocked(&rx->rxr[1]); 1661447a2df6Sdlg } 1662447a2df6Sdlg 1663765dc391Sjmatthew bnxt_rx_fill(q); 1664*2783188aSjmatthew bnxt_rx_fill_ag(q); 1665765dc391Sjmatthew if ((rx->rx_cons == rx->rx_prod) || 1666765dc391Sjmatthew (rx->rx_ag_cons == rx->rx_ag_prod)) 1667765dc391Sjmatthew timeout_add(&rx->rx_refill, 0); 1668a7c0060aSjmatthew } 1669a7c0060aSjmatthew if (txfree != 0) { 1670765dc391Sjmatthew if (ifq_is_oactive(tx->tx_ifq)) 1671765dc391Sjmatthew ifq_restart(tx->tx_ifq); 1672a7c0060aSjmatthew } 167303373e89Sjmatthew return (rv); 1674a7c0060aSjmatthew } 1675a7c0060aSjmatthew 1676a7c0060aSjmatthew void 1677a7c0060aSjmatthew bnxt_watchdog(struct ifnet *ifp) 1678a7c0060aSjmatthew { 1679a7c0060aSjmatthew } 1680a7c0060aSjmatthew 1681a7c0060aSjmatthew void 1682a7c0060aSjmatthew bnxt_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1683a7c0060aSjmatthew { 1684a7c0060aSjmatthew struct bnxt_softc *sc = (struct bnxt_softc *)ifp->if_softc; 1685a7c0060aSjmatthew bnxt_hwrm_port_phy_qcfg(sc, ifmr); 1686a7c0060aSjmatthew } 1687a7c0060aSjmatthew 1688d256ca68Sjmatthew uint64_t 1689d256ca68Sjmatthew bnxt_get_media_type(uint64_t speed, int phy_type) 1690d256ca68Sjmatthew { 1691d256ca68Sjmatthew switch (phy_type) { 169252c4f284Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_UNKNOWN: 1693d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASECR: 1694d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASECR_CA_L: 1695d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASECR_CA_S: 1696d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASECR_CA_N: 1697d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASECR4: 1698d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASECR4: 1699d256ca68Sjmatthew switch (speed) { 1700d256ca68Sjmatthew case IF_Gbps(1): 1701d256ca68Sjmatthew return IFM_1000_T; 1702d256ca68Sjmatthew case IF_Gbps(10): 1703d256ca68Sjmatthew return IFM_10G_SFP_CU; 1704d256ca68Sjmatthew case IF_Gbps(25): 1705d256ca68Sjmatthew return IFM_25G_CR; 1706d256ca68Sjmatthew case IF_Gbps(40): 1707d256ca68Sjmatthew return IFM_40G_CR4; 1708d256ca68Sjmatthew case IF_Gbps(50): 1709d256ca68Sjmatthew return IFM_50G_CR2; 1710d256ca68Sjmatthew case IF_Gbps(100): 1711d256ca68Sjmatthew return IFM_100G_CR4; 1712d256ca68Sjmatthew } 1713d256ca68Sjmatthew break; 1714d256ca68Sjmatthew 1715d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASELR: 1716d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASELR4: 1717d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASELR4: 1718d256ca68Sjmatthew switch (speed) { 1719d256ca68Sjmatthew case IF_Gbps(1): 1720d256ca68Sjmatthew return IFM_1000_LX; 1721d256ca68Sjmatthew case IF_Gbps(10): 1722d256ca68Sjmatthew return IFM_10G_LR; 1723d256ca68Sjmatthew case IF_Gbps(25): 1724d256ca68Sjmatthew return IFM_25G_LR; 1725d256ca68Sjmatthew case IF_Gbps(40): 1726d256ca68Sjmatthew return IFM_40G_LR4; 1727d256ca68Sjmatthew case IF_Gbps(100): 1728d256ca68Sjmatthew return IFM_100G_LR4; 1729d256ca68Sjmatthew } 1730d256ca68Sjmatthew break; 1731d256ca68Sjmatthew 1732d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASESR: 1733d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASESR: 1734d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASESR4: 1735d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASESR10: 1736d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_1G_BASESX: 1737d256ca68Sjmatthew switch (speed) { 1738d256ca68Sjmatthew case IF_Gbps(1): 1739d256ca68Sjmatthew return IFM_1000_SX; 1740d256ca68Sjmatthew case IF_Gbps(10): 1741d256ca68Sjmatthew return IFM_10G_SR; 1742d256ca68Sjmatthew case IF_Gbps(25): 1743d256ca68Sjmatthew return IFM_25G_SR; 1744d256ca68Sjmatthew case IF_Gbps(40): 1745d256ca68Sjmatthew return IFM_40G_SR4; 1746d256ca68Sjmatthew case IF_Gbps(100): 1747d256ca68Sjmatthew return IFM_100G_SR4; 1748d256ca68Sjmatthew } 1749d256ca68Sjmatthew break; 1750d256ca68Sjmatthew 1751d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASEER4: 1752d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASEER4: 1753d256ca68Sjmatthew switch (speed) { 1754d256ca68Sjmatthew case IF_Gbps(10): 1755d256ca68Sjmatthew return IFM_10G_ER; 1756d256ca68Sjmatthew case IF_Gbps(25): 1757d256ca68Sjmatthew return IFM_25G_ER; 1758d256ca68Sjmatthew } 1759d256ca68Sjmatthew /* missing IFM_40G_ER4, IFM_100G_ER4 */ 1760d256ca68Sjmatthew break; 1761d256ca68Sjmatthew 1762d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKR4: 1763d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKR2: 1764d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKR: 1765d256ca68Sjmatthew switch (speed) { 1766d256ca68Sjmatthew case IF_Gbps(10): 1767d256ca68Sjmatthew return IFM_10G_KR; 1768d256ca68Sjmatthew case IF_Gbps(20): 1769d256ca68Sjmatthew return IFM_20G_KR2; 1770d256ca68Sjmatthew case IF_Gbps(25): 1771d256ca68Sjmatthew return IFM_25G_KR; 1772d256ca68Sjmatthew case IF_Gbps(40): 1773d256ca68Sjmatthew return IFM_40G_KR4; 1774d256ca68Sjmatthew case IF_Gbps(50): 1775d256ca68Sjmatthew return IFM_50G_KR2; 1776d256ca68Sjmatthew case IF_Gbps(100): 1777d256ca68Sjmatthew return IFM_100G_KR4; 1778d256ca68Sjmatthew } 1779d256ca68Sjmatthew break; 1780d256ca68Sjmatthew 1781d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKX: 1782d256ca68Sjmatthew switch (speed) { 1783d256ca68Sjmatthew case IF_Gbps(1): 1784d256ca68Sjmatthew return IFM_1000_KX; 1785d256ca68Sjmatthew case IF_Mbps(2500): 1786d256ca68Sjmatthew return IFM_2500_KX; 1787d256ca68Sjmatthew case IF_Gbps(10): 1788d256ca68Sjmatthew return IFM_10G_KX4; 1789d256ca68Sjmatthew } 1790d256ca68Sjmatthew break; 1791d256ca68Sjmatthew 1792d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASET: 1793d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASETE: 1794d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_1G_BASET: 1795d256ca68Sjmatthew switch (speed) { 1796d256ca68Sjmatthew case IF_Mbps(10): 1797d256ca68Sjmatthew return IFM_10_T; 1798d256ca68Sjmatthew case IF_Mbps(100): 1799d256ca68Sjmatthew return IFM_100_TX; 1800d256ca68Sjmatthew case IF_Gbps(1): 1801d256ca68Sjmatthew return IFM_1000_T; 1802d256ca68Sjmatthew case IF_Mbps(2500): 1803d256ca68Sjmatthew return IFM_2500_T; 1804d256ca68Sjmatthew case IF_Gbps(10): 1805d256ca68Sjmatthew return IFM_10G_T; 1806d256ca68Sjmatthew } 1807d256ca68Sjmatthew break; 1808d256ca68Sjmatthew 1809d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_SGMIIEXTPHY: 1810d256ca68Sjmatthew switch (speed) { 1811d256ca68Sjmatthew case IF_Gbps(1): 1812d256ca68Sjmatthew return IFM_1000_SGMII; 1813d256ca68Sjmatthew } 1814d256ca68Sjmatthew break; 1815d256ca68Sjmatthew 1816d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_ACTIVE_CABLE: 1817d256ca68Sjmatthew switch (speed) { 1818d256ca68Sjmatthew case IF_Gbps(10): 1819d256ca68Sjmatthew return IFM_10G_AOC; 1820d256ca68Sjmatthew case IF_Gbps(25): 1821d256ca68Sjmatthew return IFM_25G_AOC; 1822d256ca68Sjmatthew case IF_Gbps(40): 1823d256ca68Sjmatthew return IFM_40G_AOC; 1824d256ca68Sjmatthew case IF_Gbps(100): 1825d256ca68Sjmatthew return IFM_100G_AOC; 1826d256ca68Sjmatthew } 1827d256ca68Sjmatthew break; 1828d256ca68Sjmatthew } 1829d256ca68Sjmatthew 1830d256ca68Sjmatthew return 0; 1831d256ca68Sjmatthew } 1832d256ca68Sjmatthew 1833d256ca68Sjmatthew void 1834d256ca68Sjmatthew bnxt_add_media_type(struct bnxt_softc *sc, int supported_speeds, uint64_t speed, uint64_t ifmt) 1835d256ca68Sjmatthew { 1836d256ca68Sjmatthew int speed_bit = 0; 1837d256ca68Sjmatthew switch (speed) { 1838d256ca68Sjmatthew case IF_Gbps(1): 1839d256ca68Sjmatthew speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_1GB; 1840d256ca68Sjmatthew break; 1841d256ca68Sjmatthew case IF_Gbps(2): 1842d256ca68Sjmatthew speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_2GB; 1843d256ca68Sjmatthew break; 1844d256ca68Sjmatthew case IF_Mbps(2500): 1845d256ca68Sjmatthew speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_2_5GB; 1846d256ca68Sjmatthew break; 1847d256ca68Sjmatthew case IF_Gbps(10): 1848d256ca68Sjmatthew speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_10GB; 1849d256ca68Sjmatthew break; 1850d256ca68Sjmatthew case IF_Gbps(20): 1851d256ca68Sjmatthew speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_20GB; 1852d256ca68Sjmatthew break; 1853d256ca68Sjmatthew case IF_Gbps(25): 1854d256ca68Sjmatthew speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_25GB; 1855d256ca68Sjmatthew break; 1856d256ca68Sjmatthew case IF_Gbps(40): 1857d256ca68Sjmatthew speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_40GB; 1858d256ca68Sjmatthew break; 1859d256ca68Sjmatthew case IF_Gbps(50): 1860d256ca68Sjmatthew speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_50GB; 1861d256ca68Sjmatthew break; 1862d256ca68Sjmatthew case IF_Gbps(100): 1863d256ca68Sjmatthew speed_bit = HWRM_PORT_PHY_QCFG_OUTPUT_SUPPORT_SPEEDS_100GB; 1864d256ca68Sjmatthew break; 1865d256ca68Sjmatthew } 1866d256ca68Sjmatthew if (supported_speeds & speed_bit) 1867d256ca68Sjmatthew ifmedia_add(&sc->sc_media, IFM_ETHER | ifmt, 0, NULL); 1868d256ca68Sjmatthew } 1869d256ca68Sjmatthew 1870d256ca68Sjmatthew int 1871d256ca68Sjmatthew bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *softc, struct ifmediareq *ifmr) 1872d256ca68Sjmatthew { 1873d256ca68Sjmatthew struct ifnet *ifp = &softc->sc_ac.ac_if; 1874d256ca68Sjmatthew struct hwrm_port_phy_qcfg_input req = {0}; 1875d256ca68Sjmatthew struct hwrm_port_phy_qcfg_output *resp = 1876d256ca68Sjmatthew BNXT_DMA_KVA(softc->sc_cmd_resp); 1877d256ca68Sjmatthew int link_state = LINK_STATE_DOWN; 18780f734ffcSjmatthew uint64_t speeds[] = { 1879d256ca68Sjmatthew IF_Gbps(1), IF_Gbps(2), IF_Mbps(2500), IF_Gbps(10), IF_Gbps(20), 1880d256ca68Sjmatthew IF_Gbps(25), IF_Gbps(40), IF_Gbps(50), IF_Gbps(100) 1881d256ca68Sjmatthew }; 1882d256ca68Sjmatthew uint64_t media_type; 188392586e53Sjmatthew int duplex; 1884d256ca68Sjmatthew int rc = 0; 1885d256ca68Sjmatthew int i; 1886d256ca68Sjmatthew 1887d256ca68Sjmatthew BNXT_HWRM_LOCK(softc); 1888d256ca68Sjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_QCFG); 1889d256ca68Sjmatthew 1890d256ca68Sjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 1891d256ca68Sjmatthew if (rc) { 1892d256ca68Sjmatthew printf("%s: failed to query port phy config\n", DEVNAME(softc)); 1893d256ca68Sjmatthew goto exit; 1894d256ca68Sjmatthew } 1895d256ca68Sjmatthew 189692586e53Sjmatthew if (softc->sc_hwrm_ver > 0x10800) 189792586e53Sjmatthew duplex = resp->duplex_state; 189892586e53Sjmatthew else 189992586e53Sjmatthew duplex = resp->duplex_cfg; 190092586e53Sjmatthew 1901d256ca68Sjmatthew if (resp->link == HWRM_PORT_PHY_QCFG_OUTPUT_LINK_LINK) { 190292586e53Sjmatthew if (duplex == HWRM_PORT_PHY_QCFG_OUTPUT_DUPLEX_STATE_HALF) 1903d256ca68Sjmatthew link_state = LINK_STATE_HALF_DUPLEX; 1904d256ca68Sjmatthew else 1905d256ca68Sjmatthew link_state = LINK_STATE_FULL_DUPLEX; 1906d256ca68Sjmatthew 1907d256ca68Sjmatthew switch (resp->link_speed) { 1908d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_10MB: 1909d256ca68Sjmatthew ifp->if_baudrate = IF_Mbps(10); 1910d256ca68Sjmatthew break; 1911d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_100MB: 1912d256ca68Sjmatthew ifp->if_baudrate = IF_Mbps(100); 1913d256ca68Sjmatthew break; 1914d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_1GB: 1915d256ca68Sjmatthew ifp->if_baudrate = IF_Gbps(1); 1916d256ca68Sjmatthew break; 1917d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_2GB: 1918d256ca68Sjmatthew ifp->if_baudrate = IF_Gbps(2); 1919d256ca68Sjmatthew break; 1920d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_2_5GB: 1921d256ca68Sjmatthew ifp->if_baudrate = IF_Mbps(2500); 1922d256ca68Sjmatthew break; 1923d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_10GB: 1924d256ca68Sjmatthew ifp->if_baudrate = IF_Gbps(10); 1925d256ca68Sjmatthew break; 1926d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_20GB: 1927d256ca68Sjmatthew ifp->if_baudrate = IF_Gbps(20); 1928d256ca68Sjmatthew break; 1929d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_25GB: 1930d256ca68Sjmatthew ifp->if_baudrate = IF_Gbps(25); 1931d256ca68Sjmatthew break; 1932d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_40GB: 1933d256ca68Sjmatthew ifp->if_baudrate = IF_Gbps(40); 1934d256ca68Sjmatthew break; 1935d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_50GB: 1936d256ca68Sjmatthew ifp->if_baudrate = IF_Gbps(50); 1937d256ca68Sjmatthew break; 1938d256ca68Sjmatthew case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_100GB: 1939d256ca68Sjmatthew ifp->if_baudrate = IF_Gbps(100); 1940d256ca68Sjmatthew break; 1941d256ca68Sjmatthew } 1942d256ca68Sjmatthew } 1943d256ca68Sjmatthew 1944d256ca68Sjmatthew ifmedia_delete_instance(&softc->sc_media, IFM_INST_ANY); 1945d256ca68Sjmatthew for (i = 0; i < nitems(speeds); i++) { 1946d256ca68Sjmatthew media_type = bnxt_get_media_type(speeds[i], resp->phy_type); 1947d256ca68Sjmatthew if (media_type != 0) 1948d256ca68Sjmatthew bnxt_add_media_type(softc, resp->support_speeds, 1949d256ca68Sjmatthew speeds[i], media_type); 1950d256ca68Sjmatthew } 1951d256ca68Sjmatthew ifmedia_add(&softc->sc_media, IFM_ETHER|IFM_AUTO, 0, NULL); 1952d256ca68Sjmatthew ifmedia_set(&softc->sc_media, IFM_ETHER|IFM_AUTO); 1953d256ca68Sjmatthew 1954d256ca68Sjmatthew if (ifmr != NULL) { 1955d256ca68Sjmatthew ifmr->ifm_status = IFM_AVALID; 1956d256ca68Sjmatthew if (LINK_STATE_IS_UP(ifp->if_link_state)) { 1957d256ca68Sjmatthew ifmr->ifm_status |= IFM_ACTIVE; 1958d256ca68Sjmatthew ifmr->ifm_active = IFM_ETHER | IFM_AUTO; 1959d256ca68Sjmatthew if (resp->pause & HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX) 1960d256ca68Sjmatthew ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1961d256ca68Sjmatthew if (resp->pause & HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX) 1962d256ca68Sjmatthew ifmr->ifm_active |= IFM_ETH_RXPAUSE; 196392586e53Sjmatthew if (duplex == HWRM_PORT_PHY_QCFG_OUTPUT_DUPLEX_STATE_HALF) 1964d256ca68Sjmatthew ifmr->ifm_active |= IFM_HDX; 1965d256ca68Sjmatthew else 1966d256ca68Sjmatthew ifmr->ifm_active |= IFM_FDX; 1967d256ca68Sjmatthew 1968d256ca68Sjmatthew media_type = bnxt_get_media_type(ifp->if_baudrate, resp->phy_type); 1969d256ca68Sjmatthew if (media_type != 0) 1970d256ca68Sjmatthew ifmr->ifm_active |= media_type; 1971d256ca68Sjmatthew } 1972d256ca68Sjmatthew } 1973d256ca68Sjmatthew 1974d256ca68Sjmatthew exit: 1975d256ca68Sjmatthew BNXT_HWRM_UNLOCK(softc); 1976d256ca68Sjmatthew 1977d256ca68Sjmatthew if (rc == 0 && (link_state != ifp->if_link_state)) { 1978d256ca68Sjmatthew ifp->if_link_state = link_state; 1979d256ca68Sjmatthew if_link_state_change(ifp); 1980d256ca68Sjmatthew } 1981d256ca68Sjmatthew 1982d256ca68Sjmatthew return rc; 1983d256ca68Sjmatthew } 1984d256ca68Sjmatthew 1985a7c0060aSjmatthew int 1986a7c0060aSjmatthew bnxt_media_change(struct ifnet *ifp) 1987a7c0060aSjmatthew { 1988d256ca68Sjmatthew struct bnxt_softc *sc = (struct bnxt_softc *)ifp->if_softc; 1989d256ca68Sjmatthew struct hwrm_port_phy_cfg_input req = {0}; 1990d256ca68Sjmatthew uint64_t link_speed; 1991d256ca68Sjmatthew 1992d256ca68Sjmatthew if (IFM_TYPE(sc->sc_media.ifm_media) != IFM_ETHER) 1993d256ca68Sjmatthew return EINVAL; 1994d256ca68Sjmatthew 1995d256ca68Sjmatthew if (sc->sc_flags & BNXT_FLAG_NPAR) 1996d256ca68Sjmatthew return ENODEV; 1997d256ca68Sjmatthew 1998d256ca68Sjmatthew bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_PORT_PHY_CFG); 1999d256ca68Sjmatthew 2000d256ca68Sjmatthew switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) { 2001d256ca68Sjmatthew case IFM_100G_CR4: 2002d256ca68Sjmatthew case IFM_100G_SR4: 2003d256ca68Sjmatthew case IFM_100G_KR4: 2004d256ca68Sjmatthew case IFM_100G_LR4: 2005d256ca68Sjmatthew case IFM_100G_AOC: 2006d256ca68Sjmatthew link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_100GB; 2007d256ca68Sjmatthew break; 2008d256ca68Sjmatthew 2009d256ca68Sjmatthew case IFM_50G_CR2: 2010d256ca68Sjmatthew case IFM_50G_KR2: 2011d256ca68Sjmatthew link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_50GB; 2012d256ca68Sjmatthew break; 2013d256ca68Sjmatthew 2014d256ca68Sjmatthew case IFM_40G_CR4: 2015d256ca68Sjmatthew case IFM_40G_SR4: 2016d256ca68Sjmatthew case IFM_40G_LR4: 2017d256ca68Sjmatthew case IFM_40G_KR4: 2018d256ca68Sjmatthew case IFM_40G_AOC: 2019d256ca68Sjmatthew link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_40GB; 2020d256ca68Sjmatthew break; 2021d256ca68Sjmatthew 2022d256ca68Sjmatthew case IFM_25G_CR: 2023d256ca68Sjmatthew case IFM_25G_KR: 2024d256ca68Sjmatthew case IFM_25G_SR: 2025d256ca68Sjmatthew case IFM_25G_LR: 2026d256ca68Sjmatthew case IFM_25G_ER: 2027d256ca68Sjmatthew case IFM_25G_AOC: 2028d256ca68Sjmatthew link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_25GB; 2029d256ca68Sjmatthew break; 2030d256ca68Sjmatthew 2031d256ca68Sjmatthew case IFM_10G_LR: 2032d256ca68Sjmatthew case IFM_10G_SR: 2033d256ca68Sjmatthew case IFM_10G_CX4: 2034d256ca68Sjmatthew case IFM_10G_T: 2035d256ca68Sjmatthew case IFM_10G_SFP_CU: 2036d256ca68Sjmatthew case IFM_10G_LRM: 2037d256ca68Sjmatthew case IFM_10G_KX4: 2038d256ca68Sjmatthew case IFM_10G_KR: 2039d256ca68Sjmatthew case IFM_10G_CR1: 2040d256ca68Sjmatthew case IFM_10G_ER: 2041d256ca68Sjmatthew case IFM_10G_AOC: 2042d256ca68Sjmatthew link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_10GB; 2043d256ca68Sjmatthew break; 2044d256ca68Sjmatthew 2045d256ca68Sjmatthew case IFM_2500_SX: 2046d256ca68Sjmatthew case IFM_2500_KX: 2047d256ca68Sjmatthew case IFM_2500_T: 2048d256ca68Sjmatthew link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_2_5GB; 2049d256ca68Sjmatthew break; 2050d256ca68Sjmatthew 2051d256ca68Sjmatthew case IFM_1000_T: 2052d256ca68Sjmatthew case IFM_1000_LX: 2053d256ca68Sjmatthew case IFM_1000_SX: 2054d256ca68Sjmatthew case IFM_1000_CX: 2055d256ca68Sjmatthew case IFM_1000_KX: 2056d256ca68Sjmatthew link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_1GB; 2057d256ca68Sjmatthew break; 2058d256ca68Sjmatthew 2059d256ca68Sjmatthew case IFM_100_TX: 2060d256ca68Sjmatthew link_speed = HWRM_PORT_PHY_QCFG_OUTPUT_FORCE_LINK_SPEED_100MB; 2061d256ca68Sjmatthew break; 2062d256ca68Sjmatthew 2063d256ca68Sjmatthew default: 2064d256ca68Sjmatthew link_speed = 0; 2065d256ca68Sjmatthew } 2066d256ca68Sjmatthew 206792586e53Sjmatthew req.enables |= htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_DUPLEX); 206892586e53Sjmatthew req.auto_duplex = HWRM_PORT_PHY_CFG_INPUT_AUTO_DUPLEX_BOTH; 2069d256ca68Sjmatthew if (link_speed == 0) { 2070d256ca68Sjmatthew req.auto_mode |= 2071d256ca68Sjmatthew HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_ALL_SPEEDS; 2072d256ca68Sjmatthew req.flags |= 2073d256ca68Sjmatthew htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG); 2074d256ca68Sjmatthew req.enables |= 2075d256ca68Sjmatthew htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE); 2076d256ca68Sjmatthew } else { 2077d256ca68Sjmatthew req.force_link_speed = htole16(link_speed); 2078d256ca68Sjmatthew req.flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE); 2079d256ca68Sjmatthew } 2080d256ca68Sjmatthew req.flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESET_PHY); 2081d256ca68Sjmatthew 2082d256ca68Sjmatthew return hwrm_send_message(sc, &req, sizeof(req)); 2083a7c0060aSjmatthew } 2084a7c0060aSjmatthew 2085c6900e6bSjmatthew int 2086c6900e6bSjmatthew bnxt_media_autonegotiate(struct bnxt_softc *sc) 2087c6900e6bSjmatthew { 2088c6900e6bSjmatthew struct hwrm_port_phy_cfg_input req = {0}; 2089c6900e6bSjmatthew 2090c6900e6bSjmatthew if (sc->sc_flags & BNXT_FLAG_NPAR) 2091c6900e6bSjmatthew return ENODEV; 2092c6900e6bSjmatthew 2093c6900e6bSjmatthew bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_PORT_PHY_CFG); 2094c6900e6bSjmatthew req.auto_mode |= HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_ALL_SPEEDS; 209592586e53Sjmatthew req.auto_duplex = HWRM_PORT_PHY_CFG_INPUT_AUTO_DUPLEX_BOTH; 209692586e53Sjmatthew req.enables |= htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE | 209792586e53Sjmatthew HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_DUPLEX); 2098c6900e6bSjmatthew req.flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG); 2099c6900e6bSjmatthew req.flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESET_PHY); 2100c6900e6bSjmatthew 2101c6900e6bSjmatthew return hwrm_send_message(sc, &req, sizeof(req)); 2102c6900e6bSjmatthew } 2103c6900e6bSjmatthew 2104c6900e6bSjmatthew 2105a7c0060aSjmatthew void 2106a7c0060aSjmatthew bnxt_mark_cpr_invalid(struct bnxt_cp_ring *cpr) 2107a7c0060aSjmatthew { 2108a7c0060aSjmatthew struct cmpl_base *cmp = (void *)cpr->ring.vaddr; 2109a7c0060aSjmatthew int i; 2110a7c0060aSjmatthew 2111a7c0060aSjmatthew for (i = 0; i < cpr->ring.ring_size; i++) 2112a7c0060aSjmatthew cmp[i].info3_v = !cpr->v_bit; 2113a7c0060aSjmatthew } 2114a7c0060aSjmatthew 2115a7c0060aSjmatthew void 2116a7c0060aSjmatthew bnxt_write_cp_doorbell(struct bnxt_softc *sc, struct bnxt_ring *ring, 2117a7c0060aSjmatthew int enable) 2118a7c0060aSjmatthew { 2119a7c0060aSjmatthew uint32_t val = CMPL_DOORBELL_KEY_CMPL; 2120a7c0060aSjmatthew if (enable == 0) 2121a7c0060aSjmatthew val |= CMPL_DOORBELL_MASK; 2122a7c0060aSjmatthew 2123a7c0060aSjmatthew bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4, 2124a7c0060aSjmatthew BUS_SPACE_BARRIER_WRITE); 2125a7c0060aSjmatthew bus_space_barrier(sc->sc_db_t, sc->sc_db_h, 0, sc->sc_db_s, 2126a7c0060aSjmatthew BUS_SPACE_BARRIER_WRITE); 2127a7c0060aSjmatthew bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 2128a7c0060aSjmatthew htole32(val)); 2129a7c0060aSjmatthew } 2130a7c0060aSjmatthew 2131a7c0060aSjmatthew void 2132a7c0060aSjmatthew bnxt_write_cp_doorbell_index(struct bnxt_softc *sc, struct bnxt_ring *ring, 2133a7c0060aSjmatthew uint32_t index, int enable) 2134a7c0060aSjmatthew { 2135a7c0060aSjmatthew uint32_t val = CMPL_DOORBELL_KEY_CMPL | CMPL_DOORBELL_IDX_VALID | 2136a7c0060aSjmatthew (index & CMPL_DOORBELL_IDX_MASK); 2137a7c0060aSjmatthew if (enable == 0) 2138a7c0060aSjmatthew val |= CMPL_DOORBELL_MASK; 2139a7c0060aSjmatthew bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4, 2140a7c0060aSjmatthew BUS_SPACE_BARRIER_WRITE); 2141a7c0060aSjmatthew bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 2142a7c0060aSjmatthew htole32(val)); 2143a7c0060aSjmatthew bus_space_barrier(sc->sc_db_t, sc->sc_db_h, 0, sc->sc_db_s, 2144a7c0060aSjmatthew BUS_SPACE_BARRIER_WRITE); 2145a7c0060aSjmatthew } 2146a7c0060aSjmatthew 2147a7c0060aSjmatthew void 2148a7c0060aSjmatthew bnxt_write_rx_doorbell(struct bnxt_softc *sc, struct bnxt_ring *ring, int index) 2149a7c0060aSjmatthew { 2150a7c0060aSjmatthew uint32_t val = RX_DOORBELL_KEY_RX | index; 2151a7c0060aSjmatthew bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4, 2152a7c0060aSjmatthew BUS_SPACE_BARRIER_WRITE); 2153a7c0060aSjmatthew bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 2154a7c0060aSjmatthew htole32(val)); 2155a7c0060aSjmatthew 2156a7c0060aSjmatthew /* second write isn't necessary on all hardware */ 2157a7c0060aSjmatthew bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4, 2158a7c0060aSjmatthew BUS_SPACE_BARRIER_WRITE); 2159a7c0060aSjmatthew bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 2160a7c0060aSjmatthew htole32(val)); 2161a7c0060aSjmatthew } 2162a7c0060aSjmatthew 2163a7c0060aSjmatthew void 2164a7c0060aSjmatthew bnxt_write_tx_doorbell(struct bnxt_softc *sc, struct bnxt_ring *ring, int index) 2165a7c0060aSjmatthew { 2166a7c0060aSjmatthew uint32_t val = TX_DOORBELL_KEY_TX | index; 2167a7c0060aSjmatthew bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4, 2168a7c0060aSjmatthew BUS_SPACE_BARRIER_WRITE); 2169a7c0060aSjmatthew bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 2170a7c0060aSjmatthew htole32(val)); 2171a7c0060aSjmatthew 2172a7c0060aSjmatthew /* second write isn't necessary on all hardware */ 2173a7c0060aSjmatthew bus_space_barrier(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 4, 2174a7c0060aSjmatthew BUS_SPACE_BARRIER_WRITE); 2175a7c0060aSjmatthew bus_space_write_4(sc->sc_db_t, sc->sc_db_h, ring->doorbell, 2176a7c0060aSjmatthew htole32(val)); 2177a7c0060aSjmatthew } 2178a7c0060aSjmatthew 2179a7c0060aSjmatthew u_int 2180c4f53494Sjmatthew bnxt_rx_fill_slots(struct bnxt_softc *sc, struct bnxt_ring *ring, void *ring_mem, 2181c4f53494Sjmatthew struct bnxt_slot *slots, uint *prod, int bufsize, uint16_t bdtype, 2182c4f53494Sjmatthew u_int nslots) 2183a7c0060aSjmatthew { 2184a7c0060aSjmatthew struct rx_prod_pkt_bd *rxring; 2185a7c0060aSjmatthew struct bnxt_slot *bs; 2186a7c0060aSjmatthew struct mbuf *m; 2187a7c0060aSjmatthew uint p, fills; 2188a7c0060aSjmatthew 2189c4f53494Sjmatthew rxring = (struct rx_prod_pkt_bd *)ring_mem; 2190c4f53494Sjmatthew p = *prod; 2191c4f53494Sjmatthew for (fills = 0; fills < nslots; fills++) { 2192c4f53494Sjmatthew bs = &slots[p]; 2193471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, bufsize); 2194a7c0060aSjmatthew if (m == NULL) 2195a7c0060aSjmatthew break; 2196a7c0060aSjmatthew 2197c4f53494Sjmatthew m->m_len = m->m_pkthdr.len = bufsize; 2198a7c0060aSjmatthew if (bus_dmamap_load_mbuf(sc->sc_dmat, bs->bs_map, m, 2199a7c0060aSjmatthew BUS_DMA_NOWAIT) != 0) { 2200a7c0060aSjmatthew m_freem(m); 2201a7c0060aSjmatthew break; 2202a7c0060aSjmatthew } 2203a7c0060aSjmatthew bs->bs_m = m; 2204a7c0060aSjmatthew 2205c4f53494Sjmatthew rxring[p].flags_type = htole16(bdtype); 2206c4f53494Sjmatthew rxring[p].len = htole16(bufsize); 2207a7c0060aSjmatthew rxring[p].opaque = p; 2208a7c0060aSjmatthew rxring[p].addr = htole64(bs->bs_map->dm_segs[0].ds_addr); 2209a7c0060aSjmatthew 2210c4f53494Sjmatthew if (++p >= ring->ring_size) 2211a7c0060aSjmatthew p = 0; 2212a7c0060aSjmatthew } 2213a7c0060aSjmatthew 2214a7c0060aSjmatthew if (fills != 0) 2215c4f53494Sjmatthew bnxt_write_rx_doorbell(sc, ring, p); 2216c4f53494Sjmatthew *prod = p; 2217a7c0060aSjmatthew 2218c4f53494Sjmatthew return (nslots - fills); 2219a7c0060aSjmatthew } 2220a7c0060aSjmatthew 2221a7c0060aSjmatthew int 2222765dc391Sjmatthew bnxt_rx_fill(struct bnxt_queue *q) 2223a7c0060aSjmatthew { 2224765dc391Sjmatthew struct bnxt_rx_queue *rx = &q->q_rx; 2225765dc391Sjmatthew struct bnxt_softc *sc = q->q_sc; 2226a7c0060aSjmatthew u_int slots; 2227c4f53494Sjmatthew int rv = 0; 2228a7c0060aSjmatthew 2229765dc391Sjmatthew slots = if_rxr_get(&rx->rxr[0], rx->rx_ring.ring_size); 2230c4f53494Sjmatthew if (slots > 0) { 2231765dc391Sjmatthew slots = bnxt_rx_fill_slots(sc, &rx->rx_ring, 2232765dc391Sjmatthew BNXT_DMA_KVA(rx->rx_ring_mem), rx->rx_slots, 2233765dc391Sjmatthew &rx->rx_prod, MCLBYTES, 2234c4f53494Sjmatthew RX_PROD_PKT_BD_TYPE_RX_PROD_PKT, slots); 2235765dc391Sjmatthew if_rxr_put(&rx->rxr[0], slots); 2236c4f53494Sjmatthew } else 2237c4f53494Sjmatthew rv = 1; 2238a7c0060aSjmatthew 2239*2783188aSjmatthew return (rv); 2240*2783188aSjmatthew } 2241*2783188aSjmatthew 2242*2783188aSjmatthew int 2243*2783188aSjmatthew bnxt_rx_fill_ag(struct bnxt_queue *q) 2244*2783188aSjmatthew { 2245*2783188aSjmatthew struct bnxt_rx_queue *rx = &q->q_rx; 2246*2783188aSjmatthew struct bnxt_softc *sc = q->q_sc; 2247*2783188aSjmatthew u_int slots; 2248*2783188aSjmatthew int rv = 0; 2249*2783188aSjmatthew 2250765dc391Sjmatthew slots = if_rxr_get(&rx->rxr[1], rx->rx_ag_ring.ring_size); 2251c4f53494Sjmatthew if (slots > 0) { 2252765dc391Sjmatthew slots = bnxt_rx_fill_slots(sc, &rx->rx_ag_ring, 2253765dc391Sjmatthew BNXT_DMA_KVA(rx->rx_ring_mem) + PAGE_SIZE, 2254765dc391Sjmatthew rx->rx_ag_slots, &rx->rx_ag_prod, 2255c4f53494Sjmatthew BNXT_AG_BUFFER_SIZE, 2256c4f53494Sjmatthew RX_PROD_AGG_BD_TYPE_RX_PROD_AGG, slots); 2257765dc391Sjmatthew if_rxr_put(&rx->rxr[1], slots); 2258c4f53494Sjmatthew } else 2259c4f53494Sjmatthew rv = 1; 2260a7c0060aSjmatthew 2261c4f53494Sjmatthew return (rv); 2262a7c0060aSjmatthew } 2263a7c0060aSjmatthew 2264a7c0060aSjmatthew void 2265765dc391Sjmatthew bnxt_refill(void *xq) 2266a7c0060aSjmatthew { 2267765dc391Sjmatthew struct bnxt_queue *q = xq; 2268765dc391Sjmatthew struct bnxt_rx_queue *rx = &q->q_rx; 2269a7c0060aSjmatthew 2270*2783188aSjmatthew if (rx->rx_cons == rx->rx_prod) 2271765dc391Sjmatthew bnxt_rx_fill(q); 2272a7c0060aSjmatthew 2273*2783188aSjmatthew if (rx->rx_ag_cons == rx->rx_ag_prod) 2274*2783188aSjmatthew bnxt_rx_fill_ag(q); 2275*2783188aSjmatthew 2276*2783188aSjmatthew if ((rx->rx_cons == rx->rx_prod) || 2277*2783188aSjmatthew (rx->rx_ag_cons == rx->rx_ag_prod)) 2278765dc391Sjmatthew timeout_add(&rx->rx_refill, 1); 2279a7c0060aSjmatthew } 2280a7c0060aSjmatthew 2281c4f53494Sjmatthew int 2282765dc391Sjmatthew bnxt_rx(struct bnxt_softc *sc, struct bnxt_rx_queue *rx, 2283765dc391Sjmatthew struct bnxt_cp_ring *cpr, struct mbuf_list *ml, int *slots, int *agslots, 2284765dc391Sjmatthew struct cmpl_base *cmpl) 2285a7c0060aSjmatthew { 2286c4f53494Sjmatthew struct mbuf *m, *am; 2287a7c0060aSjmatthew struct bnxt_slot *bs; 2288765dc391Sjmatthew struct rx_pkt_cmpl *rxlo = (struct rx_pkt_cmpl *)cmpl; 2289c4f53494Sjmatthew struct rx_pkt_cmpl_hi *rxhi; 2290c4f53494Sjmatthew struct rx_abuf_cmpl *ag; 2291870f5687Sjmatthew uint32_t flags; 2292870f5687Sjmatthew uint16_t errors; 2293c4f53494Sjmatthew 2294c4f53494Sjmatthew /* second part of the rx completion */ 2295c4f53494Sjmatthew rxhi = (struct rx_pkt_cmpl_hi *)bnxt_cpr_next_cmpl(sc, cpr); 2296c4f53494Sjmatthew if (rxhi == NULL) { 2297c4f53494Sjmatthew return (1); 2298c4f53494Sjmatthew } 2299c4f53494Sjmatthew 2300c4f53494Sjmatthew /* packets over 2k in size use an aggregation buffer completion too */ 2301c4f53494Sjmatthew ag = NULL; 2302765dc391Sjmatthew if ((rxlo->agg_bufs_v1 >> RX_PKT_CMPL_AGG_BUFS_SFT) != 0) { 2303c4f53494Sjmatthew ag = (struct rx_abuf_cmpl *)bnxt_cpr_next_cmpl(sc, cpr); 2304c4f53494Sjmatthew if (ag == NULL) { 2305c4f53494Sjmatthew return (1); 2306c4f53494Sjmatthew } 2307c4f53494Sjmatthew } 2308a7c0060aSjmatthew 2309765dc391Sjmatthew bs = &rx->rx_slots[rxlo->opaque]; 2310a7c0060aSjmatthew bus_dmamap_sync(sc->sc_dmat, bs->bs_map, 0, bs->bs_map->dm_mapsize, 2311a7c0060aSjmatthew BUS_DMASYNC_POSTREAD); 2312a7c0060aSjmatthew bus_dmamap_unload(sc->sc_dmat, bs->bs_map); 2313a7c0060aSjmatthew 2314a7c0060aSjmatthew m = bs->bs_m; 2315a7c0060aSjmatthew bs->bs_m = NULL; 2316765dc391Sjmatthew m->m_pkthdr.len = m->m_len = letoh16(rxlo->len); 2317a7c0060aSjmatthew (*slots)++; 2318c4f53494Sjmatthew 2319870f5687Sjmatthew /* checksum flags */ 2320870f5687Sjmatthew flags = lemtoh32(&rxhi->flags2); 2321870f5687Sjmatthew errors = lemtoh16(&rxhi->errors_v2); 2322870f5687Sjmatthew if ((flags & RX_PKT_CMPL_FLAGS2_IP_CS_CALC) != 0 && 2323870f5687Sjmatthew (errors & RX_PKT_CMPL_ERRORS_IP_CS_ERROR) == 0) 2324870f5687Sjmatthew m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; 2325870f5687Sjmatthew 2326870f5687Sjmatthew if ((flags & RX_PKT_CMPL_FLAGS2_L4_CS_CALC) != 0 && 2327870f5687Sjmatthew (errors & RX_PKT_CMPL_ERRORS_L4_CS_ERROR) == 0) 2328870f5687Sjmatthew m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK | 2329870f5687Sjmatthew M_UDP_CSUM_IN_OK; 2330870f5687Sjmatthew 2331870f5687Sjmatthew #if NVLAN > 0 2332870f5687Sjmatthew if ((flags & RX_PKT_CMPL_FLAGS2_META_FORMAT_MASK) == 2333870f5687Sjmatthew RX_PKT_CMPL_FLAGS2_META_FORMAT_VLAN) { 2334870f5687Sjmatthew m->m_pkthdr.ether_vtag = lemtoh16(&rxhi->metadata); 2335870f5687Sjmatthew m->m_flags |= M_VLANTAG; 2336870f5687Sjmatthew } 2337870f5687Sjmatthew #endif 2338870f5687Sjmatthew 2339d160d8f0Sjmatthew if (lemtoh16(&rxlo->flags_type) & RX_PKT_CMPL_FLAGS_RSS_VALID) { 2340d160d8f0Sjmatthew m->m_pkthdr.ph_flowid = lemtoh32(&rxlo->rss_hash); 2341d160d8f0Sjmatthew m->m_pkthdr.csum_flags |= M_FLOWID; 2342d160d8f0Sjmatthew } 2343d160d8f0Sjmatthew 2344c4f53494Sjmatthew if (ag != NULL) { 2345765dc391Sjmatthew bs = &rx->rx_ag_slots[ag->opaque]; 2346c4f53494Sjmatthew bus_dmamap_sync(sc->sc_dmat, bs->bs_map, 0, 2347c4f53494Sjmatthew bs->bs_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 2348c4f53494Sjmatthew bus_dmamap_unload(sc->sc_dmat, bs->bs_map); 2349c4f53494Sjmatthew 2350c4f53494Sjmatthew am = bs->bs_m; 2351c4f53494Sjmatthew bs->bs_m = NULL; 2352c4f53494Sjmatthew am->m_len = letoh16(ag->len); 2353c4f53494Sjmatthew m->m_next = am; 2354c4f53494Sjmatthew m->m_pkthdr.len += am->m_len; 2355c4f53494Sjmatthew (*agslots)++; 2356a7c0060aSjmatthew } 2357a7c0060aSjmatthew 2358c4f53494Sjmatthew ml_enqueue(ml, m); 2359c4f53494Sjmatthew return (0); 2360c4f53494Sjmatthew } 2361c4f53494Sjmatthew 2362c4f53494Sjmatthew void 2363765dc391Sjmatthew bnxt_txeof(struct bnxt_softc *sc, struct bnxt_tx_queue *tx, int *txfree, 2364765dc391Sjmatthew struct cmpl_base *cmpl) 2365a7c0060aSjmatthew { 2366a7c0060aSjmatthew struct tx_cmpl *txcmpl = (struct tx_cmpl *)cmpl; 2367a7c0060aSjmatthew struct bnxt_slot *bs; 2368a7c0060aSjmatthew bus_dmamap_t map; 2369c4f53494Sjmatthew u_int idx, segs, last; 2370a7c0060aSjmatthew 2371765dc391Sjmatthew idx = tx->tx_ring_cons; 2372765dc391Sjmatthew last = tx->tx_cons; 2373058d3950Sjmatthew do { 2374765dc391Sjmatthew bs = &tx->tx_slots[tx->tx_cons]; 2375a7c0060aSjmatthew map = bs->bs_map; 2376a7c0060aSjmatthew 2377af7e9c1bSjmatthew segs = BNXT_TX_SLOTS(bs); 2378a7c0060aSjmatthew bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 2379a7c0060aSjmatthew BUS_DMASYNC_POSTWRITE); 2380a7c0060aSjmatthew bus_dmamap_unload(sc->sc_dmat, map); 2381a7c0060aSjmatthew m_freem(bs->bs_m); 2382a7c0060aSjmatthew bs->bs_m = NULL; 2383a7c0060aSjmatthew 2384058d3950Sjmatthew idx += segs; 2385c4f53494Sjmatthew (*txfree) += segs; 2386765dc391Sjmatthew if (idx >= tx->tx_ring.ring_size) 2387765dc391Sjmatthew idx -= tx->tx_ring.ring_size; 2388a7c0060aSjmatthew 2389765dc391Sjmatthew last = tx->tx_cons; 2390765dc391Sjmatthew if (++tx->tx_cons >= tx->tx_ring.ring_size) 2391765dc391Sjmatthew tx->tx_cons = 0; 2392a7c0060aSjmatthew 2393058d3950Sjmatthew } while (last != txcmpl->opaque); 2394765dc391Sjmatthew tx->tx_ring_cons = idx; 2395a7c0060aSjmatthew } 2396a7c0060aSjmatthew 2397a7c0060aSjmatthew /* bnxt_hwrm.c */ 2398a7c0060aSjmatthew 23990c45b53cSjmatthew int 2400a7c0060aSjmatthew bnxt_hwrm_err_map(uint16_t err) 2401a7c0060aSjmatthew { 2402a7c0060aSjmatthew int rc; 2403a7c0060aSjmatthew 2404a7c0060aSjmatthew switch (err) { 2405a7c0060aSjmatthew case HWRM_ERR_CODE_SUCCESS: 2406a7c0060aSjmatthew return 0; 2407a7c0060aSjmatthew case HWRM_ERR_CODE_INVALID_PARAMS: 2408a7c0060aSjmatthew case HWRM_ERR_CODE_INVALID_FLAGS: 2409a7c0060aSjmatthew case HWRM_ERR_CODE_INVALID_ENABLES: 2410a7c0060aSjmatthew return EINVAL; 2411a7c0060aSjmatthew case HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED: 2412a7c0060aSjmatthew return EACCES; 2413a7c0060aSjmatthew case HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR: 2414a7c0060aSjmatthew return ENOMEM; 2415a7c0060aSjmatthew case HWRM_ERR_CODE_CMD_NOT_SUPPORTED: 2416a7c0060aSjmatthew return ENOSYS; 2417a7c0060aSjmatthew case HWRM_ERR_CODE_FAIL: 2418a7c0060aSjmatthew return EIO; 2419a7c0060aSjmatthew case HWRM_ERR_CODE_HWRM_ERROR: 2420a7c0060aSjmatthew case HWRM_ERR_CODE_UNKNOWN_ERR: 2421a7c0060aSjmatthew default: 2422a7c0060aSjmatthew return EIO; 2423a7c0060aSjmatthew } 2424a7c0060aSjmatthew 2425a7c0060aSjmatthew return rc; 2426a7c0060aSjmatthew } 2427a7c0060aSjmatthew 24280c45b53cSjmatthew void 2429a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(struct bnxt_softc *softc, void *request, 2430a7c0060aSjmatthew uint16_t req_type) 2431a7c0060aSjmatthew { 2432a7c0060aSjmatthew struct input *req = request; 2433a7c0060aSjmatthew 2434a7c0060aSjmatthew req->req_type = htole16(req_type); 2435a7c0060aSjmatthew req->cmpl_ring = 0xffff; 2436a7c0060aSjmatthew req->target_id = 0xffff; 2437a7c0060aSjmatthew req->resp_addr = htole64(BNXT_DMA_DVA(softc->sc_cmd_resp)); 2438a7c0060aSjmatthew } 2439a7c0060aSjmatthew 24400c45b53cSjmatthew int 2441a7c0060aSjmatthew _hwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len) 2442a7c0060aSjmatthew { 2443a7c0060aSjmatthew struct input *req = msg; 2444a7c0060aSjmatthew struct hwrm_err_output *resp = BNXT_DMA_KVA(softc->sc_cmd_resp); 2445a7c0060aSjmatthew uint32_t *data = msg; 2446a7c0060aSjmatthew int i; 2447a7c0060aSjmatthew uint8_t *valid; 2448a7c0060aSjmatthew uint16_t err; 2449a7c0060aSjmatthew uint16_t max_req_len = HWRM_MAX_REQ_LEN; 2450a7c0060aSjmatthew struct hwrm_short_input short_input = {0}; 2451a7c0060aSjmatthew 2452a7c0060aSjmatthew /* TODO: DMASYNC in here. */ 2453a7c0060aSjmatthew req->seq_id = htole16(softc->sc_cmd_seq++); 2454a7c0060aSjmatthew memset(resp, 0, PAGE_SIZE); 2455a7c0060aSjmatthew 2456a7c0060aSjmatthew if (softc->sc_flags & BNXT_FLAG_SHORT_CMD) { 2457a7c0060aSjmatthew void *short_cmd_req = BNXT_DMA_KVA(softc->sc_cmd_resp); 2458a7c0060aSjmatthew 2459a7c0060aSjmatthew memcpy(short_cmd_req, req, msg_len); 2460a7c0060aSjmatthew memset((uint8_t *) short_cmd_req + msg_len, 0, 2461a7c0060aSjmatthew softc->sc_max_req_len - msg_len); 2462a7c0060aSjmatthew 2463a7c0060aSjmatthew short_input.req_type = req->req_type; 2464a7c0060aSjmatthew short_input.signature = 2465a7c0060aSjmatthew htole16(HWRM_SHORT_INPUT_SIGNATURE_SHORT_CMD); 2466a7c0060aSjmatthew short_input.size = htole16(msg_len); 2467a7c0060aSjmatthew short_input.req_addr = 2468a7c0060aSjmatthew htole64(BNXT_DMA_DVA(softc->sc_cmd_resp)); 2469a7c0060aSjmatthew 2470a7c0060aSjmatthew data = (uint32_t *)&short_input; 2471a7c0060aSjmatthew msg_len = sizeof(short_input); 2472a7c0060aSjmatthew 2473a7c0060aSjmatthew /* Sync memory write before updating doorbell */ 2474a7c0060aSjmatthew membar_sync(); 2475a7c0060aSjmatthew 2476a7c0060aSjmatthew max_req_len = BNXT_HWRM_SHORT_REQ_LEN; 2477a7c0060aSjmatthew } 2478a7c0060aSjmatthew 2479a7c0060aSjmatthew /* Write request msg to hwrm channel */ 2480a7c0060aSjmatthew for (i = 0; i < msg_len; i += 4) { 2481a7c0060aSjmatthew bus_space_write_4(softc->sc_hwrm_t, 2482a7c0060aSjmatthew softc->sc_hwrm_h, 2483a7c0060aSjmatthew i, *data); 2484a7c0060aSjmatthew data++; 2485a7c0060aSjmatthew } 2486a7c0060aSjmatthew 2487a7c0060aSjmatthew /* Clear to the end of the request buffer */ 2488a7c0060aSjmatthew for (i = msg_len; i < max_req_len; i += 4) 2489a7c0060aSjmatthew bus_space_write_4(softc->sc_hwrm_t, softc->sc_hwrm_h, 2490a7c0060aSjmatthew i, 0); 2491a7c0060aSjmatthew 2492a7c0060aSjmatthew /* Ring channel doorbell */ 2493a7c0060aSjmatthew bus_space_write_4(softc->sc_hwrm_t, softc->sc_hwrm_h, 0x100, 2494a7c0060aSjmatthew htole32(1)); 2495a7c0060aSjmatthew 2496a7c0060aSjmatthew /* Check if response len is updated */ 2497a7c0060aSjmatthew for (i = 0; i < softc->sc_cmd_timeo; i++) { 2498a7c0060aSjmatthew if (resp->resp_len && resp->resp_len <= 4096) 2499a7c0060aSjmatthew break; 2500a7c0060aSjmatthew DELAY(1000); 2501a7c0060aSjmatthew } 2502a7c0060aSjmatthew if (i >= softc->sc_cmd_timeo) { 2503a7c0060aSjmatthew printf("%s: timeout sending %s: (timeout: %u) seq: %d\n", 2504a7c0060aSjmatthew DEVNAME(softc), GET_HWRM_REQ_TYPE(req->req_type), 2505a7c0060aSjmatthew softc->sc_cmd_timeo, 2506a7c0060aSjmatthew le16toh(req->seq_id)); 2507a7c0060aSjmatthew return ETIMEDOUT; 2508a7c0060aSjmatthew } 2509a7c0060aSjmatthew /* Last byte of resp contains the valid key */ 2510a7c0060aSjmatthew valid = (uint8_t *)resp + resp->resp_len - 1; 2511a7c0060aSjmatthew for (i = 0; i < softc->sc_cmd_timeo; i++) { 2512a7c0060aSjmatthew if (*valid == HWRM_RESP_VALID_KEY) 2513a7c0060aSjmatthew break; 2514a7c0060aSjmatthew DELAY(1000); 2515a7c0060aSjmatthew } 2516a7c0060aSjmatthew if (i >= softc->sc_cmd_timeo) { 2517a7c0060aSjmatthew printf("%s: timeout sending %s: " 2518a7c0060aSjmatthew "(timeout: %u) msg {0x%x 0x%x} len:%d v: %d\n", 2519a7c0060aSjmatthew DEVNAME(softc), GET_HWRM_REQ_TYPE(req->req_type), 2520a7c0060aSjmatthew softc->sc_cmd_timeo, le16toh(req->req_type), 2521a7c0060aSjmatthew le16toh(req->seq_id), msg_len, 2522a7c0060aSjmatthew *valid); 2523a7c0060aSjmatthew return ETIMEDOUT; 2524a7c0060aSjmatthew } 2525a7c0060aSjmatthew 2526a7c0060aSjmatthew err = le16toh(resp->error_code); 2527a7c0060aSjmatthew if (err) { 2528a7c0060aSjmatthew /* HWRM_ERR_CODE_FAIL is a "normal" error, don't log */ 2529a7c0060aSjmatthew if (err != HWRM_ERR_CODE_FAIL) { 2530a7c0060aSjmatthew printf("%s: %s command returned %s error.\n", 2531a7c0060aSjmatthew DEVNAME(softc), 2532a7c0060aSjmatthew GET_HWRM_REQ_TYPE(req->req_type), 2533a7c0060aSjmatthew GET_HWRM_ERROR_CODE(err)); 2534a7c0060aSjmatthew } 2535a7c0060aSjmatthew return bnxt_hwrm_err_map(err); 2536a7c0060aSjmatthew } 2537a7c0060aSjmatthew 2538a7c0060aSjmatthew return 0; 2539a7c0060aSjmatthew } 2540a7c0060aSjmatthew 2541a7c0060aSjmatthew 25420c45b53cSjmatthew int 2543a7c0060aSjmatthew hwrm_send_message(struct bnxt_softc *softc, void *msg, uint32_t msg_len) 2544a7c0060aSjmatthew { 2545a7c0060aSjmatthew int rc; 2546a7c0060aSjmatthew 2547a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2548a7c0060aSjmatthew rc = _hwrm_send_message(softc, msg, msg_len); 2549a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2550a7c0060aSjmatthew return rc; 2551a7c0060aSjmatthew } 2552a7c0060aSjmatthew 2553a7c0060aSjmatthew 2554a7c0060aSjmatthew int 2555a7c0060aSjmatthew bnxt_hwrm_queue_qportcfg(struct bnxt_softc *softc) 2556a7c0060aSjmatthew { 2557a7c0060aSjmatthew struct hwrm_queue_qportcfg_input req = {0}; 2558a7c0060aSjmatthew struct hwrm_queue_qportcfg_output *resp = 2559a7c0060aSjmatthew BNXT_DMA_KVA(softc->sc_cmd_resp); 2560d460f6dcSjmatthew int rc = 0; 2561a7c0060aSjmatthew 2562a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_QPORTCFG); 2563a7c0060aSjmatthew 2564a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2565a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 2566a7c0060aSjmatthew if (rc) 2567a7c0060aSjmatthew goto qportcfg_exit; 2568a7c0060aSjmatthew 2569a7c0060aSjmatthew if (!resp->max_configurable_queues) { 2570a7c0060aSjmatthew rc = -EINVAL; 2571a7c0060aSjmatthew goto qportcfg_exit; 2572a7c0060aSjmatthew } 2573a7c0060aSjmatthew 2574d460f6dcSjmatthew softc->sc_tx_queue_id = resp->queue_id0; 2575a7c0060aSjmatthew 2576a7c0060aSjmatthew qportcfg_exit: 2577a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2578d256ca68Sjmatthew return rc; 2579a7c0060aSjmatthew } 2580a7c0060aSjmatthew 2581a7c0060aSjmatthew int 2582a7c0060aSjmatthew bnxt_hwrm_ver_get(struct bnxt_softc *softc) 2583a7c0060aSjmatthew { 2584a7c0060aSjmatthew struct hwrm_ver_get_input req = {0}; 2585a7c0060aSjmatthew struct hwrm_ver_get_output *resp = 2586a7c0060aSjmatthew BNXT_DMA_KVA(softc->sc_cmd_resp); 2587a7c0060aSjmatthew int rc; 2588a7c0060aSjmatthew #if 0 2589a7c0060aSjmatthew const char nastr[] = "<not installed>"; 2590a7c0060aSjmatthew const char naver[] = "<N/A>"; 2591a7c0060aSjmatthew #endif 2592a7c0060aSjmatthew uint32_t dev_caps_cfg; 2593a7c0060aSjmatthew 2594a7c0060aSjmatthew softc->sc_max_req_len = HWRM_MAX_REQ_LEN; 2595a7c0060aSjmatthew softc->sc_cmd_timeo = 1000; 2596a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VER_GET); 2597a7c0060aSjmatthew 2598a7c0060aSjmatthew req.hwrm_intf_maj = HWRM_VERSION_MAJOR; 2599a7c0060aSjmatthew req.hwrm_intf_min = HWRM_VERSION_MINOR; 2600a7c0060aSjmatthew req.hwrm_intf_upd = HWRM_VERSION_UPDATE; 2601a7c0060aSjmatthew 2602a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2603a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 2604a7c0060aSjmatthew if (rc) 2605a7c0060aSjmatthew goto fail; 2606a7c0060aSjmatthew 2607a7c0060aSjmatthew printf(": fw ver %d.%d.%d, ", resp->hwrm_fw_maj, resp->hwrm_fw_min, 2608a7c0060aSjmatthew resp->hwrm_fw_bld); 260992586e53Sjmatthew 261092586e53Sjmatthew softc->sc_hwrm_ver = (resp->hwrm_intf_maj << 16) | 261192586e53Sjmatthew (resp->hwrm_intf_min << 8) | resp->hwrm_intf_upd; 2612a7c0060aSjmatthew #if 0 2613a7c0060aSjmatthew snprintf(softc->ver_info->hwrm_if_ver, BNXT_VERSTR_SIZE, "%d.%d.%d", 2614a7c0060aSjmatthew resp->hwrm_intf_maj, resp->hwrm_intf_min, resp->hwrm_intf_upd); 2615a7c0060aSjmatthew softc->ver_info->hwrm_if_major = resp->hwrm_intf_maj; 2616a7c0060aSjmatthew softc->ver_info->hwrm_if_minor = resp->hwrm_intf_min; 2617a7c0060aSjmatthew softc->ver_info->hwrm_if_update = resp->hwrm_intf_upd; 2618a7c0060aSjmatthew snprintf(softc->ver_info->hwrm_fw_ver, BNXT_VERSTR_SIZE, "%d.%d.%d", 2619a7c0060aSjmatthew resp->hwrm_fw_maj, resp->hwrm_fw_min, resp->hwrm_fw_bld); 2620a7c0060aSjmatthew strlcpy(softc->ver_info->driver_hwrm_if_ver, HWRM_VERSION_STR, 2621a7c0060aSjmatthew BNXT_VERSTR_SIZE); 2622a7c0060aSjmatthew strlcpy(softc->ver_info->hwrm_fw_name, resp->hwrm_fw_name, 2623a7c0060aSjmatthew BNXT_NAME_SIZE); 2624a7c0060aSjmatthew 2625a7c0060aSjmatthew if (resp->mgmt_fw_maj == 0 && resp->mgmt_fw_min == 0 && 2626a7c0060aSjmatthew resp->mgmt_fw_bld == 0) { 2627a7c0060aSjmatthew strlcpy(softc->ver_info->mgmt_fw_ver, naver, BNXT_VERSTR_SIZE); 2628a7c0060aSjmatthew strlcpy(softc->ver_info->mgmt_fw_name, nastr, BNXT_NAME_SIZE); 2629a7c0060aSjmatthew } 2630a7c0060aSjmatthew else { 2631a7c0060aSjmatthew snprintf(softc->ver_info->mgmt_fw_ver, BNXT_VERSTR_SIZE, 2632a7c0060aSjmatthew "%d.%d.%d", resp->mgmt_fw_maj, resp->mgmt_fw_min, 2633a7c0060aSjmatthew resp->mgmt_fw_bld); 2634a7c0060aSjmatthew strlcpy(softc->ver_info->mgmt_fw_name, resp->mgmt_fw_name, 2635a7c0060aSjmatthew BNXT_NAME_SIZE); 2636a7c0060aSjmatthew } 2637a7c0060aSjmatthew if (resp->netctrl_fw_maj == 0 && resp->netctrl_fw_min == 0 && 2638a7c0060aSjmatthew resp->netctrl_fw_bld == 0) { 2639a7c0060aSjmatthew strlcpy(softc->ver_info->netctrl_fw_ver, naver, 2640a7c0060aSjmatthew BNXT_VERSTR_SIZE); 2641a7c0060aSjmatthew strlcpy(softc->ver_info->netctrl_fw_name, nastr, 2642a7c0060aSjmatthew BNXT_NAME_SIZE); 2643a7c0060aSjmatthew } 2644a7c0060aSjmatthew else { 2645a7c0060aSjmatthew snprintf(softc->ver_info->netctrl_fw_ver, BNXT_VERSTR_SIZE, 2646a7c0060aSjmatthew "%d.%d.%d", resp->netctrl_fw_maj, resp->netctrl_fw_min, 2647a7c0060aSjmatthew resp->netctrl_fw_bld); 2648a7c0060aSjmatthew strlcpy(softc->ver_info->netctrl_fw_name, resp->netctrl_fw_name, 2649a7c0060aSjmatthew BNXT_NAME_SIZE); 2650a7c0060aSjmatthew } 2651a7c0060aSjmatthew if (resp->roce_fw_maj == 0 && resp->roce_fw_min == 0 && 2652a7c0060aSjmatthew resp->roce_fw_bld == 0) { 2653a7c0060aSjmatthew strlcpy(softc->ver_info->roce_fw_ver, naver, BNXT_VERSTR_SIZE); 2654a7c0060aSjmatthew strlcpy(softc->ver_info->roce_fw_name, nastr, BNXT_NAME_SIZE); 2655a7c0060aSjmatthew } 2656a7c0060aSjmatthew else { 2657a7c0060aSjmatthew snprintf(softc->ver_info->roce_fw_ver, BNXT_VERSTR_SIZE, 2658a7c0060aSjmatthew "%d.%d.%d", resp->roce_fw_maj, resp->roce_fw_min, 2659a7c0060aSjmatthew resp->roce_fw_bld); 2660a7c0060aSjmatthew strlcpy(softc->ver_info->roce_fw_name, resp->roce_fw_name, 2661a7c0060aSjmatthew BNXT_NAME_SIZE); 2662a7c0060aSjmatthew } 2663a7c0060aSjmatthew softc->ver_info->chip_num = le16toh(resp->chip_num); 2664a7c0060aSjmatthew softc->ver_info->chip_rev = resp->chip_rev; 2665a7c0060aSjmatthew softc->ver_info->chip_metal = resp->chip_metal; 2666a7c0060aSjmatthew softc->ver_info->chip_bond_id = resp->chip_bond_id; 2667a7c0060aSjmatthew softc->ver_info->chip_type = resp->chip_platform_type; 2668a7c0060aSjmatthew #endif 2669a7c0060aSjmatthew 2670a7c0060aSjmatthew if (resp->max_req_win_len) 2671a7c0060aSjmatthew softc->sc_max_req_len = le16toh(resp->max_req_win_len); 2672a7c0060aSjmatthew if (resp->def_req_timeout) 2673a7c0060aSjmatthew softc->sc_cmd_timeo = le16toh(resp->def_req_timeout); 2674a7c0060aSjmatthew 2675a7c0060aSjmatthew dev_caps_cfg = le32toh(resp->dev_caps_cfg); 2676a7c0060aSjmatthew if ((dev_caps_cfg & HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED) && 2677a7c0060aSjmatthew (dev_caps_cfg & HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_REQUIRED)) 2678a7c0060aSjmatthew softc->sc_flags |= BNXT_FLAG_SHORT_CMD; 2679a7c0060aSjmatthew 2680a7c0060aSjmatthew fail: 2681a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2682a7c0060aSjmatthew return rc; 2683a7c0060aSjmatthew } 2684a7c0060aSjmatthew 2685a7c0060aSjmatthew 2686a7c0060aSjmatthew int 2687a7c0060aSjmatthew bnxt_hwrm_func_drv_rgtr(struct bnxt_softc *softc) 2688a7c0060aSjmatthew { 2689a7c0060aSjmatthew struct hwrm_func_drv_rgtr_input req = {0}; 2690a7c0060aSjmatthew 2691a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR); 2692a7c0060aSjmatthew 2693a7c0060aSjmatthew req.enables = htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_VER | 2694a7c0060aSjmatthew HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_OS_TYPE); 2695a7c0060aSjmatthew req.os_type = htole16(HWRM_FUNC_DRV_RGTR_INPUT_OS_TYPE_FREEBSD); 2696a7c0060aSjmatthew 2697a7c0060aSjmatthew req.ver_maj = 6; 2698a7c0060aSjmatthew req.ver_min = 4; 2699a7c0060aSjmatthew req.ver_upd = 0; 2700a7c0060aSjmatthew 2701a7c0060aSjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 2702a7c0060aSjmatthew } 2703a7c0060aSjmatthew 2704a7c0060aSjmatthew #if 0 2705a7c0060aSjmatthew 2706a7c0060aSjmatthew int 2707a7c0060aSjmatthew bnxt_hwrm_func_drv_unrgtr(struct bnxt_softc *softc, bool shutdown) 2708a7c0060aSjmatthew { 2709a7c0060aSjmatthew struct hwrm_func_drv_unrgtr_input req = {0}; 2710a7c0060aSjmatthew 2711a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_UNRGTR); 2712a7c0060aSjmatthew if (shutdown == true) 2713a7c0060aSjmatthew req.flags |= 2714a7c0060aSjmatthew HWRM_FUNC_DRV_UNRGTR_INPUT_FLAGS_PREPARE_FOR_SHUTDOWN; 2715a7c0060aSjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 2716a7c0060aSjmatthew } 2717a7c0060aSjmatthew 2718a7c0060aSjmatthew #endif 2719a7c0060aSjmatthew 2720a7c0060aSjmatthew int 2721a7c0060aSjmatthew bnxt_hwrm_func_qcaps(struct bnxt_softc *softc) 2722a7c0060aSjmatthew { 2723a7c0060aSjmatthew int rc = 0; 2724a7c0060aSjmatthew struct hwrm_func_qcaps_input req = {0}; 2725a7c0060aSjmatthew struct hwrm_func_qcaps_output *resp = 2726a7c0060aSjmatthew BNXT_DMA_KVA(softc->sc_cmd_resp); 2727a7c0060aSjmatthew /* struct bnxt_func_info *func = &softc->func; */ 2728a7c0060aSjmatthew 2729a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCAPS); 2730a7c0060aSjmatthew req.fid = htole16(0xffff); 2731a7c0060aSjmatthew 2732a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2733a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 2734a7c0060aSjmatthew if (rc) 2735a7c0060aSjmatthew goto fail; 2736a7c0060aSjmatthew 2737a7c0060aSjmatthew if (resp->flags & 2738a7c0060aSjmatthew htole32(HWRM_FUNC_QCAPS_OUTPUT_FLAGS_WOL_MAGICPKT_SUPPORTED)) 2739a7c0060aSjmatthew softc->sc_flags |= BNXT_FLAG_WOL_CAP; 2740a7c0060aSjmatthew 2741a7c0060aSjmatthew memcpy(softc->sc_ac.ac_enaddr, resp->mac_address, 6); 2742a7c0060aSjmatthew /* 2743a7c0060aSjmatthew func->fw_fid = le16toh(resp->fid); 2744a7c0060aSjmatthew memcpy(func->mac_addr, resp->mac_address, ETHER_ADDR_LEN); 2745a7c0060aSjmatthew func->max_rsscos_ctxs = le16toh(resp->max_rsscos_ctx); 2746a7c0060aSjmatthew func->max_cp_rings = le16toh(resp->max_cmpl_rings); 2747a7c0060aSjmatthew func->max_tx_rings = le16toh(resp->max_tx_rings); 2748a7c0060aSjmatthew func->max_rx_rings = le16toh(resp->max_rx_rings); 2749a7c0060aSjmatthew func->max_hw_ring_grps = le32toh(resp->max_hw_ring_grps); 2750a7c0060aSjmatthew if (!func->max_hw_ring_grps) 2751a7c0060aSjmatthew func->max_hw_ring_grps = func->max_tx_rings; 2752a7c0060aSjmatthew func->max_l2_ctxs = le16toh(resp->max_l2_ctxs); 2753a7c0060aSjmatthew func->max_vnics = le16toh(resp->max_vnics); 2754a7c0060aSjmatthew func->max_stat_ctxs = le16toh(resp->max_stat_ctx); 2755a7c0060aSjmatthew if (BNXT_PF(softc)) { 2756a7c0060aSjmatthew struct bnxt_pf_info *pf = &softc->pf; 2757a7c0060aSjmatthew 2758a7c0060aSjmatthew pf->port_id = le16toh(resp->port_id); 2759a7c0060aSjmatthew pf->first_vf_id = le16toh(resp->first_vf_id); 2760a7c0060aSjmatthew pf->max_vfs = le16toh(resp->max_vfs); 2761a7c0060aSjmatthew pf->max_encap_records = le32toh(resp->max_encap_records); 2762a7c0060aSjmatthew pf->max_decap_records = le32toh(resp->max_decap_records); 2763a7c0060aSjmatthew pf->max_tx_em_flows = le32toh(resp->max_tx_em_flows); 2764a7c0060aSjmatthew pf->max_tx_wm_flows = le32toh(resp->max_tx_wm_flows); 2765a7c0060aSjmatthew pf->max_rx_em_flows = le32toh(resp->max_rx_em_flows); 2766a7c0060aSjmatthew pf->max_rx_wm_flows = le32toh(resp->max_rx_wm_flows); 2767a7c0060aSjmatthew } 2768a7c0060aSjmatthew if (!_is_valid_ether_addr(func->mac_addr)) { 2769a7c0060aSjmatthew device_printf(softc->dev, "Invalid ethernet address, generating random locally administered address\n"); 2770a7c0060aSjmatthew get_random_ether_addr(func->mac_addr); 2771a7c0060aSjmatthew } 2772a7c0060aSjmatthew */ 2773a7c0060aSjmatthew 2774a7c0060aSjmatthew fail: 2775a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2776a7c0060aSjmatthew return rc; 2777a7c0060aSjmatthew } 2778a7c0060aSjmatthew 2779a7c0060aSjmatthew 2780a7c0060aSjmatthew int 2781a7c0060aSjmatthew bnxt_hwrm_func_qcfg(struct bnxt_softc *softc) 2782a7c0060aSjmatthew { 2783a7c0060aSjmatthew struct hwrm_func_qcfg_input req = {0}; 2784a7c0060aSjmatthew /* struct hwrm_func_qcfg_output *resp = 2785a7c0060aSjmatthew BNXT_DMA_KVA(softc->sc_cmd_resp); 2786a7c0060aSjmatthew struct bnxt_func_qcfg *fn_qcfg = &softc->fn_qcfg; */ 2787a7c0060aSjmatthew int rc; 2788a7c0060aSjmatthew 2789a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCFG); 2790a7c0060aSjmatthew req.fid = htole16(0xffff); 2791a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2792a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 2793a7c0060aSjmatthew if (rc) 2794a7c0060aSjmatthew goto fail; 2795a7c0060aSjmatthew 2796a7c0060aSjmatthew /* 2797a7c0060aSjmatthew fn_qcfg->alloc_completion_rings = le16toh(resp->alloc_cmpl_rings); 2798a7c0060aSjmatthew fn_qcfg->alloc_tx_rings = le16toh(resp->alloc_tx_rings); 2799a7c0060aSjmatthew fn_qcfg->alloc_rx_rings = le16toh(resp->alloc_rx_rings); 2800a7c0060aSjmatthew fn_qcfg->alloc_vnics = le16toh(resp->alloc_vnics); 2801a7c0060aSjmatthew */ 2802a7c0060aSjmatthew fail: 2803a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2804a7c0060aSjmatthew return rc; 2805a7c0060aSjmatthew } 2806a7c0060aSjmatthew 2807a7c0060aSjmatthew 2808a7c0060aSjmatthew int 2809a7c0060aSjmatthew bnxt_hwrm_func_reset(struct bnxt_softc *softc) 2810a7c0060aSjmatthew { 2811a7c0060aSjmatthew struct hwrm_func_reset_input req = {0}; 2812a7c0060aSjmatthew 2813a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_RESET); 2814a7c0060aSjmatthew req.enables = 0; 2815a7c0060aSjmatthew 2816a7c0060aSjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 2817a7c0060aSjmatthew } 2818a7c0060aSjmatthew 2819a7c0060aSjmatthew int 2820c4f53494Sjmatthew bnxt_hwrm_vnic_cfg_placement(struct bnxt_softc *softc, 2821c4f53494Sjmatthew struct bnxt_vnic_info *vnic) 2822c4f53494Sjmatthew { 2823c4f53494Sjmatthew struct hwrm_vnic_plcmodes_cfg_input req = {0}; 2824c4f53494Sjmatthew 2825c4f53494Sjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_PLCMODES_CFG); 2826c4f53494Sjmatthew 2827c4f53494Sjmatthew req.flags = htole32( 2828c4f53494Sjmatthew HWRM_VNIC_PLCMODES_CFG_INPUT_FLAGS_JUMBO_PLACEMENT); 2829c4f53494Sjmatthew req.enables = htole32( 2830c4f53494Sjmatthew HWRM_VNIC_PLCMODES_CFG_INPUT_ENABLES_JUMBO_THRESH_VALID); 2831c4f53494Sjmatthew req.vnic_id = htole16(vnic->id); 2832c4f53494Sjmatthew req.jumbo_thresh = htole16(MCLBYTES); 2833c4f53494Sjmatthew 2834c4f53494Sjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 2835c4f53494Sjmatthew } 2836c4f53494Sjmatthew 2837c4f53494Sjmatthew int 2838a7c0060aSjmatthew bnxt_hwrm_vnic_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic) 2839a7c0060aSjmatthew { 2840a7c0060aSjmatthew struct hwrm_vnic_cfg_input req = {0}; 2841a7c0060aSjmatthew 2842a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_CFG); 2843a7c0060aSjmatthew 2844a7c0060aSjmatthew if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT) 2845a7c0060aSjmatthew req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_DEFAULT); 2846a7c0060aSjmatthew if (vnic->flags & BNXT_VNIC_FLAG_BD_STALL) 2847a7c0060aSjmatthew req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_BD_STALL_MODE); 2848a7c0060aSjmatthew if (vnic->flags & BNXT_VNIC_FLAG_VLAN_STRIP) 2849a7c0060aSjmatthew req.flags |= htole32(HWRM_VNIC_CFG_INPUT_FLAGS_VLAN_STRIP_MODE); 2850a7c0060aSjmatthew req.enables = htole32(HWRM_VNIC_CFG_INPUT_ENABLES_DFLT_RING_GRP | 2851a7c0060aSjmatthew HWRM_VNIC_CFG_INPUT_ENABLES_RSS_RULE | 2852a7c0060aSjmatthew HWRM_VNIC_CFG_INPUT_ENABLES_MRU); 2853a7c0060aSjmatthew req.vnic_id = htole16(vnic->id); 2854a7c0060aSjmatthew req.dflt_ring_grp = htole16(vnic->def_ring_grp); 2855a7c0060aSjmatthew req.rss_rule = htole16(vnic->rss_id); 2856a7c0060aSjmatthew req.cos_rule = htole16(vnic->cos_rule); 2857a7c0060aSjmatthew req.lb_rule = htole16(vnic->lb_rule); 2858a7c0060aSjmatthew req.mru = htole16(vnic->mru); 2859a7c0060aSjmatthew 2860a7c0060aSjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 2861a7c0060aSjmatthew } 2862a7c0060aSjmatthew 2863a7c0060aSjmatthew int 2864a7c0060aSjmatthew bnxt_hwrm_vnic_alloc(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic) 2865a7c0060aSjmatthew { 2866a7c0060aSjmatthew struct hwrm_vnic_alloc_input req = {0}; 2867a7c0060aSjmatthew struct hwrm_vnic_alloc_output *resp = 2868a7c0060aSjmatthew BNXT_DMA_KVA(softc->sc_cmd_resp); 2869a7c0060aSjmatthew int rc; 2870a7c0060aSjmatthew 2871a7c0060aSjmatthew if (vnic->id != (uint16_t)HWRM_NA_SIGNATURE) { 2872a7c0060aSjmatthew printf("%s: attempt to re-allocate vnic %04x\n", 2873a7c0060aSjmatthew DEVNAME(softc), vnic->id); 2874a7c0060aSjmatthew return EINVAL; 2875a7c0060aSjmatthew } 2876a7c0060aSjmatthew 2877a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_ALLOC); 2878a7c0060aSjmatthew 2879a7c0060aSjmatthew if (vnic->flags & BNXT_VNIC_FLAG_DEFAULT) 2880a7c0060aSjmatthew req.flags = htole32(HWRM_VNIC_ALLOC_INPUT_FLAGS_DEFAULT); 2881a7c0060aSjmatthew 2882a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2883a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 2884a7c0060aSjmatthew if (rc) 2885a7c0060aSjmatthew goto fail; 2886a7c0060aSjmatthew 2887a7c0060aSjmatthew vnic->id = le32toh(resp->vnic_id); 2888a7c0060aSjmatthew 2889a7c0060aSjmatthew fail: 2890a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2891d256ca68Sjmatthew return rc; 2892a7c0060aSjmatthew } 2893a7c0060aSjmatthew 2894a7c0060aSjmatthew int 2895a7c0060aSjmatthew bnxt_hwrm_vnic_free(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic) 2896a7c0060aSjmatthew { 2897a7c0060aSjmatthew struct hwrm_vnic_free_input req = {0}; 2898a7c0060aSjmatthew int rc; 2899a7c0060aSjmatthew 2900a7c0060aSjmatthew if (vnic->id == (uint16_t)HWRM_NA_SIGNATURE) { 2901a7c0060aSjmatthew printf("%s: attempt to deallocate vnic %04x\n", 2902a7c0060aSjmatthew DEVNAME(softc), vnic->id); 2903a7c0060aSjmatthew return (EINVAL); 2904a7c0060aSjmatthew } 2905a7c0060aSjmatthew 2906a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_FREE); 2907a7c0060aSjmatthew req.vnic_id = htole16(vnic->id); 2908a7c0060aSjmatthew 2909a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2910a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 2911a7c0060aSjmatthew if (rc == 0) 2912a7c0060aSjmatthew vnic->id = (uint16_t)HWRM_NA_SIGNATURE; 2913a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2914a7c0060aSjmatthew 2915a7c0060aSjmatthew return (rc); 2916a7c0060aSjmatthew } 2917a7c0060aSjmatthew 2918a7c0060aSjmatthew int 2919a7c0060aSjmatthew bnxt_hwrm_vnic_ctx_alloc(struct bnxt_softc *softc, uint16_t *ctx_id) 2920a7c0060aSjmatthew { 2921a7c0060aSjmatthew struct hwrm_vnic_rss_cos_lb_ctx_alloc_input req = {0}; 2922a7c0060aSjmatthew struct hwrm_vnic_rss_cos_lb_ctx_alloc_output *resp = 2923a7c0060aSjmatthew BNXT_DMA_KVA(softc->sc_cmd_resp); 2924a7c0060aSjmatthew int rc; 2925a7c0060aSjmatthew 2926a7c0060aSjmatthew if (*ctx_id != (uint16_t)HWRM_NA_SIGNATURE) { 2927a7c0060aSjmatthew printf("%s: attempt to re-allocate vnic ctx %04x\n", 2928a7c0060aSjmatthew DEVNAME(softc), *ctx_id); 2929a7c0060aSjmatthew return EINVAL; 2930a7c0060aSjmatthew } 2931a7c0060aSjmatthew 2932a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_COS_LB_CTX_ALLOC); 2933a7c0060aSjmatthew 2934a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2935a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 2936a7c0060aSjmatthew if (rc) 2937a7c0060aSjmatthew goto fail; 2938a7c0060aSjmatthew 2939a7c0060aSjmatthew *ctx_id = letoh16(resp->rss_cos_lb_ctx_id); 2940a7c0060aSjmatthew 2941a7c0060aSjmatthew fail: 2942a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2943a7c0060aSjmatthew return (rc); 2944a7c0060aSjmatthew } 2945a7c0060aSjmatthew 2946a7c0060aSjmatthew int 2947a7c0060aSjmatthew bnxt_hwrm_vnic_ctx_free(struct bnxt_softc *softc, uint16_t *ctx_id) 2948a7c0060aSjmatthew { 2949a7c0060aSjmatthew struct hwrm_vnic_rss_cos_lb_ctx_free_input req = {0}; 2950a7c0060aSjmatthew int rc; 2951a7c0060aSjmatthew 2952a7c0060aSjmatthew if (*ctx_id == (uint16_t)HWRM_NA_SIGNATURE) { 2953a7c0060aSjmatthew printf("%s: attempt to deallocate vnic ctx %04x\n", 2954a7c0060aSjmatthew DEVNAME(softc), *ctx_id); 2955a7c0060aSjmatthew return (EINVAL); 2956a7c0060aSjmatthew } 2957a7c0060aSjmatthew 2958a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_COS_LB_CTX_FREE); 2959a7c0060aSjmatthew req.rss_cos_lb_ctx_id = htole32(*ctx_id); 2960a7c0060aSjmatthew 2961a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2962a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 2963a7c0060aSjmatthew if (rc == 0) 2964a7c0060aSjmatthew *ctx_id = (uint16_t)HWRM_NA_SIGNATURE; 2965a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2966a7c0060aSjmatthew return (rc); 2967a7c0060aSjmatthew } 2968a7c0060aSjmatthew 2969a7c0060aSjmatthew int 2970a7c0060aSjmatthew bnxt_hwrm_ring_grp_alloc(struct bnxt_softc *softc, struct bnxt_grp_info *grp) 2971a7c0060aSjmatthew { 2972a7c0060aSjmatthew struct hwrm_ring_grp_alloc_input req = {0}; 2973a7c0060aSjmatthew struct hwrm_ring_grp_alloc_output *resp; 2974a7c0060aSjmatthew int rc = 0; 2975a7c0060aSjmatthew 2976a7c0060aSjmatthew if (grp->grp_id != HWRM_NA_SIGNATURE) { 2977a7c0060aSjmatthew printf("%s: attempt to re-allocate ring group %04x\n", 2978a7c0060aSjmatthew DEVNAME(softc), grp->grp_id); 2979a7c0060aSjmatthew return EINVAL; 2980a7c0060aSjmatthew } 2981a7c0060aSjmatthew 2982a7c0060aSjmatthew resp = BNXT_DMA_KVA(softc->sc_cmd_resp); 2983a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_GRP_ALLOC); 2984a7c0060aSjmatthew req.cr = htole16(grp->cp_ring_id); 2985a7c0060aSjmatthew req.rr = htole16(grp->rx_ring_id); 2986a7c0060aSjmatthew req.ar = htole16(grp->ag_ring_id); 2987a7c0060aSjmatthew req.sc = htole16(grp->stats_ctx); 2988a7c0060aSjmatthew 2989a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 2990a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 2991a7c0060aSjmatthew if (rc) 2992a7c0060aSjmatthew goto fail; 2993a7c0060aSjmatthew 2994a7c0060aSjmatthew grp->grp_id = letoh32(resp->ring_group_id); 2995a7c0060aSjmatthew 2996a7c0060aSjmatthew fail: 2997a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 2998a7c0060aSjmatthew return rc; 2999a7c0060aSjmatthew } 3000a7c0060aSjmatthew 3001a7c0060aSjmatthew int 3002a7c0060aSjmatthew bnxt_hwrm_ring_grp_free(struct bnxt_softc *softc, struct bnxt_grp_info *grp) 3003a7c0060aSjmatthew { 3004a7c0060aSjmatthew struct hwrm_ring_grp_free_input req = {0}; 3005a7c0060aSjmatthew int rc = 0; 3006a7c0060aSjmatthew 3007a7c0060aSjmatthew if (grp->grp_id == HWRM_NA_SIGNATURE) { 3008a7c0060aSjmatthew printf("%s: attempt to free ring group %04x\n", 3009a7c0060aSjmatthew DEVNAME(softc), grp->grp_id); 3010a7c0060aSjmatthew return EINVAL; 3011a7c0060aSjmatthew } 3012a7c0060aSjmatthew 3013a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_GRP_FREE); 3014a7c0060aSjmatthew req.ring_group_id = htole32(grp->grp_id); 3015a7c0060aSjmatthew 3016a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3017a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3018a7c0060aSjmatthew if (rc == 0) 3019a7c0060aSjmatthew grp->grp_id = HWRM_NA_SIGNATURE; 3020a7c0060aSjmatthew 3021a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3022a7c0060aSjmatthew return (rc); 3023a7c0060aSjmatthew } 3024a7c0060aSjmatthew 3025a7c0060aSjmatthew /* 3026a7c0060aSjmatthew * Ring allocation message to the firmware 3027a7c0060aSjmatthew */ 3028a7c0060aSjmatthew int 3029a7c0060aSjmatthew bnxt_hwrm_ring_alloc(struct bnxt_softc *softc, uint8_t type, 3030a7c0060aSjmatthew struct bnxt_ring *ring, uint16_t cmpl_ring_id, uint32_t stat_ctx_id, 3031a7c0060aSjmatthew int irq) 3032a7c0060aSjmatthew { 3033a7c0060aSjmatthew struct hwrm_ring_alloc_input req = {0}; 3034a7c0060aSjmatthew struct hwrm_ring_alloc_output *resp; 3035a7c0060aSjmatthew int rc; 3036a7c0060aSjmatthew 3037a7c0060aSjmatthew if (ring->phys_id != (uint16_t)HWRM_NA_SIGNATURE) { 3038a7c0060aSjmatthew printf("%s: attempt to re-allocate ring %04x\n", 3039a7c0060aSjmatthew DEVNAME(softc), ring->phys_id); 3040a7c0060aSjmatthew return EINVAL; 3041a7c0060aSjmatthew } 3042a7c0060aSjmatthew 3043a7c0060aSjmatthew resp = BNXT_DMA_KVA(softc->sc_cmd_resp); 3044a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_ALLOC); 3045a7c0060aSjmatthew req.enables = htole32(0); 3046a7c0060aSjmatthew req.fbo = htole32(0); 3047a7c0060aSjmatthew 3048a7c0060aSjmatthew if (stat_ctx_id != HWRM_NA_SIGNATURE) { 3049a7c0060aSjmatthew req.enables |= htole32( 3050a7c0060aSjmatthew HWRM_RING_ALLOC_INPUT_ENABLES_STAT_CTX_ID_VALID); 3051a7c0060aSjmatthew req.stat_ctx_id = htole32(stat_ctx_id); 3052a7c0060aSjmatthew } 3053a7c0060aSjmatthew req.ring_type = type; 3054a7c0060aSjmatthew req.page_tbl_addr = htole64(ring->paddr); 3055a7c0060aSjmatthew req.length = htole32(ring->ring_size); 3056a7c0060aSjmatthew req.logical_id = htole16(ring->id); 3057a7c0060aSjmatthew req.cmpl_ring_id = htole16(cmpl_ring_id); 3058d460f6dcSjmatthew req.queue_id = htole16(softc->sc_tx_queue_id); 305961ed761cSsf req.int_mode = (softc->sc_flags & BNXT_FLAG_MSIX) ? 306061ed761cSsf HWRM_RING_ALLOC_INPUT_INT_MODE_MSIX : 306161ed761cSsf HWRM_RING_ALLOC_INPUT_INT_MODE_LEGACY; 3062a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3063a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3064a7c0060aSjmatthew if (rc) 3065a7c0060aSjmatthew goto fail; 3066a7c0060aSjmatthew 3067a7c0060aSjmatthew ring->phys_id = le16toh(resp->ring_id); 3068a7c0060aSjmatthew 3069a7c0060aSjmatthew fail: 3070a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3071a7c0060aSjmatthew return rc; 3072a7c0060aSjmatthew } 3073a7c0060aSjmatthew 3074a7c0060aSjmatthew int 3075a7c0060aSjmatthew bnxt_hwrm_ring_free(struct bnxt_softc *softc, uint8_t type, struct bnxt_ring *ring) 3076a7c0060aSjmatthew { 3077a7c0060aSjmatthew struct hwrm_ring_free_input req = {0}; 3078a7c0060aSjmatthew int rc; 3079a7c0060aSjmatthew 3080a7c0060aSjmatthew if (ring->phys_id == (uint16_t)HWRM_NA_SIGNATURE) { 3081a7c0060aSjmatthew printf("%s: attempt to deallocate ring %04x\n", 3082a7c0060aSjmatthew DEVNAME(softc), ring->phys_id); 3083a7c0060aSjmatthew return (EINVAL); 3084a7c0060aSjmatthew } 3085a7c0060aSjmatthew 3086a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_RING_FREE); 3087a7c0060aSjmatthew req.ring_type = type; 3088a7c0060aSjmatthew req.ring_id = htole16(ring->phys_id); 3089a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3090a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3091a7c0060aSjmatthew if (rc) 3092a7c0060aSjmatthew goto fail; 3093a7c0060aSjmatthew 3094a7c0060aSjmatthew ring->phys_id = (uint16_t)HWRM_NA_SIGNATURE; 3095a7c0060aSjmatthew fail: 3096a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3097a7c0060aSjmatthew return (rc); 3098a7c0060aSjmatthew } 3099a7c0060aSjmatthew 3100a7c0060aSjmatthew 3101a7c0060aSjmatthew int 3102a7c0060aSjmatthew bnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr, 3103a7c0060aSjmatthew uint64_t paddr) 3104a7c0060aSjmatthew { 3105a7c0060aSjmatthew struct hwrm_stat_ctx_alloc_input req = {0}; 3106a7c0060aSjmatthew struct hwrm_stat_ctx_alloc_output *resp; 3107a7c0060aSjmatthew int rc = 0; 3108a7c0060aSjmatthew 3109a7c0060aSjmatthew if (cpr->stats_ctx_id != HWRM_NA_SIGNATURE) { 3110a7c0060aSjmatthew printf("%s: attempt to re-allocate stats ctx %08x\n", 3111a7c0060aSjmatthew DEVNAME(softc), cpr->stats_ctx_id); 3112a7c0060aSjmatthew return EINVAL; 3113a7c0060aSjmatthew } 3114a7c0060aSjmatthew 3115a7c0060aSjmatthew resp = BNXT_DMA_KVA(softc->sc_cmd_resp); 3116a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_STAT_CTX_ALLOC); 3117a7c0060aSjmatthew 3118a7c0060aSjmatthew req.update_period_ms = htole32(1000); 3119a7c0060aSjmatthew req.stats_dma_addr = htole64(paddr); 3120a7c0060aSjmatthew 3121a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3122a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3123a7c0060aSjmatthew if (rc) 3124a7c0060aSjmatthew goto fail; 3125a7c0060aSjmatthew 3126a7c0060aSjmatthew cpr->stats_ctx_id = le32toh(resp->stat_ctx_id); 3127a7c0060aSjmatthew 3128a7c0060aSjmatthew fail: 3129a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3130a7c0060aSjmatthew 3131a7c0060aSjmatthew return rc; 3132a7c0060aSjmatthew } 3133a7c0060aSjmatthew 3134a7c0060aSjmatthew int 3135a7c0060aSjmatthew bnxt_hwrm_stat_ctx_free(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr) 3136a7c0060aSjmatthew { 3137a7c0060aSjmatthew struct hwrm_stat_ctx_free_input req = {0}; 3138a7c0060aSjmatthew int rc = 0; 3139a7c0060aSjmatthew 3140a7c0060aSjmatthew if (cpr->stats_ctx_id == HWRM_NA_SIGNATURE) { 3141a7c0060aSjmatthew printf("%s: attempt to free stats ctx %08x\n", 3142a7c0060aSjmatthew DEVNAME(softc), cpr->stats_ctx_id); 3143a7c0060aSjmatthew return EINVAL; 3144a7c0060aSjmatthew } 3145a7c0060aSjmatthew 3146a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_STAT_CTX_FREE); 3147a7c0060aSjmatthew req.stat_ctx_id = htole32(cpr->stats_ctx_id); 3148a7c0060aSjmatthew 3149a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3150a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3151a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3152a7c0060aSjmatthew 3153a7c0060aSjmatthew if (rc == 0) 3154a7c0060aSjmatthew cpr->stats_ctx_id = HWRM_NA_SIGNATURE; 3155a7c0060aSjmatthew 3156a7c0060aSjmatthew return (rc); 3157a7c0060aSjmatthew } 3158a7c0060aSjmatthew 3159a7c0060aSjmatthew #if 0 3160a7c0060aSjmatthew 3161a7c0060aSjmatthew int 3162a7c0060aSjmatthew bnxt_hwrm_port_qstats(struct bnxt_softc *softc) 3163a7c0060aSjmatthew { 3164a7c0060aSjmatthew struct hwrm_port_qstats_input req = {0}; 3165a7c0060aSjmatthew int rc = 0; 3166a7c0060aSjmatthew 3167a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_QSTATS); 3168a7c0060aSjmatthew 3169a7c0060aSjmatthew req.port_id = htole16(softc->pf.port_id); 3170a7c0060aSjmatthew req.rx_stat_host_addr = htole64(softc->hw_rx_port_stats.idi_paddr); 3171a7c0060aSjmatthew req.tx_stat_host_addr = htole64(softc->hw_tx_port_stats.idi_paddr); 3172a7c0060aSjmatthew 3173a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3174a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3175a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3176a7c0060aSjmatthew 3177a7c0060aSjmatthew return rc; 3178a7c0060aSjmatthew } 3179a7c0060aSjmatthew 3180a7c0060aSjmatthew #endif 3181a7c0060aSjmatthew 3182a7c0060aSjmatthew int 3183a7c0060aSjmatthew bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt_softc *softc, 3184b12ece3dSjmatthew uint32_t vnic_id, uint32_t rx_mask, uint64_t mc_addr, uint32_t mc_count) 3185a7c0060aSjmatthew { 3186a7c0060aSjmatthew struct hwrm_cfa_l2_set_rx_mask_input req = {0}; 3187a7c0060aSjmatthew 3188a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_SET_RX_MASK); 3189a7c0060aSjmatthew 3190b12ece3dSjmatthew req.vnic_id = htole32(vnic_id); 3191b12ece3dSjmatthew req.mask = htole32(rx_mask); 3192b12ece3dSjmatthew req.mc_tbl_addr = htole64(mc_addr); 3193b12ece3dSjmatthew req.num_mc_entries = htole32(mc_count); 3194a7c0060aSjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 3195a7c0060aSjmatthew } 3196a7c0060aSjmatthew 3197a7c0060aSjmatthew int 3198a7c0060aSjmatthew bnxt_hwrm_set_filter(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic) 3199a7c0060aSjmatthew { 3200a7c0060aSjmatthew struct hwrm_cfa_l2_filter_alloc_input req = {0}; 3201a7c0060aSjmatthew struct hwrm_cfa_l2_filter_alloc_output *resp; 3202a7c0060aSjmatthew uint32_t enables = 0; 3203a7c0060aSjmatthew int rc = 0; 3204a7c0060aSjmatthew 3205a7c0060aSjmatthew if (vnic->filter_id != -1) { 3206a7c0060aSjmatthew printf("%s: attempt to re-allocate l2 ctx filter\n", 3207a7c0060aSjmatthew DEVNAME(softc)); 3208a7c0060aSjmatthew return EINVAL; 3209a7c0060aSjmatthew } 3210a7c0060aSjmatthew 3211a7c0060aSjmatthew resp = BNXT_DMA_KVA(softc->sc_cmd_resp); 3212a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_FILTER_ALLOC); 3213a7c0060aSjmatthew 3214615a26c0Sjmatthew req.flags = htole32(HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX 3215615a26c0Sjmatthew | HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_OUTERMOST); 3216a7c0060aSjmatthew enables = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR 3217a7c0060aSjmatthew | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR_MASK 3218a7c0060aSjmatthew | HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_DST_ID; 3219a7c0060aSjmatthew req.enables = htole32(enables); 3220a7c0060aSjmatthew req.dst_id = htole16(vnic->id); 3221a7c0060aSjmatthew memcpy(req.l2_addr, softc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); 3222a7c0060aSjmatthew memset(&req.l2_addr_mask, 0xff, sizeof(req.l2_addr_mask)); 3223a7c0060aSjmatthew 3224a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3225a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3226a7c0060aSjmatthew if (rc) 3227a7c0060aSjmatthew goto fail; 3228a7c0060aSjmatthew 3229a7c0060aSjmatthew vnic->filter_id = le64toh(resp->l2_filter_id); 3230a7c0060aSjmatthew vnic->flow_id = le64toh(resp->flow_id); 3231a7c0060aSjmatthew 3232a7c0060aSjmatthew fail: 3233a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3234a7c0060aSjmatthew return (rc); 3235a7c0060aSjmatthew } 3236a7c0060aSjmatthew 3237a7c0060aSjmatthew int 3238a7c0060aSjmatthew bnxt_hwrm_free_filter(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic) 3239a7c0060aSjmatthew { 3240a7c0060aSjmatthew struct hwrm_cfa_l2_filter_free_input req = {0}; 3241a7c0060aSjmatthew int rc = 0; 3242a7c0060aSjmatthew 3243a7c0060aSjmatthew if (vnic->filter_id == -1) { 3244a7c0060aSjmatthew printf("%s: attempt to deallocate filter %llx\n", 3245a7c0060aSjmatthew DEVNAME(softc), vnic->filter_id); 3246a7c0060aSjmatthew return (EINVAL); 3247a7c0060aSjmatthew } 3248a7c0060aSjmatthew 3249a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_CFA_L2_FILTER_FREE); 3250a7c0060aSjmatthew req.l2_filter_id = htole64(vnic->filter_id); 3251a7c0060aSjmatthew 3252a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3253a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3254a7c0060aSjmatthew if (rc == 0) 3255a7c0060aSjmatthew vnic->filter_id = -1; 3256a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3257a7c0060aSjmatthew 3258a7c0060aSjmatthew return (rc); 3259a7c0060aSjmatthew } 3260a7c0060aSjmatthew 3261a7c0060aSjmatthew 3262a7c0060aSjmatthew int 3263d160d8f0Sjmatthew bnxt_hwrm_vnic_rss_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic, 3264d160d8f0Sjmatthew uint32_t hash_type, daddr_t rss_table, daddr_t rss_key) 3265a7c0060aSjmatthew { 3266a7c0060aSjmatthew struct hwrm_vnic_rss_cfg_input req = {0}; 3267a7c0060aSjmatthew 3268a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_RSS_CFG); 3269a7c0060aSjmatthew 3270a7c0060aSjmatthew req.hash_type = htole32(hash_type); 3271d160d8f0Sjmatthew req.ring_grp_tbl_addr = htole64(rss_table); 3272d160d8f0Sjmatthew req.hash_key_tbl_addr = htole64(rss_key); 3273a7c0060aSjmatthew req.rss_ctx_idx = htole16(vnic->rss_id); 3274a7c0060aSjmatthew 3275a7c0060aSjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 3276a7c0060aSjmatthew } 3277a7c0060aSjmatthew 3278a7c0060aSjmatthew int 3279765dc391Sjmatthew bnxt_cfg_async_cr(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr) 3280a7c0060aSjmatthew { 3281a7c0060aSjmatthew int rc = 0; 3282a7c0060aSjmatthew 3283a7c0060aSjmatthew if (1 /* BNXT_PF(softc) */) { 3284a7c0060aSjmatthew struct hwrm_func_cfg_input req = {0}; 3285a7c0060aSjmatthew 3286a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG); 3287a7c0060aSjmatthew 3288a7c0060aSjmatthew req.fid = htole16(0xffff); 3289a7c0060aSjmatthew req.enables = htole32(HWRM_FUNC_CFG_INPUT_ENABLES_ASYNC_EVENT_CR); 3290765dc391Sjmatthew req.async_event_cr = htole16(cpr->ring.phys_id); 3291a7c0060aSjmatthew 3292a7c0060aSjmatthew rc = hwrm_send_message(softc, &req, sizeof(req)); 3293a7c0060aSjmatthew } else { 3294a7c0060aSjmatthew struct hwrm_func_vf_cfg_input req = {0}; 3295a7c0060aSjmatthew 3296a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_VF_CFG); 3297a7c0060aSjmatthew 3298a7c0060aSjmatthew req.enables = htole32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_ASYNC_EVENT_CR); 3299765dc391Sjmatthew req.async_event_cr = htole16(cpr->ring.phys_id); 3300a7c0060aSjmatthew 3301a7c0060aSjmatthew rc = hwrm_send_message(softc, &req, sizeof(req)); 3302a7c0060aSjmatthew } 3303a7c0060aSjmatthew return rc; 3304a7c0060aSjmatthew } 3305a7c0060aSjmatthew 3306a7c0060aSjmatthew #if 0 3307a7c0060aSjmatthew 3308a7c0060aSjmatthew void 3309a7c0060aSjmatthew bnxt_validate_hw_lro_settings(struct bnxt_softc *softc) 3310a7c0060aSjmatthew { 3311a7c0060aSjmatthew softc->hw_lro.enable = min(softc->hw_lro.enable, 1); 3312a7c0060aSjmatthew 3313a7c0060aSjmatthew softc->hw_lro.is_mode_gro = min(softc->hw_lro.is_mode_gro, 1); 3314a7c0060aSjmatthew 3315a7c0060aSjmatthew softc->hw_lro.max_agg_segs = min(softc->hw_lro.max_agg_segs, 3316a7c0060aSjmatthew HWRM_VNIC_TPA_CFG_INPUT_MAX_AGG_SEGS_MAX); 3317a7c0060aSjmatthew 3318a7c0060aSjmatthew softc->hw_lro.max_aggs = min(softc->hw_lro.max_aggs, 3319a7c0060aSjmatthew HWRM_VNIC_TPA_CFG_INPUT_MAX_AGGS_MAX); 3320a7c0060aSjmatthew 3321a7c0060aSjmatthew softc->hw_lro.min_agg_len = min(softc->hw_lro.min_agg_len, BNXT_MAX_MTU); 3322a7c0060aSjmatthew } 3323a7c0060aSjmatthew 3324a7c0060aSjmatthew int 3325a7c0060aSjmatthew bnxt_hwrm_vnic_tpa_cfg(struct bnxt_softc *softc) 3326a7c0060aSjmatthew { 3327a7c0060aSjmatthew struct hwrm_vnic_tpa_cfg_input req = {0}; 3328a7c0060aSjmatthew uint32_t flags; 3329a7c0060aSjmatthew 3330a7c0060aSjmatthew if (softc->vnic_info.id == (uint16_t) HWRM_NA_SIGNATURE) { 3331a7c0060aSjmatthew return 0; 3332a7c0060aSjmatthew } 3333a7c0060aSjmatthew 3334a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_VNIC_TPA_CFG); 3335a7c0060aSjmatthew 3336a7c0060aSjmatthew if (softc->hw_lro.enable) { 3337a7c0060aSjmatthew flags = HWRM_VNIC_TPA_CFG_INPUT_FLAGS_TPA | 3338a7c0060aSjmatthew HWRM_VNIC_TPA_CFG_INPUT_FLAGS_ENCAP_TPA | 3339a7c0060aSjmatthew HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_ECN | 3340a7c0060aSjmatthew HWRM_VNIC_TPA_CFG_INPUT_FLAGS_AGG_WITH_SAME_GRE_SEQ; 3341a7c0060aSjmatthew 3342a7c0060aSjmatthew if (softc->hw_lro.is_mode_gro) 3343a7c0060aSjmatthew flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_GRO; 3344a7c0060aSjmatthew else 3345a7c0060aSjmatthew flags |= HWRM_VNIC_TPA_CFG_INPUT_FLAGS_RSC_WND_UPDATE; 3346a7c0060aSjmatthew 3347a7c0060aSjmatthew req.flags = htole32(flags); 3348a7c0060aSjmatthew 3349a7c0060aSjmatthew req.enables = htole32(HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGG_SEGS | 3350a7c0060aSjmatthew HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MAX_AGGS | 3351a7c0060aSjmatthew HWRM_VNIC_TPA_CFG_INPUT_ENABLES_MIN_AGG_LEN); 3352a7c0060aSjmatthew 3353a7c0060aSjmatthew req.max_agg_segs = htole16(softc->hw_lro.max_agg_segs); 3354a7c0060aSjmatthew req.max_aggs = htole16(softc->hw_lro.max_aggs); 3355a7c0060aSjmatthew req.min_agg_len = htole32(softc->hw_lro.min_agg_len); 3356a7c0060aSjmatthew } 3357a7c0060aSjmatthew 3358a7c0060aSjmatthew req.vnic_id = htole16(softc->vnic_info.id); 3359a7c0060aSjmatthew 3360a7c0060aSjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 3361a7c0060aSjmatthew } 3362a7c0060aSjmatthew 3363a7c0060aSjmatthew 3364a7c0060aSjmatthew int 3365a7c0060aSjmatthew bnxt_hwrm_fw_reset(struct bnxt_softc *softc, uint8_t processor, 3366a7c0060aSjmatthew uint8_t *selfreset) 3367a7c0060aSjmatthew { 3368a7c0060aSjmatthew struct hwrm_fw_reset_input req = {0}; 3369a7c0060aSjmatthew struct hwrm_fw_reset_output *resp = 3370a7c0060aSjmatthew (void *)softc->hwrm_cmd_resp.idi_vaddr; 3371a7c0060aSjmatthew int rc; 3372a7c0060aSjmatthew 3373a7c0060aSjmatthew MPASS(selfreset); 3374a7c0060aSjmatthew 3375a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_RESET); 3376a7c0060aSjmatthew req.embedded_proc_type = processor; 3377a7c0060aSjmatthew req.selfrst_status = *selfreset; 3378a7c0060aSjmatthew 3379a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3380a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3381a7c0060aSjmatthew if (rc) 3382a7c0060aSjmatthew goto exit; 3383a7c0060aSjmatthew *selfreset = resp->selfrst_status; 3384a7c0060aSjmatthew 3385a7c0060aSjmatthew exit: 3386a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3387a7c0060aSjmatthew return rc; 3388a7c0060aSjmatthew } 3389a7c0060aSjmatthew 3390a7c0060aSjmatthew int 3391a7c0060aSjmatthew bnxt_hwrm_fw_qstatus(struct bnxt_softc *softc, uint8_t type, uint8_t *selfreset) 3392a7c0060aSjmatthew { 3393a7c0060aSjmatthew struct hwrm_fw_qstatus_input req = {0}; 3394a7c0060aSjmatthew struct hwrm_fw_qstatus_output *resp = 3395a7c0060aSjmatthew (void *)softc->hwrm_cmd_resp.idi_vaddr; 3396a7c0060aSjmatthew int rc; 3397a7c0060aSjmatthew 3398a7c0060aSjmatthew MPASS(selfreset); 3399a7c0060aSjmatthew 3400a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_QSTATUS); 3401a7c0060aSjmatthew req.embedded_proc_type = type; 3402a7c0060aSjmatthew 3403a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3404a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3405a7c0060aSjmatthew if (rc) 3406a7c0060aSjmatthew goto exit; 3407a7c0060aSjmatthew *selfreset = resp->selfrst_status; 3408a7c0060aSjmatthew 3409a7c0060aSjmatthew exit: 3410a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3411a7c0060aSjmatthew return rc; 3412a7c0060aSjmatthew } 3413a7c0060aSjmatthew 3414a7c0060aSjmatthew #endif 3415a7c0060aSjmatthew 3416a7c0060aSjmatthew int 3417a7c0060aSjmatthew bnxt_hwrm_nvm_get_dev_info(struct bnxt_softc *softc, uint16_t *mfg_id, 3418a7c0060aSjmatthew uint16_t *device_id, uint32_t *sector_size, uint32_t *nvram_size, 3419a7c0060aSjmatthew uint32_t *reserved_size, uint32_t *available_size) 3420a7c0060aSjmatthew { 3421a7c0060aSjmatthew struct hwrm_nvm_get_dev_info_input req = {0}; 3422a7c0060aSjmatthew struct hwrm_nvm_get_dev_info_output *resp = 3423a7c0060aSjmatthew BNXT_DMA_KVA(softc->sc_cmd_resp); 3424a7c0060aSjmatthew int rc; 3425a7c0060aSjmatthew uint32_t old_timeo; 3426a7c0060aSjmatthew 3427a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_NVM_GET_DEV_INFO); 3428a7c0060aSjmatthew 3429a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3430a7c0060aSjmatthew old_timeo = softc->sc_cmd_timeo; 3431a7c0060aSjmatthew softc->sc_cmd_timeo = BNXT_NVM_TIMEO; 3432a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3433a7c0060aSjmatthew softc->sc_cmd_timeo = old_timeo; 3434a7c0060aSjmatthew if (rc) 3435a7c0060aSjmatthew goto exit; 3436a7c0060aSjmatthew 3437a7c0060aSjmatthew if (mfg_id) 3438a7c0060aSjmatthew *mfg_id = le16toh(resp->manufacturer_id); 3439a7c0060aSjmatthew if (device_id) 3440a7c0060aSjmatthew *device_id = le16toh(resp->device_id); 3441a7c0060aSjmatthew if (sector_size) 3442a7c0060aSjmatthew *sector_size = le32toh(resp->sector_size); 3443a7c0060aSjmatthew if (nvram_size) 3444a7c0060aSjmatthew *nvram_size = le32toh(resp->nvram_size); 3445a7c0060aSjmatthew if (reserved_size) 3446a7c0060aSjmatthew *reserved_size = le32toh(resp->reserved_size); 3447a7c0060aSjmatthew if (available_size) 3448a7c0060aSjmatthew *available_size = le32toh(resp->available_size); 3449a7c0060aSjmatthew 3450a7c0060aSjmatthew exit: 3451a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3452a7c0060aSjmatthew return rc; 3453a7c0060aSjmatthew } 3454a7c0060aSjmatthew 3455a7c0060aSjmatthew #if 0 3456a7c0060aSjmatthew 3457a7c0060aSjmatthew int 3458a7c0060aSjmatthew bnxt_hwrm_fw_get_time(struct bnxt_softc *softc, uint16_t *year, uint8_t *month, 3459a7c0060aSjmatthew uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second, 3460a7c0060aSjmatthew uint16_t *millisecond, uint16_t *zone) 3461a7c0060aSjmatthew { 3462a7c0060aSjmatthew struct hwrm_fw_get_time_input req = {0}; 3463a7c0060aSjmatthew struct hwrm_fw_get_time_output *resp = 3464a7c0060aSjmatthew (void *)softc->hwrm_cmd_resp.idi_vaddr; 3465a7c0060aSjmatthew int rc; 3466a7c0060aSjmatthew 3467a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_GET_TIME); 3468a7c0060aSjmatthew 3469a7c0060aSjmatthew BNXT_HWRM_LOCK(softc); 3470a7c0060aSjmatthew rc = _hwrm_send_message(softc, &req, sizeof(req)); 3471a7c0060aSjmatthew if (rc) 3472a7c0060aSjmatthew goto exit; 3473a7c0060aSjmatthew 3474a7c0060aSjmatthew if (year) 3475a7c0060aSjmatthew *year = le16toh(resp->year); 3476a7c0060aSjmatthew if (month) 3477a7c0060aSjmatthew *month = resp->month; 3478a7c0060aSjmatthew if (day) 3479a7c0060aSjmatthew *day = resp->day; 3480a7c0060aSjmatthew if (hour) 3481a7c0060aSjmatthew *hour = resp->hour; 3482a7c0060aSjmatthew if (minute) 3483a7c0060aSjmatthew *minute = resp->minute; 3484a7c0060aSjmatthew if (second) 3485a7c0060aSjmatthew *second = resp->second; 3486a7c0060aSjmatthew if (millisecond) 3487a7c0060aSjmatthew *millisecond = le16toh(resp->millisecond); 3488a7c0060aSjmatthew if (zone) 3489a7c0060aSjmatthew *zone = le16toh(resp->zone); 3490a7c0060aSjmatthew 3491a7c0060aSjmatthew exit: 3492a7c0060aSjmatthew BNXT_HWRM_UNLOCK(softc); 3493a7c0060aSjmatthew return rc; 3494a7c0060aSjmatthew } 3495a7c0060aSjmatthew 3496a7c0060aSjmatthew int 3497a7c0060aSjmatthew bnxt_hwrm_fw_set_time(struct bnxt_softc *softc, uint16_t year, uint8_t month, 3498a7c0060aSjmatthew uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, 3499a7c0060aSjmatthew uint16_t millisecond, uint16_t zone) 3500a7c0060aSjmatthew { 3501a7c0060aSjmatthew struct hwrm_fw_set_time_input req = {0}; 3502a7c0060aSjmatthew 3503a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FW_SET_TIME); 3504a7c0060aSjmatthew 3505a7c0060aSjmatthew req.year = htole16(year); 3506a7c0060aSjmatthew req.month = month; 3507a7c0060aSjmatthew req.day = day; 3508a7c0060aSjmatthew req.hour = hour; 3509a7c0060aSjmatthew req.minute = minute; 3510a7c0060aSjmatthew req.second = second; 3511a7c0060aSjmatthew req.millisecond = htole16(millisecond); 3512a7c0060aSjmatthew req.zone = htole16(zone); 3513a7c0060aSjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 3514a7c0060aSjmatthew } 3515a7c0060aSjmatthew 3516a7c0060aSjmatthew #endif 3517a7c0060aSjmatthew 3518a7c0060aSjmatthew void 3519a7c0060aSjmatthew _bnxt_hwrm_set_async_event_bit(struct hwrm_func_drv_rgtr_input *req, int bit) 3520a7c0060aSjmatthew { 3521a7c0060aSjmatthew req->async_event_fwd[bit/32] |= (1 << (bit % 32)); 3522a7c0060aSjmatthew } 3523a7c0060aSjmatthew 3524da5607f6Sjsg int 3525da5607f6Sjsg bnxt_hwrm_func_rgtr_async_events(struct bnxt_softc *softc) 3526a7c0060aSjmatthew { 3527a7c0060aSjmatthew struct hwrm_func_drv_rgtr_input req = {0}; 3528a7c0060aSjmatthew int events[] = { 3529a7c0060aSjmatthew HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE, 3530a7c0060aSjmatthew HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD, 3531a7c0060aSjmatthew HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED, 3532a7c0060aSjmatthew HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE, 3533a7c0060aSjmatthew HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE 3534a7c0060aSjmatthew }; 3535a7c0060aSjmatthew int i; 3536a7c0060aSjmatthew 3537a7c0060aSjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_DRV_RGTR); 3538a7c0060aSjmatthew 3539a7c0060aSjmatthew req.enables = 3540a7c0060aSjmatthew htole32(HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_ASYNC_EVENT_FWD); 3541a7c0060aSjmatthew 3542a7c0060aSjmatthew for (i = 0; i < nitems(events); i++) 3543a7c0060aSjmatthew _bnxt_hwrm_set_async_event_bit(&req, events[i]); 3544a7c0060aSjmatthew 3545a7c0060aSjmatthew return hwrm_send_message(softc, &req, sizeof(req)); 3546a7c0060aSjmatthew } 354740247284Sjmatthew 354840247284Sjmatthew int 354940247284Sjmatthew bnxt_get_sffpage(struct bnxt_softc *softc, struct if_sffpage *sff) 355040247284Sjmatthew { 355140247284Sjmatthew struct hwrm_port_phy_i2c_read_input req; 355240247284Sjmatthew struct hwrm_port_phy_i2c_read_output *out; 355340247284Sjmatthew int offset; 355440247284Sjmatthew 355540247284Sjmatthew bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_I2C_READ); 355640247284Sjmatthew req.i2c_slave_addr = sff->sff_addr; 355740247284Sjmatthew req.page_number = htole16(sff->sff_page); 355840247284Sjmatthew 355940247284Sjmatthew for (offset = 0; offset < 256; offset += sizeof(out->data)) { 356040247284Sjmatthew req.page_offset = htole16(offset); 356140247284Sjmatthew req.data_length = sizeof(out->data); 356240247284Sjmatthew req.enables = htole32(HWRM_PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET); 356340247284Sjmatthew 356440247284Sjmatthew if (hwrm_send_message(softc, &req, sizeof(req))) { 356540247284Sjmatthew printf("%s: failed to read i2c data\n", DEVNAME(softc)); 356640247284Sjmatthew return 1; 356740247284Sjmatthew } 356840247284Sjmatthew 356940247284Sjmatthew out = (struct hwrm_port_phy_i2c_read_output *) 357040247284Sjmatthew BNXT_DMA_KVA(softc->sc_cmd_resp); 357140247284Sjmatthew memcpy(sff->sff_data + offset, out->data, sizeof(out->data)); 357240247284Sjmatthew } 357340247284Sjmatthew 357440247284Sjmatthew return 0; 357540247284Sjmatthew } 3576