Index: head/sys/dev/bnxt/bnxt.h =================================================================== --- head/sys/dev/bnxt/bnxt.h (revision 314368) +++ head/sys/dev/bnxt/bnxt.h (revision 314369) @@ -1,591 +1,599 @@ /*- * Broadcom NetXtreme-C/E network driver. * * Copyright (c) 2016 Broadcom, All Rights Reserved. * The term Broadcom refers to Broadcom Limited and/or its subsidiaries * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #ifndef _BNXT_H #define _BNXT_H #include #include #include #include #include #include #include #include #include #include #include "hsi_struct_def.h" /* PCI IDs */ #define BROADCOM_VENDOR_ID 0x14E4 #define BCM57301 0x16c8 #define BCM57302 0x16c9 #define BCM57304 0x16ca #define BCM57311 0x16ce #define BCM57312 0x16cf #define BCM57314 0x16df #define BCM57402 0x16d0 #define BCM57402_NPAR 0x16d4 #define BCM57404 0x16d1 #define BCM57404_NPAR 0x16e7 #define BCM57406 0x16d2 #define BCM57406_NPAR 0x16e8 #define BCM57407 0x16d5 #define BCM57407_NPAR 0x16ea #define BCM57407_SFP 0x16e9 #define BCM57412 0x16d6 #define BCM57412_NPAR1 0x16de #define BCM57412_NPAR2 0x16eb #define BCM57414 0x16d7 #define BCM57414_NPAR1 0x16ec #define BCM57414_NPAR2 0x16ed #define BCM57416 0x16d8 #define BCM57416_NPAR1 0x16ee #define BCM57416_NPAR2 0x16ef #define BCM57416_SFP 0x16e3 #define BCM57417 0x16d9 #define BCM57417_NPAR1 0x16c0 #define BCM57417_NPAR2 0x16cc #define BCM57417_SFP 0x16e2 #define BCM58700 0x16cd #define NETXTREME_C_VF1 0x16cb #define NETXTREME_C_VF2 0x16e1 #define NETXTREME_C_VF3 0x16e5 #define NETXTREME_E_VF1 0x16c1 #define NETXTREME_E_VF2 0x16d3 #define NETXTREME_E_VF3 0x16dc #define CSUM_OFFLOAD (CSUM_IP_TSO|CSUM_IP6_TSO|CSUM_IP| \ CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP| \ CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP) #define BNXT_MAX_MTU 9000 +#define BNXT_RSS_HASH_TYPE_TCPV4 0 +#define BNXT_RSS_HASH_TYPE_UDPV4 1 +#define BNXT_RSS_HASH_TYPE_IPV4 2 +#define BNXT_RSS_HASH_TYPE_TCPV6 3 +#define BNXT_RSS_HASH_TYPE_UDPV6 4 +#define BNXT_RSS_HASH_TYPE_IPV6 5 +#define BNXT_GET_RSS_PROFILE_ID(rss_hash_type) ((rss_hash_type >> 1) & 0x1F) + /* Completion related defines */ #define CMP_VALID(cmp, v_bit) \ ((!!(((struct cmpl_base *)(cmp))->info3_v & htole32(CMPL_BASE_V))) == !!(v_bit) ) #define NEXT_CP_CONS_V(ring, cons, v_bit) do { \ if (__predict_false(++(cons) == (ring)->ring_size)) \ ((cons) = 0, (v_bit) = !v_bit); \ } while (0) #define RING_NEXT(ring, idx) (__predict_false(idx + 1 == (ring)->ring_size) ? \ 0 : idx + 1) #define CMPL_PREFETCH_NEXT(cpr, idx) \ __builtin_prefetch(&((struct cmpl_base *)(cpr)->ring.vaddr)[((idx) +\ (CACHE_LINE_SIZE / sizeof(struct cmpl_base))) & \ ((cpr)->ring.ring_size - 1)]) /* * If we update the index, a write barrier is needed after the write to ensure * the completion ring has space before the RX/TX ring does. Since we can't * make the RX and AG doorbells covered by the same barrier without remapping * MSI-X vectors, we create the barrier over the enture doorbell bar. * TODO: Remap the MSI-X vectors to allow a barrier to only cover the doorbells * for a single ring group. * * A barrier of just the size of the write is used to ensure the ordering * remains correct and no writes are lost. */ #define BNXT_CP_DISABLE_DB(ring) do { \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, 4, \ BUS_SPACE_BARRIER_WRITE); \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, 0, \ (ring)->softc->doorbell_bar.size, BUS_SPACE_BARRIER_WRITE); \ bus_space_write_4((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, \ htole32(CMPL_DOORBELL_KEY_CMPL | CMPL_DOORBELL_MASK)); \ } while (0) #define BNXT_CP_ENABLE_DB(ring) do { \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, 4, \ BUS_SPACE_BARRIER_WRITE); \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, 0, \ (ring)->softc->doorbell_bar.size, BUS_SPACE_BARRIER_WRITE); \ bus_space_write_4((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, \ htole32(CMPL_DOORBELL_KEY_CMPL)); \ } while (0) #define BNXT_CP_IDX_ENABLE_DB(ring, cons) do { \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, 4, \ BUS_SPACE_BARRIER_WRITE); \ bus_space_write_4((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, \ htole32(CMPL_DOORBELL_KEY_CMPL | CMPL_DOORBELL_IDX_VALID | \ (cons))); \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, 0, \ (ring)->softc->doorbell_bar.size, BUS_SPACE_BARRIER_WRITE); \ } while (0) #define BNXT_CP_IDX_DISABLE_DB(ring, cons) do { \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, 4, \ BUS_SPACE_BARRIER_WRITE); \ bus_space_write_4((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, \ htole32(CMPL_DOORBELL_KEY_CMPL | CMPL_DOORBELL_IDX_VALID | \ CMPL_DOORBELL_MASK | (cons))); \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, 0, \ (ring)->softc->doorbell_bar.size, BUS_SPACE_BARRIER_WRITE); \ } while (0) #define BNXT_TX_DB(ring, idx) do { \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, 4, \ BUS_SPACE_BARRIER_WRITE); \ bus_space_write_4( \ (ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, \ (ring)->doorbell, htole32(TX_DOORBELL_KEY_TX | (idx))); \ } while (0) #define BNXT_RX_DB(ring, idx) do { \ bus_space_barrier((ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, (ring)->doorbell, 4, \ BUS_SPACE_BARRIER_WRITE); \ bus_space_write_4( \ (ring)->softc->doorbell_bar.tag, \ (ring)->softc->doorbell_bar.handle, \ (ring)->doorbell, htole32(RX_DOORBELL_KEY_RX | (idx))); \ } while (0) /* Lock macros */ #define BNXT_HWRM_LOCK_INIT(_softc, _name) \ mtx_init(&(_softc)->hwrm_lock, _name, "BNXT HWRM Lock", MTX_DEF) #define BNXT_HWRM_LOCK(_softc) mtx_lock(&(_softc)->hwrm_lock) #define BNXT_HWRM_UNLOCK(_softc) mtx_unlock(&(_softc)->hwrm_lock) #define BNXT_HWRM_LOCK_DESTROY(_softc) mtx_destroy(&(_softc)->hwrm_lock) #define BNXT_HWRM_LOCK_ASSERT(_softc) mtx_assert(&(_softc)->hwrm_lock, \ MA_OWNED) /* Chip info */ #define BNXT_TSO_SIZE UINT16_MAX /* NVRAM access */ enum bnxt_nvm_directory_type { BNX_DIR_TYPE_UNUSED = 0, BNX_DIR_TYPE_PKG_LOG = 1, BNX_DIR_TYPE_UPDATE = 2, BNX_DIR_TYPE_CHIMP_PATCH = 3, BNX_DIR_TYPE_BOOTCODE = 4, BNX_DIR_TYPE_VPD = 5, BNX_DIR_TYPE_EXP_ROM_MBA = 6, BNX_DIR_TYPE_AVS = 7, BNX_DIR_TYPE_PCIE = 8, BNX_DIR_TYPE_PORT_MACRO = 9, BNX_DIR_TYPE_APE_FW = 10, BNX_DIR_TYPE_APE_PATCH = 11, BNX_DIR_TYPE_KONG_FW = 12, BNX_DIR_TYPE_KONG_PATCH = 13, BNX_DIR_TYPE_BONO_FW = 14, BNX_DIR_TYPE_BONO_PATCH = 15, BNX_DIR_TYPE_TANG_FW = 16, BNX_DIR_TYPE_TANG_PATCH = 17, BNX_DIR_TYPE_BOOTCODE_2 = 18, BNX_DIR_TYPE_CCM = 19, BNX_DIR_TYPE_PCI_CFG = 20, BNX_DIR_TYPE_TSCF_UCODE = 21, BNX_DIR_TYPE_ISCSI_BOOT = 22, BNX_DIR_TYPE_ISCSI_BOOT_IPV6 = 24, BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6 = 25, BNX_DIR_TYPE_ISCSI_BOOT_CFG6 = 26, BNX_DIR_TYPE_EXT_PHY = 27, BNX_DIR_TYPE_SHARED_CFG = 40, BNX_DIR_TYPE_PORT_CFG = 41, BNX_DIR_TYPE_FUNC_CFG = 42, BNX_DIR_TYPE_MGMT_CFG = 48, BNX_DIR_TYPE_MGMT_DATA = 49, BNX_DIR_TYPE_MGMT_WEB_DATA = 50, BNX_DIR_TYPE_MGMT_WEB_META = 51, BNX_DIR_TYPE_MGMT_EVENT_LOG = 52, BNX_DIR_TYPE_MGMT_AUDIT_LOG = 53 }; enum bnxnvm_pkglog_field_index { BNX_PKG_LOG_FIELD_IDX_INSTALLED_TIMESTAMP = 0, BNX_PKG_LOG_FIELD_IDX_PKG_DESCRIPTION = 1, BNX_PKG_LOG_FIELD_IDX_PKG_VERSION = 2, BNX_PKG_LOG_FIELD_IDX_PKG_TIMESTAMP = 3, BNX_PKG_LOG_FIELD_IDX_PKG_CHECKSUM = 4, BNX_PKG_LOG_FIELD_IDX_INSTALLED_ITEMS = 5, BNX_PKG_LOG_FIELD_IDX_INSTALLED_MASK = 6 }; #define BNX_DIR_ORDINAL_FIRST 0 #define BNX_DIR_EXT_NONE 0 struct bnxt_bar_info { struct resource *res; bus_space_tag_t tag; bus_space_handle_t handle; bus_size_t size; int rid; }; struct bnxt_link_info { uint8_t media_type; uint8_t transceiver; uint8_t phy_addr; uint8_t phy_link_status; uint8_t wire_speed; uint8_t loop_back; uint8_t link_up; uint8_t last_link_up; uint8_t duplex; uint8_t last_duplex; uint8_t pause; uint8_t last_pause; uint8_t auto_pause; uint8_t force_pause; uint8_t duplex_setting; uint8_t auto_mode; #define PHY_VER_LEN 3 uint8_t phy_ver[PHY_VER_LEN]; uint8_t phy_type; uint16_t link_speed; uint16_t support_speeds; uint16_t auto_link_speeds; uint16_t auto_link_speed; uint16_t force_link_speed; uint32_t preemphasis; /* copy of requested setting */ uint8_t autoneg; #define BNXT_AUTONEG_SPEED 1 #define BNXT_AUTONEG_FLOW_CTRL 2 uint8_t req_duplex; uint8_t req_flow_ctrl; uint16_t req_link_speed; }; enum bnxt_cp_type { BNXT_DEFAULT, BNXT_TX, BNXT_RX, BNXT_SHARED }; struct bnxt_cos_queue { uint8_t id; uint8_t profile; }; struct bnxt_func_info { uint32_t fw_fid; uint8_t mac_addr[ETHER_ADDR_LEN]; uint16_t max_rsscos_ctxs; uint16_t max_cp_rings; uint16_t max_tx_rings; uint16_t max_rx_rings; uint16_t max_hw_ring_grps; uint16_t max_irqs; uint16_t max_l2_ctxs; uint16_t max_vnics; uint16_t max_stat_ctxs; }; struct bnxt_pf_info { #define BNXT_FIRST_PF_FID 1 #define BNXT_FIRST_VF_FID 128 uint8_t port_id; uint32_t first_vf_id; uint16_t active_vfs; uint16_t max_vfs; uint32_t max_encap_records; uint32_t max_decap_records; uint32_t max_tx_em_flows; uint32_t max_tx_wm_flows; uint32_t max_rx_em_flows; uint32_t max_rx_wm_flows; unsigned long *vf_event_bmap; uint16_t hwrm_cmd_req_pages; void *hwrm_cmd_req_addr[4]; bus_addr_t hwrm_cmd_req_dma_addr[4]; }; struct bnxt_vf_info { uint16_t fw_fid; uint8_t mac_addr[ETHER_ADDR_LEN]; uint16_t max_rsscos_ctxs; uint16_t max_cp_rings; uint16_t max_tx_rings; uint16_t max_rx_rings; uint16_t max_hw_ring_grps; uint16_t max_l2_ctxs; uint16_t max_irqs; uint16_t max_vnics; uint16_t max_stat_ctxs; uint32_t vlan; #define BNXT_VF_QOS 0x1 #define BNXT_VF_SPOOFCHK 0x2 #define BNXT_VF_LINK_FORCED 0x4 #define BNXT_VF_LINK_UP 0x8 uint32_t flags; uint32_t func_flags; /* func cfg flags */ uint32_t min_tx_rate; uint32_t max_tx_rate; void *hwrm_cmd_req_addr; bus_addr_t hwrm_cmd_req_dma_addr; }; #define BNXT_FLAG_VF (1<<1) #define BNXT_PF(softc) (!((softc)->flags & BNXT_FLAG_VF)) #define BNXT_VF(softc) ((softc)->flags & BNXT_FLAG_VF) struct bnxt_vlan_tag { SLIST_ENTRY(bnxt_vlan_tag) next; uint16_t tpid; uint16_t tag; }; struct bnxt_vnic_info { uint16_t id; uint16_t def_ring_grp; uint16_t cos_rule; uint16_t lb_rule; uint16_t mru; uint32_t rx_mask; bool vlan_only; struct iflib_dma_info mc_list; int mc_list_count; #define BNXT_MAX_MC_ADDRS 16 uint32_t flags; #define BNXT_VNIC_FLAG_DEFAULT 0x01 #define BNXT_VNIC_FLAG_BD_STALL 0x02 #define BNXT_VNIC_FLAG_VLAN_STRIP 0x04 uint64_t filter_id; uint32_t flow_id; uint16_t rss_id; uint32_t rss_hash_type; uint8_t rss_hash_key[HW_HASH_KEY_SIZE]; struct iflib_dma_info rss_hash_key_tbl; struct iflib_dma_info rss_grp_tbl; SLIST_HEAD(vlan_head, bnxt_vlan_tag) vlan_tags; struct iflib_dma_info vlan_tag_list; }; struct bnxt_grp_info { uint16_t stats_ctx; uint16_t grp_id; uint16_t rx_ring_id; uint16_t cp_ring_id; uint16_t ag_ring_id; }; struct bnxt_ring { uint64_t paddr; vm_offset_t doorbell; caddr_t vaddr; struct bnxt_softc *softc; uint32_t ring_size; /* Must be a power of two */ uint16_t id; /* Logical ID */ uint16_t phys_id; }; struct bnxt_cp_ring { struct bnxt_ring ring; struct if_irq irq; uint32_t cons; bool v_bit; /* Value of valid bit */ struct ctx_hw_stats *stats; uint32_t stats_ctx_id; uint32_t last_idx; /* Used by RX rings only * set to the last read pidx */ }; struct bnxt_full_tpa_start { struct rx_tpa_start_cmpl low; struct rx_tpa_start_cmpl_hi high; }; /* All the version information for the part */ #define BNXT_VERSTR_SIZE (3*3+2+1) /* ie: "255.255.255\0" */ #define BNXT_NAME_SIZE 17 struct bnxt_ver_info { uint8_t hwrm_if_major; uint8_t hwrm_if_minor; uint8_t hwrm_if_update; char hwrm_if_ver[BNXT_VERSTR_SIZE]; char driver_hwrm_if_ver[BNXT_VERSTR_SIZE]; char hwrm_fw_ver[BNXT_VERSTR_SIZE]; char mgmt_fw_ver[BNXT_VERSTR_SIZE]; char netctrl_fw_ver[BNXT_VERSTR_SIZE]; char roce_fw_ver[BNXT_VERSTR_SIZE]; char phy_ver[BNXT_VERSTR_SIZE]; char pkg_ver[64]; char hwrm_fw_name[BNXT_NAME_SIZE]; char mgmt_fw_name[BNXT_NAME_SIZE]; char netctrl_fw_name[BNXT_NAME_SIZE]; char roce_fw_name[BNXT_NAME_SIZE]; char phy_vendor[BNXT_NAME_SIZE]; char phy_partnumber[BNXT_NAME_SIZE]; uint16_t chip_num; uint8_t chip_rev; uint8_t chip_metal; uint8_t chip_bond_id; uint8_t chip_type; uint8_t hwrm_min_major; uint8_t hwrm_min_minor; uint8_t hwrm_min_update; struct sysctl_ctx_list ver_ctx; struct sysctl_oid *ver_oid; }; struct bnxt_nvram_info { uint16_t mfg_id; uint16_t device_id; uint32_t sector_size; uint32_t size; uint32_t reserved_size; uint32_t available_size; struct sysctl_ctx_list nvm_ctx; struct sysctl_oid *nvm_oid; }; struct bnxt_softc { device_t dev; if_ctx_t ctx; if_softc_ctx_t scctx; if_shared_ctx_t sctx; struct ifmedia *media; struct bnxt_bar_info hwrm_bar; struct bnxt_bar_info doorbell_bar; struct bnxt_link_info link_info; #define BNXT_FLAG_NPAR 1 uint32_t flags; uint32_t total_msix; struct bnxt_func_info func; struct bnxt_pf_info pf; struct bnxt_vf_info vf; uint16_t hwrm_cmd_seq; uint32_t hwrm_cmd_timeo; /* milliseconds */ struct iflib_dma_info hwrm_cmd_resp; /* Interrupt info for HWRM */ struct if_irq irq; struct mtx hwrm_lock; uint16_t hwrm_max_req_len; #define BNXT_MAX_QUEUE 8 uint8_t max_tc; struct bnxt_cos_queue q_info[BNXT_MAX_QUEUE]; struct iflib_dma_info hw_rx_port_stats; struct iflib_dma_info hw_tx_port_stats; struct rx_port_stats *rx_port_stats; struct tx_port_stats *tx_port_stats; int num_cp_rings; struct bnxt_ring *tx_rings; struct bnxt_cp_ring *tx_cp_rings; struct iflib_dma_info tx_stats; int ntxqsets; struct bnxt_vnic_info vnic_info; struct bnxt_ring *ag_rings; struct bnxt_ring *rx_rings; struct bnxt_cp_ring *rx_cp_rings; struct bnxt_grp_info *grp_info; struct iflib_dma_info rx_stats; int nrxqsets; struct bnxt_cp_ring def_cp_ring; struct iflib_dma_info def_cp_ring_mem; struct grouptask def_cp_task; struct sysctl_ctx_list hw_stats; struct sysctl_oid *hw_stats_oid; struct bnxt_full_tpa_start *tpa_start; struct bnxt_ver_info *ver_info; struct bnxt_nvram_info *nvm_info; }; struct bnxt_filter_info { STAILQ_ENTRY(bnxt_filter_info) next; uint64_t fw_l2_filter_id; #define INVALID_MAC_INDEX ((uint16_t)-1) uint16_t mac_index; /* Filter Characteristics */ uint32_t flags; uint32_t enables; uint8_t l2_addr[ETHER_ADDR_LEN]; uint8_t l2_addr_mask[ETHER_ADDR_LEN]; uint16_t l2_ovlan; uint16_t l2_ovlan_mask; uint16_t l2_ivlan; uint16_t l2_ivlan_mask; uint8_t t_l2_addr[ETHER_ADDR_LEN]; uint8_t t_l2_addr_mask[ETHER_ADDR_LEN]; uint16_t t_l2_ovlan; uint16_t t_l2_ovlan_mask; uint16_t t_l2_ivlan; uint16_t t_l2_ivlan_mask; uint8_t tunnel_type; uint16_t mirror_vnic_id; uint32_t vni; uint8_t pri_hint; uint64_t l2_filter_id_hint; }; /* Function declarations */ void bnxt_report_link(struct bnxt_softc *softc); bool bnxt_check_hwrm_version(struct bnxt_softc *softc); #endif /* _BNXT_H */ Index: head/sys/dev/bnxt/bnxt_txrx.c =================================================================== --- head/sys/dev/bnxt/bnxt_txrx.c (revision 314368) +++ head/sys/dev/bnxt/bnxt_txrx.c (revision 314369) @@ -1,641 +1,660 @@ /*- * Broadcom NetXtreme-C/E network driver. * * Copyright (c) 2016 Broadcom, All Rights Reserved. * The term Broadcom refers to Broadcom Limited and/or its subsidiaries * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "opt_inet.h" #include "opt_inet6.h" #include "opt_rss.h" #include "bnxt.h" /* * Function prototypes */ static int bnxt_isc_txd_encap(void *sc, if_pkt_info_t pi); static void bnxt_isc_txd_flush(void *sc, uint16_t txqid, uint32_t pidx); static int bnxt_isc_txd_credits_update(void *sc, uint16_t txqid, uint32_t cidx, bool clear); static void bnxt_isc_rxd_refill(void *sc, uint16_t rxqid, uint8_t flid, uint32_t pidx, uint64_t *paddrs, caddr_t *vaddrs, uint16_t count, uint16_t buf_size); static void bnxt_isc_rxd_flush(void *sc, uint16_t rxqid, uint8_t flid, uint32_t pidx); static int bnxt_isc_rxd_available(void *sc, uint16_t rxqid, uint32_t idx, int budget); static int bnxt_isc_rxd_pkt_get(void *sc, if_rxd_info_t ri); static int bnxt_intr(void *sc); struct if_txrx bnxt_txrx = { bnxt_isc_txd_encap, bnxt_isc_txd_flush, bnxt_isc_txd_credits_update, bnxt_isc_rxd_available, bnxt_isc_rxd_pkt_get, bnxt_isc_rxd_refill, bnxt_isc_rxd_flush, bnxt_intr }; /* * Device Dependent Packet Transmit and Receive Functions */ static const uint16_t bnxt_tx_lhint[] = { TX_BD_SHORT_FLAGS_LHINT_LT512, TX_BD_SHORT_FLAGS_LHINT_LT1K, TX_BD_SHORT_FLAGS_LHINT_LT2K, TX_BD_SHORT_FLAGS_LHINT_LT2K, TX_BD_SHORT_FLAGS_LHINT_GTE2K, }; static int bnxt_isc_txd_encap(void *sc, if_pkt_info_t pi) { struct bnxt_softc *softc = (struct bnxt_softc *)sc; struct bnxt_ring *txr = &softc->tx_rings[pi->ipi_qsidx]; struct tx_bd_long *tbd; struct tx_bd_long_hi *tbdh; bool need_hi = false; uint16_t flags_type; uint16_t lflags; uint32_t cfa_meta; int seg = 0; /* If we have offloads enabled, we need to use two BDs. */ if ((pi->ipi_csum_flags & (CSUM_OFFLOAD | CSUM_TSO | CSUM_IP)) || pi->ipi_mflags & M_VLANTAG) need_hi = true; /* TODO: Devices before Cu+B1 need to not mix long and short BDs */ need_hi = true; pi->ipi_new_pidx = pi->ipi_pidx; tbd = &((struct tx_bd_long *)txr->vaddr)[pi->ipi_new_pidx]; pi->ipi_ndescs = 0; /* No need to byte-swap the opaque value */ tbd->opaque = ((pi->ipi_nsegs + need_hi) << 24) | pi->ipi_new_pidx; tbd->len = htole16(pi->ipi_segs[seg].ds_len); tbd->addr = htole64(pi->ipi_segs[seg++].ds_addr); flags_type = ((pi->ipi_nsegs + need_hi) << TX_BD_SHORT_FLAGS_BD_CNT_SFT) & TX_BD_SHORT_FLAGS_BD_CNT_MASK; if (pi->ipi_len >= 2048) flags_type |= TX_BD_SHORT_FLAGS_LHINT_GTE2K; else flags_type |= bnxt_tx_lhint[pi->ipi_len >> 9]; if (need_hi) { flags_type |= TX_BD_LONG_TYPE_TX_BD_LONG; pi->ipi_new_pidx = RING_NEXT(txr, pi->ipi_new_pidx); tbdh = &((struct tx_bd_long_hi *)txr->vaddr)[pi->ipi_new_pidx]; tbdh->mss = htole16(pi->ipi_tso_segsz); tbdh->hdr_size = htole16((pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen) >> 1); tbdh->cfa_action = 0; lflags = 0; cfa_meta = 0; if (pi->ipi_mflags & M_VLANTAG) { /* TODO: Do we need to byte-swap the vtag here? */ cfa_meta = TX_BD_LONG_CFA_META_KEY_VLAN_TAG | pi->ipi_vtag; cfa_meta |= TX_BD_LONG_CFA_META_VLAN_TPID_TPID8100; } tbdh->cfa_meta = htole32(cfa_meta); if (pi->ipi_csum_flags & CSUM_TSO) { lflags |= TX_BD_LONG_LFLAGS_LSO | TX_BD_LONG_LFLAGS_T_IPID; } else if(pi->ipi_csum_flags & CSUM_OFFLOAD) { lflags |= TX_BD_LONG_LFLAGS_TCP_UDP_CHKSUM | TX_BD_LONG_LFLAGS_IP_CHKSUM; } else if(pi->ipi_csum_flags & CSUM_IP) { lflags |= TX_BD_LONG_LFLAGS_IP_CHKSUM; } tbdh->lflags = htole16(lflags); } else { flags_type |= TX_BD_SHORT_TYPE_TX_BD_SHORT; } for (; seg < pi->ipi_nsegs; seg++) { tbd->flags_type = htole16(flags_type); pi->ipi_new_pidx = RING_NEXT(txr, pi->ipi_new_pidx); tbd = &((struct tx_bd_long *)txr->vaddr)[pi->ipi_new_pidx]; tbd->len = htole16(pi->ipi_segs[seg].ds_len); tbd->addr = htole64(pi->ipi_segs[seg].ds_addr); flags_type = TX_BD_SHORT_TYPE_TX_BD_SHORT; } flags_type |= TX_BD_SHORT_FLAGS_PACKET_END; tbd->flags_type = htole16(flags_type); pi->ipi_new_pidx = RING_NEXT(txr, pi->ipi_new_pidx); return 0; } static void bnxt_isc_txd_flush(void *sc, uint16_t txqid, uint32_t pidx) { struct bnxt_softc *softc = (struct bnxt_softc *)sc; struct bnxt_ring *tx_ring = &softc->tx_rings[txqid]; /* pidx is what we last set ipi_new_pidx to */ BNXT_TX_DB(tx_ring, pidx); /* TODO: Cumulus+ doesn't need the double doorbell */ BNXT_TX_DB(tx_ring, pidx); return; } static int bnxt_isc_txd_credits_update(void *sc, uint16_t txqid, uint32_t idx, bool clear) { struct bnxt_softc *softc = (struct bnxt_softc *)sc; struct bnxt_cp_ring *cpr = &softc->tx_cp_rings[txqid]; struct tx_cmpl *cmpl = (struct tx_cmpl *)cpr->ring.vaddr; int avail = 0; uint32_t cons = cpr->cons; bool v_bit = cpr->v_bit; bool last_v_bit; uint32_t last_cons; uint16_t type; uint16_t err; for (;;) { last_cons = cons; last_v_bit = v_bit; NEXT_CP_CONS_V(&cpr->ring, cons, v_bit); CMPL_PREFETCH_NEXT(cpr, cons); if (!CMP_VALID(&cmpl[cons], v_bit)) goto done; type = cmpl[cons].flags_type & TX_CMPL_TYPE_MASK; switch (type) { case TX_CMPL_TYPE_TX_L2: err = (le16toh(cmpl[cons].errors_v) & TX_CMPL_ERRORS_BUFFER_ERROR_MASK) >> TX_CMPL_ERRORS_BUFFER_ERROR_SFT; if (err) device_printf(softc->dev, "TX completion error %u\n", err); /* No need to byte-swap the opaque value */ avail += cmpl[cons].opaque >> 24; /* * If we're not clearing, iflib only cares if there's * at least one buffer. Don't scan the whole ring in * this case. */ if (!clear) goto done; break; default: if (type & 1) { NEXT_CP_CONS_V(&cpr->ring, cons, v_bit); if (!CMP_VALID(&cmpl[cons], v_bit)) goto done; } device_printf(softc->dev, "Unhandled TX completion type %u\n", type); break; } } done: if (clear && avail) { cpr->cons = last_cons; cpr->v_bit = last_v_bit; BNXT_CP_IDX_DISABLE_DB(&cpr->ring, cpr->cons); } return avail; } static void bnxt_isc_rxd_refill(void *sc, uint16_t rxqid, uint8_t flid, uint32_t pidx, uint64_t *paddrs, caddr_t *vaddrs, uint16_t count, uint16_t len) { struct bnxt_softc *softc = (struct bnxt_softc *)sc; struct bnxt_ring *rx_ring; struct rx_prod_pkt_bd *rxbd; uint16_t type; uint16_t i; if (flid == 0) { rx_ring = &softc->rx_rings[rxqid]; type = RX_PROD_PKT_BD_TYPE_RX_PROD_PKT; } else { rx_ring = &softc->ag_rings[rxqid]; type = RX_PROD_AGG_BD_TYPE_RX_PROD_AGG; } rxbd = (void *)rx_ring->vaddr; for (i=0; iring_size) pidx = 0; } return; } static void bnxt_isc_rxd_flush(void *sc, uint16_t rxqid, uint8_t flid, uint32_t pidx) { struct bnxt_softc *softc = (struct bnxt_softc *)sc; struct bnxt_ring *rx_ring; if (flid == 0) rx_ring = &softc->rx_rings[rxqid]; else rx_ring = &softc->ag_rings[rxqid]; /* * We *must* update the completion ring before updating the RX ring * or we will overrun the completion ring and the device will wedge for * RX. */ if (softc->rx_cp_rings[rxqid].cons != UINT32_MAX) BNXT_CP_IDX_DISABLE_DB(&softc->rx_cp_rings[rxqid].ring, softc->rx_cp_rings[rxqid].cons); /* We're given the last filled RX buffer here, not the next empty one */ BNXT_RX_DB(rx_ring, RING_NEXT(rx_ring, pidx)); /* TODO: Cumulus+ doesn't need the double doorbell */ BNXT_RX_DB(rx_ring, RING_NEXT(rx_ring, pidx)); return; } static int bnxt_isc_rxd_available(void *sc, uint16_t rxqid, uint32_t idx, int budget) { struct bnxt_softc *softc = (struct bnxt_softc *)sc; struct bnxt_cp_ring *cpr = &softc->rx_cp_rings[rxqid]; struct rx_pkt_cmpl *rcp; struct rx_tpa_start_cmpl *rtpa; struct rx_tpa_end_cmpl *rtpae; struct cmpl_base *cmp = (struct cmpl_base *)cpr->ring.vaddr; int avail = 0; uint32_t cons = cpr->cons; bool v_bit = cpr->v_bit; uint8_t ags; int i; uint16_t type; uint8_t agg_id; for (;;) { NEXT_CP_CONS_V(&cpr->ring, cons, v_bit); CMPL_PREFETCH_NEXT(cpr, cons); if (!CMP_VALID(&cmp[cons], v_bit)) goto cmpl_invalid; type = le16toh(cmp[cons].type) & CMPL_BASE_TYPE_MASK; switch (type) { case CMPL_BASE_TYPE_RX_L2: rcp = (void *)&cmp[cons]; ags = (rcp->agg_bufs_v1 & RX_PKT_CMPL_AGG_BUFS_MASK) >> RX_PKT_CMPL_AGG_BUFS_SFT; NEXT_CP_CONS_V(&cpr->ring, cons, v_bit); CMPL_PREFETCH_NEXT(cpr, cons); if (!CMP_VALID(&cmp[cons], v_bit)) goto cmpl_invalid; /* Now account for all the AG completions */ for (i=0; iring, cons, v_bit); CMPL_PREFETCH_NEXT(cpr, cons); if (!CMP_VALID(&cmp[cons], v_bit)) goto cmpl_invalid; } avail++; break; case CMPL_BASE_TYPE_RX_TPA_END: rtpae = (void *)&cmp[cons]; ags = (rtpae->agg_bufs_v1 & RX_TPA_END_CMPL_AGG_BUFS_MASK) >> RX_TPA_END_CMPL_AGG_BUFS_SFT; NEXT_CP_CONS_V(&cpr->ring, cons, v_bit); CMPL_PREFETCH_NEXT(cpr, cons); if (!CMP_VALID(&cmp[cons], v_bit)) goto cmpl_invalid; /* Now account for all the AG completions */ for (i=0; iring, cons, v_bit); CMPL_PREFETCH_NEXT(cpr, cons); if (!CMP_VALID(&cmp[cons], v_bit)) goto cmpl_invalid; } avail++; break; case CMPL_BASE_TYPE_RX_TPA_START: rtpa = (void *)&cmp[cons]; agg_id = (rtpa->agg_id & RX_TPA_START_CMPL_AGG_ID_MASK) >> RX_TPA_START_CMPL_AGG_ID_SFT; softc->tpa_start[agg_id].low = *rtpa; NEXT_CP_CONS_V(&cpr->ring, cons, v_bit); CMPL_PREFETCH_NEXT(cpr, cons); if (!CMP_VALID(&cmp[cons], v_bit)) goto cmpl_invalid; softc->tpa_start[agg_id].high = ((struct rx_tpa_start_cmpl_hi *)cmp)[cons]; break; case CMPL_BASE_TYPE_RX_AGG: break; default: device_printf(softc->dev, "Unhandled completion type %d on RXQ %d\n", type, rxqid); /* Odd completion types use two completions */ if (type & 1) { NEXT_CP_CONS_V(&cpr->ring, cons, v_bit); CMPL_PREFETCH_NEXT(cpr, cons); if (!CMP_VALID(&cmp[cons], v_bit)) goto cmpl_invalid; } break; } if (avail > budget) break; } cmpl_invalid: return avail; } +static void +bnxt_set_rsstype(if_rxd_info_t ri, uint8_t rss_hash_type) +{ + uint8_t rss_profile_id; + + rss_profile_id = BNXT_GET_RSS_PROFILE_ID(rss_hash_type); + switch (rss_profile_id) { + case BNXT_RSS_HASH_TYPE_TCPV4: + ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV4; + break; + case BNXT_RSS_HASH_TYPE_UDPV4: + ri->iri_rsstype = M_HASHTYPE_RSS_UDP_IPV4; + break; + case BNXT_RSS_HASH_TYPE_IPV4: + ri->iri_rsstype = M_HASHTYPE_RSS_IPV4; + break; + case BNXT_RSS_HASH_TYPE_TCPV6: + ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV6; + break; + case BNXT_RSS_HASH_TYPE_UDPV6: + ri->iri_rsstype = M_HASHTYPE_RSS_UDP_IPV6; + break; + case BNXT_RSS_HASH_TYPE_IPV6: + ri->iri_rsstype = M_HASHTYPE_RSS_IPV6; + break; + default: + ri->iri_rsstype = M_HASHTYPE_OPAQUE; + break; + } +} + static int bnxt_pkt_get_l2(struct bnxt_softc *softc, if_rxd_info_t ri, struct bnxt_cp_ring *cpr, uint16_t flags_type) { struct rx_pkt_cmpl *rcp; struct rx_pkt_cmpl_hi *rcph; struct rx_abuf_cmpl *acp; uint32_t flags2; uint32_t errors; uint8_t ags; int i; rcp = &((struct rx_pkt_cmpl *)cpr->ring.vaddr)[cpr->cons]; /* Extract from the first 16-byte BD */ if (flags_type & RX_PKT_CMPL_FLAGS_RSS_VALID) { ri->iri_flowid = le32toh(rcp->rss_hash); - /* - * TODO: Extract something useful from rcp->rss_hash_type - * (undocumented) - * May be documented in the "LSI ES" - * also check the firmware code. - */ - ri->iri_rsstype = M_HASHTYPE_OPAQUE; + bnxt_set_rsstype(ri, rcp->rss_hash_type); } else { ri->iri_rsstype = M_HASHTYPE_NONE; } ags = (rcp->agg_bufs_v1 & RX_PKT_CMPL_AGG_BUFS_MASK) >> RX_PKT_CMPL_AGG_BUFS_SFT; ri->iri_nfrags = ags + 1; /* No need to byte-swap the opaque value */ ri->iri_frags[0].irf_flid = (rcp->opaque >> 16) & 0xff; ri->iri_frags[0].irf_idx = rcp->opaque & 0xffff; ri->iri_frags[0].irf_len = le16toh(rcp->len); ri->iri_len = le16toh(rcp->len); /* Now the second 16-byte BD */ NEXT_CP_CONS_V(&cpr->ring, cpr->cons, cpr->v_bit); ri->iri_cidx = RING_NEXT(&cpr->ring, ri->iri_cidx); rcph = &((struct rx_pkt_cmpl_hi *)cpr->ring.vaddr)[cpr->cons]; flags2 = le32toh(rcph->flags2); errors = le16toh(rcph->errors_v2); if ((flags2 & RX_PKT_CMPL_FLAGS2_META_FORMAT_MASK) == RX_PKT_CMPL_FLAGS2_META_FORMAT_VLAN) { ri->iri_flags |= M_VLANTAG; /* TODO: Should this be the entire 16-bits? */ ri->iri_vtag = le32toh(rcph->metadata) & (RX_PKT_CMPL_METADATA_VID_MASK | RX_PKT_CMPL_METADATA_DE | RX_PKT_CMPL_METADATA_PRI_MASK); } if (flags2 & RX_PKT_CMPL_FLAGS2_IP_CS_CALC) { ri->iri_csum_flags |= CSUM_IP_CHECKED; if (!(errors & RX_PKT_CMPL_ERRORS_IP_CS_ERROR)) ri->iri_csum_flags |= CSUM_IP_VALID; } if (flags2 & RX_PKT_CMPL_FLAGS2_L4_CS_CALC) { ri->iri_csum_flags |= CSUM_L4_CALC; if (!(errors & RX_PKT_CMPL_ERRORS_L4_CS_ERROR)) { ri->iri_csum_flags |= CSUM_L4_VALID; ri->iri_csum_data = 0xffff; } } /* And finally the ag ring stuff. */ for (i=1; i < ri->iri_nfrags; i++) { NEXT_CP_CONS_V(&cpr->ring, cpr->cons, cpr->v_bit); ri->iri_cidx = RING_NEXT(&cpr->ring, ri->iri_cidx); acp = &((struct rx_abuf_cmpl *)cpr->ring.vaddr)[cpr->cons]; /* No need to byte-swap the opaque value */ ri->iri_frags[i].irf_flid = (acp->opaque >> 16 & 0xff); ri->iri_frags[i].irf_idx = acp->opaque & 0xffff; ri->iri_frags[i].irf_len = le16toh(acp->len); ri->iri_len += le16toh(acp->len); } return 0; } static int bnxt_pkt_get_tpa(struct bnxt_softc *softc, if_rxd_info_t ri, struct bnxt_cp_ring *cpr, uint16_t flags_type) { struct rx_tpa_end_cmpl *agend = &((struct rx_tpa_end_cmpl *)cpr->ring.vaddr)[cpr->cons]; struct rx_tpa_end_cmpl_hi *agendh; struct rx_abuf_cmpl *acp; struct bnxt_full_tpa_start *tpas; uint32_t flags2; uint8_t ags; uint8_t agg_id; int i; /* Get the agg_id */ agg_id = (agend->agg_id & RX_TPA_END_CMPL_AGG_ID_MASK) >> RX_TPA_END_CMPL_AGG_ID_SFT; tpas = &softc->tpa_start[agg_id]; /* Extract from the first 16-byte BD */ if (le16toh(tpas->low.flags_type) & RX_TPA_START_CMPL_FLAGS_RSS_VALID) { ri->iri_flowid = le32toh(tpas->low.rss_hash); - /* - * TODO: Extract something useful from tpas->low.rss_hash_type - * (undocumented) - * May be documented in the "LSI ES" - * also check the firmware code. - */ - ri->iri_rsstype = M_HASHTYPE_OPAQUE; + bnxt_set_rsstype(ri, tpas->low.rss_hash_type); } else { ri->iri_rsstype = M_HASHTYPE_NONE; } ags = (agend->agg_bufs_v1 & RX_TPA_END_CMPL_AGG_BUFS_MASK) >> RX_TPA_END_CMPL_AGG_BUFS_SFT; ri->iri_nfrags = ags + 1; /* No need to byte-swap the opaque value */ ri->iri_frags[0].irf_flid = (tpas->low.opaque >> 16) & 0xff; ri->iri_frags[0].irf_idx = tpas->low.opaque & 0xffff; ri->iri_frags[0].irf_len = le16toh(tpas->low.len); ri->iri_len = le16toh(tpas->low.len); /* Now the second 16-byte BD */ NEXT_CP_CONS_V(&cpr->ring, cpr->cons, cpr->v_bit); ri->iri_cidx = RING_NEXT(&cpr->ring, ri->iri_cidx); agendh = &((struct rx_tpa_end_cmpl_hi *)cpr->ring.vaddr)[cpr->cons]; flags2 = le32toh(tpas->high.flags2); if ((flags2 & RX_TPA_START_CMPL_FLAGS2_META_FORMAT_MASK) == RX_TPA_START_CMPL_FLAGS2_META_FORMAT_VLAN) { ri->iri_flags |= M_VLANTAG; /* TODO: Should this be the entire 16-bits? */ ri->iri_vtag = le32toh(tpas->high.metadata) & (RX_TPA_START_CMPL_METADATA_VID_MASK | RX_TPA_START_CMPL_METADATA_DE | RX_TPA_START_CMPL_METADATA_PRI_MASK); } if (flags2 & RX_TPA_START_CMPL_FLAGS2_IP_CS_CALC) { ri->iri_csum_flags |= CSUM_IP_CHECKED; ri->iri_csum_flags |= CSUM_IP_VALID; } if (flags2 & RX_TPA_START_CMPL_FLAGS2_L4_CS_CALC) { ri->iri_csum_flags |= CSUM_L4_CALC; ri->iri_csum_flags |= CSUM_L4_VALID; ri->iri_csum_data = 0xffff; } /* Now the ag ring stuff. */ for (i=1; i < ri->iri_nfrags; i++) { NEXT_CP_CONS_V(&cpr->ring, cpr->cons, cpr->v_bit); ri->iri_cidx = RING_NEXT(&cpr->ring, ri->iri_cidx); acp = &((struct rx_abuf_cmpl *)cpr->ring.vaddr)[cpr->cons]; /* No need to byte-swap the opaque value */ ri->iri_frags[i].irf_flid = (acp->opaque >> 16) & 0xff; ri->iri_frags[i].irf_idx = acp->opaque & 0xffff; ri->iri_frags[i].irf_len = le16toh(acp->len); ri->iri_len += le16toh(acp->len); } /* And finally, the empty BD at the end... */ ri->iri_nfrags++; /* No need to byte-swap the opaque value */ ri->iri_frags[i].irf_flid = (agend->opaque >> 16) % 0xff; ri->iri_frags[i].irf_idx = agend->opaque & 0xffff; ri->iri_frags[i].irf_len = le16toh(agend->len); ri->iri_len += le16toh(agend->len); return 0; } /* If we return anything but zero, iflib will assert... */ static int bnxt_isc_rxd_pkt_get(void *sc, if_rxd_info_t ri) { struct bnxt_softc *softc = (struct bnxt_softc *)sc; struct bnxt_cp_ring *cpr = &softc->rx_cp_rings[ri->iri_qsidx]; struct cmpl_base *cmp; uint16_t flags_type; uint16_t type; for (;;) { NEXT_CP_CONS_V(&cpr->ring, cpr->cons, cpr->v_bit); ri->iri_cidx = RING_NEXT(&cpr->ring, ri->iri_cidx); CMPL_PREFETCH_NEXT(cpr, cpr->cons); cmp = &((struct cmpl_base *)cpr->ring.vaddr)[cpr->cons]; flags_type = le16toh(cmp->type); type = flags_type & CMPL_BASE_TYPE_MASK; switch (type) { case CMPL_BASE_TYPE_RX_L2: return bnxt_pkt_get_l2(softc, ri, cpr, flags_type); case CMPL_BASE_TYPE_RX_TPA_END: return bnxt_pkt_get_tpa(softc, ri, cpr, flags_type); case CMPL_BASE_TYPE_RX_TPA_START: NEXT_CP_CONS_V(&cpr->ring, cpr->cons, cpr->v_bit); ri->iri_cidx = RING_NEXT(&cpr->ring, ri->iri_cidx); CMPL_PREFETCH_NEXT(cpr, cpr->cons); break; default: device_printf(softc->dev, "Unhandled completion type %d on RXQ %d get\n", type, ri->iri_qsidx); if (type & 1) { NEXT_CP_CONS_V(&cpr->ring, cpr->cons, cpr->v_bit); ri->iri_cidx = RING_NEXT(&cpr->ring, ri->iri_cidx); CMPL_PREFETCH_NEXT(cpr, cpr->cons); } break; } } return 0; } static int bnxt_intr(void *sc) { struct bnxt_softc *softc = (struct bnxt_softc *)sc; device_printf(softc->dev, "STUB: %s @ %s:%d\n", __func__, __FILE__, __LINE__); return ENOSYS; }