16c8d8eccSSepherosa Ziehau /* 26c8d8eccSSepherosa Ziehau * Copyright (c) 2001 Wind River Systems 36c8d8eccSSepherosa Ziehau * Copyright (c) 1997, 1998, 1999, 2001 46c8d8eccSSepherosa Ziehau * Bill Paul <wpaul@windriver.com>. All rights reserved. 56c8d8eccSSepherosa Ziehau * 66c8d8eccSSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 76c8d8eccSSepherosa Ziehau * modification, are permitted provided that the following conditions 86c8d8eccSSepherosa Ziehau * are met: 96c8d8eccSSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 106c8d8eccSSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 116c8d8eccSSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 126c8d8eccSSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 136c8d8eccSSepherosa Ziehau * documentation and/or other materials provided with the distribution. 146c8d8eccSSepherosa Ziehau * 3. All advertising materials mentioning features or use of this software 156c8d8eccSSepherosa Ziehau * must display the following acknowledgement: 166c8d8eccSSepherosa Ziehau * This product includes software developed by Bill Paul. 176c8d8eccSSepherosa Ziehau * 4. Neither the name of the author nor the names of any co-contributors 186c8d8eccSSepherosa Ziehau * may be used to endorse or promote products derived from this software 196c8d8eccSSepherosa Ziehau * without specific prior written permission. 206c8d8eccSSepherosa Ziehau * 216c8d8eccSSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 226c8d8eccSSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 236c8d8eccSSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 246c8d8eccSSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 256c8d8eccSSepherosa Ziehau * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 266c8d8eccSSepherosa Ziehau * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 276c8d8eccSSepherosa Ziehau * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 286c8d8eccSSepherosa Ziehau * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 296c8d8eccSSepherosa Ziehau * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 306c8d8eccSSepherosa Ziehau * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 316c8d8eccSSepherosa Ziehau * THE POSSIBILITY OF SUCH DAMAGE. 326c8d8eccSSepherosa Ziehau * 336c8d8eccSSepherosa Ziehau * $FreeBSD: src/sys/dev/bge/if_bge.c,v 1.3.2.39 2005/07/03 03:41:18 silby Exp $ 346c8d8eccSSepherosa Ziehau */ 356c8d8eccSSepherosa Ziehau 3666deb1c1SSepherosa Ziehau #include "opt_bnx.h" 3739a8d43aSSepherosa Ziehau #include "opt_ifpoll.h" 386c8d8eccSSepherosa Ziehau 396c8d8eccSSepherosa Ziehau #include <sys/param.h> 406c8d8eccSSepherosa Ziehau #include <sys/bus.h> 416c8d8eccSSepherosa Ziehau #include <sys/endian.h> 426c8d8eccSSepherosa Ziehau #include <sys/kernel.h> 436c8d8eccSSepherosa Ziehau #include <sys/interrupt.h> 446c8d8eccSSepherosa Ziehau #include <sys/mbuf.h> 456c8d8eccSSepherosa Ziehau #include <sys/malloc.h> 466c8d8eccSSepherosa Ziehau #include <sys/queue.h> 476c8d8eccSSepherosa Ziehau #include <sys/rman.h> 486c8d8eccSSepherosa Ziehau #include <sys/serialize.h> 496c8d8eccSSepherosa Ziehau #include <sys/socket.h> 506c8d8eccSSepherosa Ziehau #include <sys/sockio.h> 516c8d8eccSSepherosa Ziehau #include <sys/sysctl.h> 526c8d8eccSSepherosa Ziehau 5366deb1c1SSepherosa Ziehau #include <netinet/ip.h> 5466deb1c1SSepherosa Ziehau #include <netinet/tcp.h> 5566deb1c1SSepherosa Ziehau 566c8d8eccSSepherosa Ziehau #include <net/bpf.h> 576c8d8eccSSepherosa Ziehau #include <net/ethernet.h> 586c8d8eccSSepherosa Ziehau #include <net/if.h> 596c8d8eccSSepherosa Ziehau #include <net/if_arp.h> 606c8d8eccSSepherosa Ziehau #include <net/if_dl.h> 616c8d8eccSSepherosa Ziehau #include <net/if_media.h> 6239a8d43aSSepherosa Ziehau #include <net/if_poll.h> 636c8d8eccSSepherosa Ziehau #include <net/if_types.h> 646c8d8eccSSepherosa Ziehau #include <net/ifq_var.h> 65695a8586SSepherosa Ziehau #include <net/toeplitz.h> 66695a8586SSepherosa Ziehau #include <net/toeplitz2.h> 676c8d8eccSSepherosa Ziehau #include <net/vlan/if_vlan_var.h> 686c8d8eccSSepherosa Ziehau #include <net/vlan/if_vlan_ether.h> 696c8d8eccSSepherosa Ziehau 706c8d8eccSSepherosa Ziehau #include <dev/netif/mii_layer/mii.h> 716c8d8eccSSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h> 726c8d8eccSSepherosa Ziehau #include <dev/netif/mii_layer/brgphyreg.h> 736c8d8eccSSepherosa Ziehau 746c8d8eccSSepherosa Ziehau #include <bus/pci/pcidevs.h> 756c8d8eccSSepherosa Ziehau #include <bus/pci/pcireg.h> 766c8d8eccSSepherosa Ziehau #include <bus/pci/pcivar.h> 776c8d8eccSSepherosa Ziehau 786c8d8eccSSepherosa Ziehau #include <dev/netif/bge/if_bgereg.h> 796c8d8eccSSepherosa Ziehau #include <dev/netif/bnx/if_bnxvar.h> 806c8d8eccSSepherosa Ziehau 816c8d8eccSSepherosa Ziehau /* "device miibus" required. See GENERIC if you get errors here. */ 826c8d8eccSSepherosa Ziehau #include "miibus_if.h" 836c8d8eccSSepherosa Ziehau 843b18363fSSepherosa Ziehau #define BNX_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 856c8d8eccSSepherosa Ziehau 86df9ccc98SSepherosa Ziehau #define BNX_INTR_CKINTVL ((10 * hz) / 1000) /* 10ms */ 87df9ccc98SSepherosa Ziehau 88695a8586SSepherosa Ziehau #ifdef BNX_RSS_DEBUG 89695a8586SSepherosa Ziehau #define BNX_RSS_DPRINTF(sc, lvl, fmt, ...) \ 90695a8586SSepherosa Ziehau do { \ 91695a8586SSepherosa Ziehau if (sc->bnx_rss_debug >= lvl) \ 92695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, fmt, __VA_ARGS__); \ 93695a8586SSepherosa Ziehau } while (0) 94695a8586SSepherosa Ziehau #else /* !BNX_RSS_DEBUG */ 95695a8586SSepherosa Ziehau #define BNX_RSS_DPRINTF(sc, lvl, fmt, ...) ((void)0) 96695a8586SSepherosa Ziehau #endif /* BNX_RSS_DEBUG */ 97695a8586SSepherosa Ziehau 986c8d8eccSSepherosa Ziehau static const struct bnx_type { 996c8d8eccSSepherosa Ziehau uint16_t bnx_vid; 1006c8d8eccSSepherosa Ziehau uint16_t bnx_did; 1016c8d8eccSSepherosa Ziehau char *bnx_name; 1026c8d8eccSSepherosa Ziehau } bnx_devs[] = { 1036c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5717, 1046c8d8eccSSepherosa Ziehau "Broadcom BCM5717 Gigabit Ethernet" }, 105d79f5d8fSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5717C, 106d79f5d8fSSepherosa Ziehau "Broadcom BCM5717C Gigabit Ethernet" }, 1076c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5718, 1086c8d8eccSSepherosa Ziehau "Broadcom BCM5718 Gigabit Ethernet" }, 1096c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5719, 1106c8d8eccSSepherosa Ziehau "Broadcom BCM5719 Gigabit Ethernet" }, 1116c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5720_ALT, 1126c8d8eccSSepherosa Ziehau "Broadcom BCM5720 Gigabit Ethernet" }, 1136c8d8eccSSepherosa Ziehau 114b96cbbb6SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5725, 115b96cbbb6SSepherosa Ziehau "Broadcom BCM5725 Gigabit Ethernet" }, 116b96cbbb6SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5727, 117b96cbbb6SSepherosa Ziehau "Broadcom BCM5727 Gigabit Ethernet" }, 118b96cbbb6SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5762, 119b96cbbb6SSepherosa Ziehau "Broadcom BCM5762 Gigabit Ethernet" }, 120b96cbbb6SSepherosa Ziehau 1216c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57761, 1226c8d8eccSSepherosa Ziehau "Broadcom BCM57761 Gigabit Ethernet" }, 12332ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57762, 12432ff3c80SSepherosa Ziehau "Broadcom BCM57762 Gigabit Ethernet" }, 1256c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57765, 1266c8d8eccSSepherosa Ziehau "Broadcom BCM57765 Gigabit Ethernet" }, 12732ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57766, 12832ff3c80SSepherosa Ziehau "Broadcom BCM57766 Gigabit Ethernet" }, 12932ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57781, 13032ff3c80SSepherosa Ziehau "Broadcom BCM57781 Gigabit Ethernet" }, 13132ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57782, 13232ff3c80SSepherosa Ziehau "Broadcom BCM57782 Gigabit Ethernet" }, 1336c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57785, 1346c8d8eccSSepherosa Ziehau "Broadcom BCM57785 Gigabit Ethernet" }, 13532ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57786, 13632ff3c80SSepherosa Ziehau "Broadcom BCM57786 Gigabit Ethernet" }, 13732ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57791, 13832ff3c80SSepherosa Ziehau "Broadcom BCM57791 Fast Ethernet" }, 1396c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57795, 1406c8d8eccSSepherosa Ziehau "Broadcom BCM57795 Fast Ethernet" }, 1416c8d8eccSSepherosa Ziehau 1426c8d8eccSSepherosa Ziehau { 0, 0, NULL } 1436c8d8eccSSepherosa Ziehau }; 1446c8d8eccSSepherosa Ziehau 1451c9d03f6SSepherosa Ziehau static const int bnx_tx_mailbox[BNX_TX_RING_MAX] = { 1461c9d03f6SSepherosa Ziehau BGE_MBX_TX_HOST_PROD0_LO, 1471c9d03f6SSepherosa Ziehau BGE_MBX_TX_HOST_PROD0_HI, 1481c9d03f6SSepherosa Ziehau BGE_MBX_TX_HOST_PROD1_LO, 1491c9d03f6SSepherosa Ziehau BGE_MBX_TX_HOST_PROD1_HI 1501c9d03f6SSepherosa Ziehau }; 1511c9d03f6SSepherosa Ziehau 1526c8d8eccSSepherosa Ziehau #define BNX_IS_JUMBO_CAPABLE(sc) ((sc)->bnx_flags & BNX_FLAG_JUMBO) 1536c8d8eccSSepherosa Ziehau #define BNX_IS_5717_PLUS(sc) ((sc)->bnx_flags & BNX_FLAG_5717_PLUS) 154f368d0d9SSepherosa Ziehau #define BNX_IS_57765_PLUS(sc) ((sc)->bnx_flags & BNX_FLAG_57765_PLUS) 155f368d0d9SSepherosa Ziehau #define BNX_IS_57765_FAMILY(sc) \ 156f368d0d9SSepherosa Ziehau ((sc)->bnx_flags & BNX_FLAG_57765_FAMILY) 1576c8d8eccSSepherosa Ziehau 1586c8d8eccSSepherosa Ziehau typedef int (*bnx_eaddr_fcn_t)(struct bnx_softc *, uint8_t[]); 1596c8d8eccSSepherosa Ziehau 1606c8d8eccSSepherosa Ziehau static int bnx_probe(device_t); 1616c8d8eccSSepherosa Ziehau static int bnx_attach(device_t); 1626c8d8eccSSepherosa Ziehau static int bnx_detach(device_t); 1636c8d8eccSSepherosa Ziehau static void bnx_shutdown(device_t); 1646c8d8eccSSepherosa Ziehau static int bnx_suspend(device_t); 1656c8d8eccSSepherosa Ziehau static int bnx_resume(device_t); 1666c8d8eccSSepherosa Ziehau static int bnx_miibus_readreg(device_t, int, int); 1676c8d8eccSSepherosa Ziehau static int bnx_miibus_writereg(device_t, int, int, int); 1686c8d8eccSSepherosa Ziehau static void bnx_miibus_statchg(device_t); 1696c8d8eccSSepherosa Ziehau 17024e16e4bSSepherosa Ziehau static int bnx_handle_status(struct bnx_softc *); 17139a8d43aSSepherosa Ziehau #ifdef IFPOLL_ENABLE 17239a8d43aSSepherosa Ziehau static void bnx_npoll(struct ifnet *, struct ifpoll_info *); 1734fa38985SSepherosa Ziehau static void bnx_npoll_rx(struct ifnet *, void *, int); 1744fa38985SSepherosa Ziehau static void bnx_npoll_tx(struct ifnet *, void *, int); 175695a8586SSepherosa Ziehau static void bnx_npoll_tx_notag(struct ifnet *, void *, int); 1764fa38985SSepherosa Ziehau static void bnx_npoll_status(struct ifnet *); 177695a8586SSepherosa Ziehau static void bnx_npoll_status_notag(struct ifnet *); 1786c8d8eccSSepherosa Ziehau #endif 1796c8d8eccSSepherosa Ziehau static void bnx_intr_legacy(void *); 18003cc99fdSSepherosa Ziehau static void bnx_msi(void *); 1816c8d8eccSSepherosa Ziehau static void bnx_intr(struct bnx_softc *); 182695a8586SSepherosa Ziehau static void bnx_msix_status(void *); 183695a8586SSepherosa Ziehau static void bnx_msix_tx_status(void *); 184695a8586SSepherosa Ziehau static void bnx_msix_rx(void *); 185695a8586SSepherosa Ziehau static void bnx_msix_rxtx(void *); 1866c8d8eccSSepherosa Ziehau static void bnx_enable_intr(struct bnx_softc *); 1876c8d8eccSSepherosa Ziehau static void bnx_disable_intr(struct bnx_softc *); 18833a04907SSepherosa Ziehau static void bnx_txeof(struct bnx_tx_ring *, uint16_t); 189beedf5beSSepherosa Ziehau static void bnx_rxeof(struct bnx_rx_ret_ring *, uint16_t, int); 1900c7da01dSSepherosa Ziehau static int bnx_alloc_intr(struct bnx_softc *); 1910c7da01dSSepherosa Ziehau static int bnx_setup_intr(struct bnx_softc *); 1920c7da01dSSepherosa Ziehau static void bnx_free_intr(struct bnx_softc *); 193f33ac8a4SSepherosa Ziehau static void bnx_teardown_intr(struct bnx_softc *, int); 194695a8586SSepherosa Ziehau static int bnx_alloc_msix(struct bnx_softc *); 195695a8586SSepherosa Ziehau static void bnx_free_msix(struct bnx_softc *, boolean_t); 196695a8586SSepherosa Ziehau static void bnx_check_intr_rxtx(void *); 197695a8586SSepherosa Ziehau static void bnx_check_intr_rx(void *); 198695a8586SSepherosa Ziehau static void bnx_check_intr_tx(void *); 199841cdf08SSepherosa Ziehau static void bnx_rx_std_refill_ithread(void *); 200841cdf08SSepherosa Ziehau static void bnx_rx_std_refill(void *, void *); 201695a8586SSepherosa Ziehau static void bnx_rx_std_refill_sched_ipi(void *); 202695a8586SSepherosa Ziehau static void bnx_rx_std_refill_stop(void *); 203695a8586SSepherosa Ziehau static void bnx_rx_std_refill_sched(struct bnx_rx_ret_ring *, 204695a8586SSepherosa Ziehau struct bnx_rx_std_ring *); 2056c8d8eccSSepherosa Ziehau 206f0a26983SSepherosa Ziehau static void bnx_start(struct ifnet *, struct ifaltq_subque *); 2076c8d8eccSSepherosa Ziehau static int bnx_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 2086c8d8eccSSepherosa Ziehau static void bnx_init(void *); 2096c8d8eccSSepherosa Ziehau static void bnx_stop(struct bnx_softc *); 2103397dea6SSepherosa Ziehau static void bnx_watchdog(struct ifaltq_subque *); 2116c8d8eccSSepherosa Ziehau static int bnx_ifmedia_upd(struct ifnet *); 2126c8d8eccSSepherosa Ziehau static void bnx_ifmedia_sts(struct ifnet *, struct ifmediareq *); 2136c8d8eccSSepherosa Ziehau static void bnx_tick(void *); 214329f9016SSepherosa Ziehau static void bnx_serialize(struct ifnet *, enum ifnet_serialize); 215329f9016SSepherosa Ziehau static void bnx_deserialize(struct ifnet *, enum ifnet_serialize); 216329f9016SSepherosa Ziehau static int bnx_tryserialize(struct ifnet *, enum ifnet_serialize); 217329f9016SSepherosa Ziehau #ifdef INVARIANTS 218329f9016SSepherosa Ziehau static void bnx_serialize_assert(struct ifnet *, enum ifnet_serialize, 219329f9016SSepherosa Ziehau boolean_t); 220329f9016SSepherosa Ziehau #endif 221695a8586SSepherosa Ziehau static void bnx_serialize_skipmain(struct bnx_softc *); 222695a8586SSepherosa Ziehau static void bnx_deserialize_skipmain(struct bnx_softc *sc); 2236c8d8eccSSepherosa Ziehau 2246c8d8eccSSepherosa Ziehau static int bnx_alloc_jumbo_mem(struct bnx_softc *); 2256c8d8eccSSepherosa Ziehau static void bnx_free_jumbo_mem(struct bnx_softc *); 2266c8d8eccSSepherosa Ziehau static struct bnx_jslot 2276c8d8eccSSepherosa Ziehau *bnx_jalloc(struct bnx_softc *); 2286c8d8eccSSepherosa Ziehau static void bnx_jfree(void *); 2296c8d8eccSSepherosa Ziehau static void bnx_jref(void *); 230beedf5beSSepherosa Ziehau static int bnx_newbuf_std(struct bnx_rx_ret_ring *, int, int); 2316c8d8eccSSepherosa Ziehau static int bnx_newbuf_jumbo(struct bnx_softc *, int, int); 232beedf5beSSepherosa Ziehau static void bnx_setup_rxdesc_std(struct bnx_rx_std_ring *, int); 2336c8d8eccSSepherosa Ziehau static void bnx_setup_rxdesc_jumbo(struct bnx_softc *, int); 234beedf5beSSepherosa Ziehau static int bnx_init_rx_ring_std(struct bnx_rx_std_ring *); 235beedf5beSSepherosa Ziehau static void bnx_free_rx_ring_std(struct bnx_rx_std_ring *); 2366c8d8eccSSepherosa Ziehau static int bnx_init_rx_ring_jumbo(struct bnx_softc *); 2376c8d8eccSSepherosa Ziehau static void bnx_free_rx_ring_jumbo(struct bnx_softc *); 23833a04907SSepherosa Ziehau static void bnx_free_tx_ring(struct bnx_tx_ring *); 23933a04907SSepherosa Ziehau static int bnx_init_tx_ring(struct bnx_tx_ring *); 24033a04907SSepherosa Ziehau static int bnx_create_tx_ring(struct bnx_tx_ring *); 24133a04907SSepherosa Ziehau static void bnx_destroy_tx_ring(struct bnx_tx_ring *); 242beedf5beSSepherosa Ziehau static int bnx_create_rx_ret_ring(struct bnx_rx_ret_ring *); 243beedf5beSSepherosa Ziehau static void bnx_destroy_rx_ret_ring(struct bnx_rx_ret_ring *); 244beedf5beSSepherosa Ziehau static int bnx_dma_alloc(device_t); 2456c8d8eccSSepherosa Ziehau static void bnx_dma_free(struct bnx_softc *); 2466c8d8eccSSepherosa Ziehau static int bnx_dma_block_alloc(struct bnx_softc *, bus_size_t, 2476c8d8eccSSepherosa Ziehau bus_dma_tag_t *, bus_dmamap_t *, void **, bus_addr_t *); 2486c8d8eccSSepherosa Ziehau static void bnx_dma_block_free(bus_dma_tag_t, bus_dmamap_t, void *); 2496c8d8eccSSepherosa Ziehau static struct mbuf * 2506c8d8eccSSepherosa Ziehau bnx_defrag_shortdma(struct mbuf *); 25133a04907SSepherosa Ziehau static int bnx_encap(struct bnx_tx_ring *, struct mbuf **, 252c9b7f592SSepherosa Ziehau uint32_t *, int *); 25333a04907SSepherosa Ziehau static int bnx_setup_tso(struct bnx_tx_ring *, struct mbuf **, 25466deb1c1SSepherosa Ziehau uint16_t *, uint16_t *); 255329f9016SSepherosa Ziehau static void bnx_setup_serialize(struct bnx_softc *); 2567dbaa833SSepherosa Ziehau static void bnx_set_tick_cpuid(struct bnx_softc *, boolean_t); 257695a8586SSepherosa Ziehau static void bnx_setup_ring_cnt(struct bnx_softc *); 2586c8d8eccSSepherosa Ziehau 259b19ddf7eSSepherosa Ziehau static struct pktinfo *bnx_rss_info(struct pktinfo *, 260b19ddf7eSSepherosa Ziehau const struct bge_rx_bd *); 261695a8586SSepherosa Ziehau static void bnx_init_rss(struct bnx_softc *); 2626c8d8eccSSepherosa Ziehau static void bnx_reset(struct bnx_softc *); 2636c8d8eccSSepherosa Ziehau static int bnx_chipinit(struct bnx_softc *); 2646c8d8eccSSepherosa Ziehau static int bnx_blockinit(struct bnx_softc *); 2656c8d8eccSSepherosa Ziehau static void bnx_stop_block(struct bnx_softc *, bus_size_t, uint32_t); 266695a8586SSepherosa Ziehau static void bnx_enable_msi(struct bnx_softc *, boolean_t); 2676c8d8eccSSepherosa Ziehau static void bnx_setmulti(struct bnx_softc *); 2686c8d8eccSSepherosa Ziehau static void bnx_setpromisc(struct bnx_softc *); 2696c8d8eccSSepherosa Ziehau static void bnx_stats_update_regs(struct bnx_softc *); 2706c8d8eccSSepherosa Ziehau static uint32_t bnx_dma_swap_options(struct bnx_softc *); 2716c8d8eccSSepherosa Ziehau 2726c8d8eccSSepherosa Ziehau static uint32_t bnx_readmem_ind(struct bnx_softc *, uint32_t); 2736c8d8eccSSepherosa Ziehau static void bnx_writemem_ind(struct bnx_softc *, uint32_t, uint32_t); 2746c8d8eccSSepherosa Ziehau #ifdef notdef 2756c8d8eccSSepherosa Ziehau static uint32_t bnx_readreg_ind(struct bnx_softc *, uint32_t); 2766c8d8eccSSepherosa Ziehau #endif 2776c8d8eccSSepherosa Ziehau static void bnx_writemem_direct(struct bnx_softc *, uint32_t, uint32_t); 2786c8d8eccSSepherosa Ziehau static void bnx_writembx(struct bnx_softc *, int, int); 2796c8d8eccSSepherosa Ziehau static int bnx_read_nvram(struct bnx_softc *, caddr_t, int, int); 2806c8d8eccSSepherosa Ziehau static uint8_t bnx_eeprom_getbyte(struct bnx_softc *, uint32_t, uint8_t *); 2816c8d8eccSSepherosa Ziehau static int bnx_read_eeprom(struct bnx_softc *, caddr_t, uint32_t, size_t); 2826c8d8eccSSepherosa Ziehau 2836c8d8eccSSepherosa Ziehau static void bnx_tbi_link_upd(struct bnx_softc *, uint32_t); 2846c8d8eccSSepherosa Ziehau static void bnx_copper_link_upd(struct bnx_softc *, uint32_t); 2856c8d8eccSSepherosa Ziehau static void bnx_autopoll_link_upd(struct bnx_softc *, uint32_t); 2866c8d8eccSSepherosa Ziehau static void bnx_link_poll(struct bnx_softc *); 2876c8d8eccSSepherosa Ziehau 2886c8d8eccSSepherosa Ziehau static int bnx_get_eaddr_mem(struct bnx_softc *, uint8_t[]); 2896c8d8eccSSepherosa Ziehau static int bnx_get_eaddr_nvram(struct bnx_softc *, uint8_t[]); 2906c8d8eccSSepherosa Ziehau static int bnx_get_eaddr_eeprom(struct bnx_softc *, uint8_t[]); 2916c8d8eccSSepherosa Ziehau static int bnx_get_eaddr(struct bnx_softc *, uint8_t[]); 2926c8d8eccSSepherosa Ziehau 2936c8d8eccSSepherosa Ziehau static void bnx_coal_change(struct bnx_softc *); 294aad4de2bSSepherosa Ziehau static int bnx_sysctl_force_defrag(SYSCTL_HANDLER_ARGS); 295472c99c8SSepherosa Ziehau static int bnx_sysctl_tx_wreg(SYSCTL_HANDLER_ARGS); 2966c8d8eccSSepherosa Ziehau static int bnx_sysctl_rx_coal_ticks(SYSCTL_HANDLER_ARGS); 2976c8d8eccSSepherosa Ziehau static int bnx_sysctl_tx_coal_ticks(SYSCTL_HANDLER_ARGS); 2986c8d8eccSSepherosa Ziehau static int bnx_sysctl_rx_coal_bds(SYSCTL_HANDLER_ARGS); 299a86cc105SSepherosa Ziehau static int bnx_sysctl_rx_coal_bds_poll(SYSCTL_HANDLER_ARGS); 3006c8d8eccSSepherosa Ziehau static int bnx_sysctl_tx_coal_bds(SYSCTL_HANDLER_ARGS); 30127357d84SSepherosa Ziehau static int bnx_sysctl_tx_coal_bds_poll(SYSCTL_HANDLER_ARGS); 3026c8d8eccSSepherosa Ziehau static int bnx_sysctl_rx_coal_bds_int(SYSCTL_HANDLER_ARGS); 3036c8d8eccSSepherosa Ziehau static int bnx_sysctl_tx_coal_bds_int(SYSCTL_HANDLER_ARGS); 3046c8d8eccSSepherosa Ziehau static int bnx_sysctl_coal_chg(SYSCTL_HANDLER_ARGS, uint32_t *, 3056c8d8eccSSepherosa Ziehau int, int, uint32_t); 3064fa38985SSepherosa Ziehau #ifdef IFPOLL_ENABLE 3074fa38985SSepherosa Ziehau static int bnx_sysctl_npoll_offset(SYSCTL_HANDLER_ARGS); 3084fa38985SSepherosa Ziehau static int bnx_sysctl_npoll_rxoff(SYSCTL_HANDLER_ARGS); 3094fa38985SSepherosa Ziehau static int bnx_sysctl_npoll_txoff(SYSCTL_HANDLER_ARGS); 3104fa38985SSepherosa Ziehau #endif 311841cdf08SSepherosa Ziehau static int bnx_sysctl_std_refill(SYSCTL_HANDLER_ARGS); 3126c8d8eccSSepherosa Ziehau 3136c8d8eccSSepherosa Ziehau static int bnx_msi_enable = 1; 314695a8586SSepherosa Ziehau static int bnx_msix_enable = 1; 315695a8586SSepherosa Ziehau 316695a8586SSepherosa Ziehau static int bnx_rx_rings = 0; /* auto */ 317695a8586SSepherosa Ziehau static int bnx_tx_rings = 0; /* auto */ 318695a8586SSepherosa Ziehau 3196c8d8eccSSepherosa Ziehau TUNABLE_INT("hw.bnx.msi.enable", &bnx_msi_enable); 320695a8586SSepherosa Ziehau TUNABLE_INT("hw.bnx.msix.enable", &bnx_msix_enable); 321695a8586SSepherosa Ziehau TUNABLE_INT("hw.bnx.rx_rings", &bnx_rx_rings); 322695a8586SSepherosa Ziehau TUNABLE_INT("hw.bnx.tx_rings", &bnx_tx_rings); 3236c8d8eccSSepherosa Ziehau 3246c8d8eccSSepherosa Ziehau static device_method_t bnx_methods[] = { 3256c8d8eccSSepherosa Ziehau /* Device interface */ 3266c8d8eccSSepherosa Ziehau DEVMETHOD(device_probe, bnx_probe), 3276c8d8eccSSepherosa Ziehau DEVMETHOD(device_attach, bnx_attach), 3286c8d8eccSSepherosa Ziehau DEVMETHOD(device_detach, bnx_detach), 3296c8d8eccSSepherosa Ziehau DEVMETHOD(device_shutdown, bnx_shutdown), 3306c8d8eccSSepherosa Ziehau DEVMETHOD(device_suspend, bnx_suspend), 3316c8d8eccSSepherosa Ziehau DEVMETHOD(device_resume, bnx_resume), 3326c8d8eccSSepherosa Ziehau 3336c8d8eccSSepherosa Ziehau /* bus interface */ 3346c8d8eccSSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 3356c8d8eccSSepherosa Ziehau DEVMETHOD(bus_driver_added, bus_generic_driver_added), 3366c8d8eccSSepherosa Ziehau 3376c8d8eccSSepherosa Ziehau /* MII interface */ 3386c8d8eccSSepherosa Ziehau DEVMETHOD(miibus_readreg, bnx_miibus_readreg), 3396c8d8eccSSepherosa Ziehau DEVMETHOD(miibus_writereg, bnx_miibus_writereg), 3406c8d8eccSSepherosa Ziehau DEVMETHOD(miibus_statchg, bnx_miibus_statchg), 3416c8d8eccSSepherosa Ziehau 342d3c9c58eSSascha Wildner DEVMETHOD_END 3436c8d8eccSSepherosa Ziehau }; 3446c8d8eccSSepherosa Ziehau 3456c8d8eccSSepherosa Ziehau static DEFINE_CLASS_0(bnx, bnx_driver, bnx_methods, sizeof(struct bnx_softc)); 3466c8d8eccSSepherosa Ziehau static devclass_t bnx_devclass; 3476c8d8eccSSepherosa Ziehau 3486c8d8eccSSepherosa Ziehau DECLARE_DUMMY_MODULE(if_bnx); 3496c8d8eccSSepherosa Ziehau DRIVER_MODULE(if_bnx, pci, bnx_driver, bnx_devclass, NULL, NULL); 3506c8d8eccSSepherosa Ziehau DRIVER_MODULE(miibus, bnx, miibus_driver, miibus_devclass, NULL, NULL); 3516c8d8eccSSepherosa Ziehau 3526c8d8eccSSepherosa Ziehau static uint32_t 3536c8d8eccSSepherosa Ziehau bnx_readmem_ind(struct bnx_softc *sc, uint32_t off) 3546c8d8eccSSepherosa Ziehau { 3556c8d8eccSSepherosa Ziehau device_t dev = sc->bnx_dev; 3566c8d8eccSSepherosa Ziehau uint32_t val; 3576c8d8eccSSepherosa Ziehau 3586c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4); 3596c8d8eccSSepherosa Ziehau val = pci_read_config(dev, BGE_PCI_MEMWIN_DATA, 4); 3606c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4); 3616c8d8eccSSepherosa Ziehau return (val); 3626c8d8eccSSepherosa Ziehau } 3636c8d8eccSSepherosa Ziehau 3646c8d8eccSSepherosa Ziehau static void 3656c8d8eccSSepherosa Ziehau bnx_writemem_ind(struct bnx_softc *sc, uint32_t off, uint32_t val) 3666c8d8eccSSepherosa Ziehau { 3676c8d8eccSSepherosa Ziehau device_t dev = sc->bnx_dev; 3686c8d8eccSSepherosa Ziehau 3696c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4); 3706c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_DATA, val, 4); 3716c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4); 3726c8d8eccSSepherosa Ziehau } 3736c8d8eccSSepherosa Ziehau 3746c8d8eccSSepherosa Ziehau static void 3756c8d8eccSSepherosa Ziehau bnx_writemem_direct(struct bnx_softc *sc, uint32_t off, uint32_t val) 3766c8d8eccSSepherosa Ziehau { 3776c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, off, val); 3786c8d8eccSSepherosa Ziehau } 3796c8d8eccSSepherosa Ziehau 3806c8d8eccSSepherosa Ziehau static void 3816c8d8eccSSepherosa Ziehau bnx_writembx(struct bnx_softc *sc, int off, int val) 3826c8d8eccSSepherosa Ziehau { 3836c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, off, val); 3846c8d8eccSSepherosa Ziehau } 3856c8d8eccSSepherosa Ziehau 3866c8d8eccSSepherosa Ziehau /* 3876c8d8eccSSepherosa Ziehau * Read a sequence of bytes from NVRAM. 3886c8d8eccSSepherosa Ziehau */ 3896c8d8eccSSepherosa Ziehau static int 3906c8d8eccSSepherosa Ziehau bnx_read_nvram(struct bnx_softc *sc, caddr_t dest, int off, int cnt) 3916c8d8eccSSepherosa Ziehau { 3926c8d8eccSSepherosa Ziehau return (1); 3936c8d8eccSSepherosa Ziehau } 3946c8d8eccSSepherosa Ziehau 3956c8d8eccSSepherosa Ziehau /* 3966c8d8eccSSepherosa Ziehau * Read a byte of data stored in the EEPROM at address 'addr.' The 3976c8d8eccSSepherosa Ziehau * BCM570x supports both the traditional bitbang interface and an 3986c8d8eccSSepherosa Ziehau * auto access interface for reading the EEPROM. We use the auto 3996c8d8eccSSepherosa Ziehau * access method. 4006c8d8eccSSepherosa Ziehau */ 4016c8d8eccSSepherosa Ziehau static uint8_t 4026c8d8eccSSepherosa Ziehau bnx_eeprom_getbyte(struct bnx_softc *sc, uint32_t addr, uint8_t *dest) 4036c8d8eccSSepherosa Ziehau { 4046c8d8eccSSepherosa Ziehau int i; 4056c8d8eccSSepherosa Ziehau uint32_t byte = 0; 4066c8d8eccSSepherosa Ziehau 4076c8d8eccSSepherosa Ziehau /* 4086c8d8eccSSepherosa Ziehau * Enable use of auto EEPROM access so we can avoid 4096c8d8eccSSepherosa Ziehau * having to use the bitbang method. 4106c8d8eccSSepherosa Ziehau */ 4116c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_AUTO_EEPROM); 4126c8d8eccSSepherosa Ziehau 4136c8d8eccSSepherosa Ziehau /* Reset the EEPROM, load the clock period. */ 4146c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_EE_ADDR, 4156c8d8eccSSepherosa Ziehau BGE_EEADDR_RESET|BGE_EEHALFCLK(BGE_HALFCLK_384SCL)); 4166c8d8eccSSepherosa Ziehau DELAY(20); 4176c8d8eccSSepherosa Ziehau 4186c8d8eccSSepherosa Ziehau /* Issue the read EEPROM command. */ 4196c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_EE_ADDR, BGE_EE_READCMD | addr); 4206c8d8eccSSepherosa Ziehau 4216c8d8eccSSepherosa Ziehau /* Wait for completion */ 4226c8d8eccSSepherosa Ziehau for(i = 0; i < BNX_TIMEOUT * 10; i++) { 4236c8d8eccSSepherosa Ziehau DELAY(10); 4246c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_EE_ADDR) & BGE_EEADDR_DONE) 4256c8d8eccSSepherosa Ziehau break; 4266c8d8eccSSepherosa Ziehau } 4276c8d8eccSSepherosa Ziehau 4286c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 4296c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "eeprom read timed out\n"); 4306c8d8eccSSepherosa Ziehau return(1); 4316c8d8eccSSepherosa Ziehau } 4326c8d8eccSSepherosa Ziehau 4336c8d8eccSSepherosa Ziehau /* Get result. */ 4346c8d8eccSSepherosa Ziehau byte = CSR_READ_4(sc, BGE_EE_DATA); 4356c8d8eccSSepherosa Ziehau 4366c8d8eccSSepherosa Ziehau *dest = (byte >> ((addr % 4) * 8)) & 0xFF; 4376c8d8eccSSepherosa Ziehau 4386c8d8eccSSepherosa Ziehau return(0); 4396c8d8eccSSepherosa Ziehau } 4406c8d8eccSSepherosa Ziehau 4416c8d8eccSSepherosa Ziehau /* 4426c8d8eccSSepherosa Ziehau * Read a sequence of bytes from the EEPROM. 4436c8d8eccSSepherosa Ziehau */ 4446c8d8eccSSepherosa Ziehau static int 4456c8d8eccSSepherosa Ziehau bnx_read_eeprom(struct bnx_softc *sc, caddr_t dest, uint32_t off, size_t len) 4466c8d8eccSSepherosa Ziehau { 4476c8d8eccSSepherosa Ziehau size_t i; 4486c8d8eccSSepherosa Ziehau int err; 4496c8d8eccSSepherosa Ziehau uint8_t byte; 4506c8d8eccSSepherosa Ziehau 4516c8d8eccSSepherosa Ziehau for (byte = 0, err = 0, i = 0; i < len; i++) { 4526c8d8eccSSepherosa Ziehau err = bnx_eeprom_getbyte(sc, off + i, &byte); 4536c8d8eccSSepherosa Ziehau if (err) 4546c8d8eccSSepherosa Ziehau break; 4556c8d8eccSSepherosa Ziehau *(dest + i) = byte; 4566c8d8eccSSepherosa Ziehau } 4576c8d8eccSSepherosa Ziehau 4586c8d8eccSSepherosa Ziehau return(err ? 1 : 0); 4596c8d8eccSSepherosa Ziehau } 4606c8d8eccSSepherosa Ziehau 4616c8d8eccSSepherosa Ziehau static int 4626c8d8eccSSepherosa Ziehau bnx_miibus_readreg(device_t dev, int phy, int reg) 4636c8d8eccSSepherosa Ziehau { 4646c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 4656c8d8eccSSepherosa Ziehau uint32_t val; 4666c8d8eccSSepherosa Ziehau int i; 4676c8d8eccSSepherosa Ziehau 4686c8d8eccSSepherosa Ziehau KASSERT(phy == sc->bnx_phyno, 4696c8d8eccSSepherosa Ziehau ("invalid phyno %d, should be %d", phy, sc->bnx_phyno)); 4706c8d8eccSSepherosa Ziehau 4716c8d8eccSSepherosa Ziehau /* Clear the autopoll bit if set, otherwise may trigger PCI errors. */ 4726c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 4736c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, 4746c8d8eccSSepherosa Ziehau sc->bnx_mi_mode & ~BGE_MIMODE_AUTOPOLL); 4756c8d8eccSSepherosa Ziehau DELAY(80); 4766c8d8eccSSepherosa Ziehau } 4776c8d8eccSSepherosa Ziehau 4786c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_READ | BGE_MICOMM_BUSY | 4796c8d8eccSSepherosa Ziehau BGE_MIPHY(phy) | BGE_MIREG(reg)); 4806c8d8eccSSepherosa Ziehau 4816c8d8eccSSepherosa Ziehau /* Poll for the PHY register access to complete. */ 4826c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 4836c8d8eccSSepherosa Ziehau DELAY(10); 4846c8d8eccSSepherosa Ziehau val = CSR_READ_4(sc, BGE_MI_COMM); 4856c8d8eccSSepherosa Ziehau if ((val & BGE_MICOMM_BUSY) == 0) { 4866c8d8eccSSepherosa Ziehau DELAY(5); 4876c8d8eccSSepherosa Ziehau val = CSR_READ_4(sc, BGE_MI_COMM); 4886c8d8eccSSepherosa Ziehau break; 4896c8d8eccSSepherosa Ziehau } 4906c8d8eccSSepherosa Ziehau } 4916c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 4926c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "PHY read timed out " 4936c8d8eccSSepherosa Ziehau "(phy %d, reg %d, val 0x%08x)\n", phy, reg, val); 4946c8d8eccSSepherosa Ziehau val = 0; 4956c8d8eccSSepherosa Ziehau } 4966c8d8eccSSepherosa Ziehau 4976c8d8eccSSepherosa Ziehau /* Restore the autopoll bit if necessary. */ 4986c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 4996c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, sc->bnx_mi_mode); 5006c8d8eccSSepherosa Ziehau DELAY(80); 5016c8d8eccSSepherosa Ziehau } 5026c8d8eccSSepherosa Ziehau 5036c8d8eccSSepherosa Ziehau if (val & BGE_MICOMM_READFAIL) 5046c8d8eccSSepherosa Ziehau return 0; 5056c8d8eccSSepherosa Ziehau 5066c8d8eccSSepherosa Ziehau return (val & 0xFFFF); 5076c8d8eccSSepherosa Ziehau } 5086c8d8eccSSepherosa Ziehau 5096c8d8eccSSepherosa Ziehau static int 5106c8d8eccSSepherosa Ziehau bnx_miibus_writereg(device_t dev, int phy, int reg, int val) 5116c8d8eccSSepherosa Ziehau { 5126c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 5136c8d8eccSSepherosa Ziehau int i; 5146c8d8eccSSepherosa Ziehau 5156c8d8eccSSepherosa Ziehau KASSERT(phy == sc->bnx_phyno, 5166c8d8eccSSepherosa Ziehau ("invalid phyno %d, should be %d", phy, sc->bnx_phyno)); 5176c8d8eccSSepherosa Ziehau 5186c8d8eccSSepherosa Ziehau /* Clear the autopoll bit if set, otherwise may trigger PCI errors. */ 5196c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 5206c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, 5216c8d8eccSSepherosa Ziehau sc->bnx_mi_mode & ~BGE_MIMODE_AUTOPOLL); 5226c8d8eccSSepherosa Ziehau DELAY(80); 5236c8d8eccSSepherosa Ziehau } 5246c8d8eccSSepherosa Ziehau 5256c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_WRITE | BGE_MICOMM_BUSY | 5266c8d8eccSSepherosa Ziehau BGE_MIPHY(phy) | BGE_MIREG(reg) | val); 5276c8d8eccSSepherosa Ziehau 5286c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 5296c8d8eccSSepherosa Ziehau DELAY(10); 5306c8d8eccSSepherosa Ziehau if (!(CSR_READ_4(sc, BGE_MI_COMM) & BGE_MICOMM_BUSY)) { 5316c8d8eccSSepherosa Ziehau DELAY(5); 5326c8d8eccSSepherosa Ziehau CSR_READ_4(sc, BGE_MI_COMM); /* dummy read */ 5336c8d8eccSSepherosa Ziehau break; 5346c8d8eccSSepherosa Ziehau } 5356c8d8eccSSepherosa Ziehau } 5366c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 5376c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "PHY write timed out " 5386c8d8eccSSepherosa Ziehau "(phy %d, reg %d, val %d)\n", phy, reg, val); 5396c8d8eccSSepherosa Ziehau } 5406c8d8eccSSepherosa Ziehau 5416c8d8eccSSepherosa Ziehau /* Restore the autopoll bit if necessary. */ 5426c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 5436c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, sc->bnx_mi_mode); 5446c8d8eccSSepherosa Ziehau DELAY(80); 5456c8d8eccSSepherosa Ziehau } 5466c8d8eccSSepherosa Ziehau 5476c8d8eccSSepherosa Ziehau return 0; 5486c8d8eccSSepherosa Ziehau } 5496c8d8eccSSepherosa Ziehau 5506c8d8eccSSepherosa Ziehau static void 5516c8d8eccSSepherosa Ziehau bnx_miibus_statchg(device_t dev) 5526c8d8eccSSepherosa Ziehau { 5536c8d8eccSSepherosa Ziehau struct bnx_softc *sc; 5546c8d8eccSSepherosa Ziehau struct mii_data *mii; 5556c8d8eccSSepherosa Ziehau 5566c8d8eccSSepherosa Ziehau sc = device_get_softc(dev); 5576c8d8eccSSepherosa Ziehau mii = device_get_softc(sc->bnx_miibus); 5586c8d8eccSSepherosa Ziehau 5596c8d8eccSSepherosa Ziehau if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 5606c8d8eccSSepherosa Ziehau (IFM_ACTIVE | IFM_AVALID)) { 5616c8d8eccSSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) { 5626c8d8eccSSepherosa Ziehau case IFM_10_T: 5636c8d8eccSSepherosa Ziehau case IFM_100_TX: 5646c8d8eccSSepherosa Ziehau sc->bnx_link = 1; 5656c8d8eccSSepherosa Ziehau break; 5666c8d8eccSSepherosa Ziehau case IFM_1000_T: 5676c8d8eccSSepherosa Ziehau case IFM_1000_SX: 5686c8d8eccSSepherosa Ziehau case IFM_2500_SX: 5696c8d8eccSSepherosa Ziehau sc->bnx_link = 1; 5706c8d8eccSSepherosa Ziehau break; 5716c8d8eccSSepherosa Ziehau default: 5726c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 5736c8d8eccSSepherosa Ziehau break; 5746c8d8eccSSepherosa Ziehau } 5756c8d8eccSSepherosa Ziehau } else { 5766c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 5776c8d8eccSSepherosa Ziehau } 5786c8d8eccSSepherosa Ziehau if (sc->bnx_link == 0) 5796c8d8eccSSepherosa Ziehau return; 5806c8d8eccSSepherosa Ziehau 5816c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_PORTMODE); 5826c8d8eccSSepherosa Ziehau if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 5836c8d8eccSSepherosa Ziehau IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) { 5846c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MAC_MODE, BGE_PORTMODE_GMII); 5856c8d8eccSSepherosa Ziehau } else { 5866c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MAC_MODE, BGE_PORTMODE_MII); 5876c8d8eccSSepherosa Ziehau } 5886c8d8eccSSepherosa Ziehau 5896c8d8eccSSepherosa Ziehau if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 5906c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX); 5916c8d8eccSSepherosa Ziehau } else { 5926c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX); 5936c8d8eccSSepherosa Ziehau } 5946c8d8eccSSepherosa Ziehau } 5956c8d8eccSSepherosa Ziehau 5966c8d8eccSSepherosa Ziehau /* 5976c8d8eccSSepherosa Ziehau * Memory management for jumbo frames. 5986c8d8eccSSepherosa Ziehau */ 5996c8d8eccSSepherosa Ziehau static int 6006c8d8eccSSepherosa Ziehau bnx_alloc_jumbo_mem(struct bnx_softc *sc) 6016c8d8eccSSepherosa Ziehau { 6026c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 6036c8d8eccSSepherosa Ziehau struct bnx_jslot *entry; 6046c8d8eccSSepherosa Ziehau uint8_t *ptr; 6056c8d8eccSSepherosa Ziehau bus_addr_t paddr; 6066c8d8eccSSepherosa Ziehau int i, error; 6076c8d8eccSSepherosa Ziehau 6086c8d8eccSSepherosa Ziehau /* 6096c8d8eccSSepherosa Ziehau * Create tag for jumbo mbufs. 6106c8d8eccSSepherosa Ziehau * This is really a bit of a kludge. We allocate a special 6116c8d8eccSSepherosa Ziehau * jumbo buffer pool which (thanks to the way our DMA 6126c8d8eccSSepherosa Ziehau * memory allocation works) will consist of contiguous 6136c8d8eccSSepherosa Ziehau * pages. This means that even though a jumbo buffer might 6146c8d8eccSSepherosa Ziehau * be larger than a page size, we don't really need to 6156c8d8eccSSepherosa Ziehau * map it into more than one DMA segment. However, the 6166c8d8eccSSepherosa Ziehau * default mbuf tag will result in multi-segment mappings, 6176c8d8eccSSepherosa Ziehau * so we have to create a special jumbo mbuf tag that 6186c8d8eccSSepherosa Ziehau * lets us get away with mapping the jumbo buffers as 6196c8d8eccSSepherosa Ziehau * a single segment. I think eventually the driver should 6206c8d8eccSSepherosa Ziehau * be changed so that it uses ordinary mbufs and cluster 6216c8d8eccSSepherosa Ziehau * buffers, i.e. jumbo frames can span multiple DMA 6226c8d8eccSSepherosa Ziehau * descriptors. But that's a project for another day. 6236c8d8eccSSepherosa Ziehau */ 6246c8d8eccSSepherosa Ziehau 6256c8d8eccSSepherosa Ziehau /* 6266c8d8eccSSepherosa Ziehau * Create DMA stuffs for jumbo RX ring. 6276c8d8eccSSepherosa Ziehau */ 6286c8d8eccSSepherosa Ziehau error = bnx_dma_block_alloc(sc, BGE_JUMBO_RX_RING_SZ, 6296c8d8eccSSepherosa Ziehau &sc->bnx_cdata.bnx_rx_jumbo_ring_tag, 6306c8d8eccSSepherosa Ziehau &sc->bnx_cdata.bnx_rx_jumbo_ring_map, 6316c8d8eccSSepherosa Ziehau (void *)&sc->bnx_ldata.bnx_rx_jumbo_ring, 6326c8d8eccSSepherosa Ziehau &sc->bnx_ldata.bnx_rx_jumbo_ring_paddr); 6336c8d8eccSSepherosa Ziehau if (error) { 6346c8d8eccSSepherosa Ziehau if_printf(ifp, "could not create jumbo RX ring\n"); 6356c8d8eccSSepherosa Ziehau return error; 6366c8d8eccSSepherosa Ziehau } 6376c8d8eccSSepherosa Ziehau 6386c8d8eccSSepherosa Ziehau /* 6396c8d8eccSSepherosa Ziehau * Create DMA stuffs for jumbo buffer block. 6406c8d8eccSSepherosa Ziehau */ 6416c8d8eccSSepherosa Ziehau error = bnx_dma_block_alloc(sc, BNX_JMEM, 6426c8d8eccSSepherosa Ziehau &sc->bnx_cdata.bnx_jumbo_tag, 6436c8d8eccSSepherosa Ziehau &sc->bnx_cdata.bnx_jumbo_map, 6446c8d8eccSSepherosa Ziehau (void **)&sc->bnx_ldata.bnx_jumbo_buf, 6456c8d8eccSSepherosa Ziehau &paddr); 6466c8d8eccSSepherosa Ziehau if (error) { 6476c8d8eccSSepherosa Ziehau if_printf(ifp, "could not create jumbo buffer\n"); 6486c8d8eccSSepherosa Ziehau return error; 6496c8d8eccSSepherosa Ziehau } 6506c8d8eccSSepherosa Ziehau 6516c8d8eccSSepherosa Ziehau SLIST_INIT(&sc->bnx_jfree_listhead); 6526c8d8eccSSepherosa Ziehau 6536c8d8eccSSepherosa Ziehau /* 6546c8d8eccSSepherosa Ziehau * Now divide it up into 9K pieces and save the addresses 6556c8d8eccSSepherosa Ziehau * in an array. Note that we play an evil trick here by using 6566c8d8eccSSepherosa Ziehau * the first few bytes in the buffer to hold the the address 6576c8d8eccSSepherosa Ziehau * of the softc structure for this interface. This is because 6586c8d8eccSSepherosa Ziehau * bnx_jfree() needs it, but it is called by the mbuf management 6596c8d8eccSSepherosa Ziehau * code which will not pass it to us explicitly. 6606c8d8eccSSepherosa Ziehau */ 6616c8d8eccSSepherosa Ziehau for (i = 0, ptr = sc->bnx_ldata.bnx_jumbo_buf; i < BNX_JSLOTS; i++) { 6626c8d8eccSSepherosa Ziehau entry = &sc->bnx_cdata.bnx_jslots[i]; 6636c8d8eccSSepherosa Ziehau entry->bnx_sc = sc; 6646c8d8eccSSepherosa Ziehau entry->bnx_buf = ptr; 6656c8d8eccSSepherosa Ziehau entry->bnx_paddr = paddr; 6666c8d8eccSSepherosa Ziehau entry->bnx_inuse = 0; 6676c8d8eccSSepherosa Ziehau entry->bnx_slot = i; 6686c8d8eccSSepherosa Ziehau SLIST_INSERT_HEAD(&sc->bnx_jfree_listhead, entry, jslot_link); 6696c8d8eccSSepherosa Ziehau 6706c8d8eccSSepherosa Ziehau ptr += BNX_JLEN; 6716c8d8eccSSepherosa Ziehau paddr += BNX_JLEN; 6726c8d8eccSSepherosa Ziehau } 6736c8d8eccSSepherosa Ziehau return 0; 6746c8d8eccSSepherosa Ziehau } 6756c8d8eccSSepherosa Ziehau 6766c8d8eccSSepherosa Ziehau static void 6776c8d8eccSSepherosa Ziehau bnx_free_jumbo_mem(struct bnx_softc *sc) 6786c8d8eccSSepherosa Ziehau { 6796c8d8eccSSepherosa Ziehau /* Destroy jumbo RX ring. */ 6806c8d8eccSSepherosa Ziehau bnx_dma_block_free(sc->bnx_cdata.bnx_rx_jumbo_ring_tag, 6816c8d8eccSSepherosa Ziehau sc->bnx_cdata.bnx_rx_jumbo_ring_map, 6826c8d8eccSSepherosa Ziehau sc->bnx_ldata.bnx_rx_jumbo_ring); 6836c8d8eccSSepherosa Ziehau 6846c8d8eccSSepherosa Ziehau /* Destroy jumbo buffer block. */ 6856c8d8eccSSepherosa Ziehau bnx_dma_block_free(sc->bnx_cdata.bnx_jumbo_tag, 6866c8d8eccSSepherosa Ziehau sc->bnx_cdata.bnx_jumbo_map, 6876c8d8eccSSepherosa Ziehau sc->bnx_ldata.bnx_jumbo_buf); 6886c8d8eccSSepherosa Ziehau } 6896c8d8eccSSepherosa Ziehau 6906c8d8eccSSepherosa Ziehau /* 6916c8d8eccSSepherosa Ziehau * Allocate a jumbo buffer. 6926c8d8eccSSepherosa Ziehau */ 6936c8d8eccSSepherosa Ziehau static struct bnx_jslot * 6946c8d8eccSSepherosa Ziehau bnx_jalloc(struct bnx_softc *sc) 6956c8d8eccSSepherosa Ziehau { 6966c8d8eccSSepherosa Ziehau struct bnx_jslot *entry; 6976c8d8eccSSepherosa Ziehau 6986c8d8eccSSepherosa Ziehau lwkt_serialize_enter(&sc->bnx_jslot_serializer); 6996c8d8eccSSepherosa Ziehau entry = SLIST_FIRST(&sc->bnx_jfree_listhead); 7006c8d8eccSSepherosa Ziehau if (entry) { 7016c8d8eccSSepherosa Ziehau SLIST_REMOVE_HEAD(&sc->bnx_jfree_listhead, jslot_link); 7026c8d8eccSSepherosa Ziehau entry->bnx_inuse = 1; 7036c8d8eccSSepherosa Ziehau } else { 7046c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "no free jumbo buffers\n"); 7056c8d8eccSSepherosa Ziehau } 7066c8d8eccSSepherosa Ziehau lwkt_serialize_exit(&sc->bnx_jslot_serializer); 7076c8d8eccSSepherosa Ziehau return(entry); 7086c8d8eccSSepherosa Ziehau } 7096c8d8eccSSepherosa Ziehau 7106c8d8eccSSepherosa Ziehau /* 7116c8d8eccSSepherosa Ziehau * Adjust usage count on a jumbo buffer. 7126c8d8eccSSepherosa Ziehau */ 7136c8d8eccSSepherosa Ziehau static void 7146c8d8eccSSepherosa Ziehau bnx_jref(void *arg) 7156c8d8eccSSepherosa Ziehau { 7166c8d8eccSSepherosa Ziehau struct bnx_jslot *entry = (struct bnx_jslot *)arg; 7176c8d8eccSSepherosa Ziehau struct bnx_softc *sc = entry->bnx_sc; 7186c8d8eccSSepherosa Ziehau 7196c8d8eccSSepherosa Ziehau if (sc == NULL) 7206c8d8eccSSepherosa Ziehau panic("bnx_jref: can't find softc pointer!"); 7216c8d8eccSSepherosa Ziehau 7226c8d8eccSSepherosa Ziehau if (&sc->bnx_cdata.bnx_jslots[entry->bnx_slot] != entry) { 7236c8d8eccSSepherosa Ziehau panic("bnx_jref: asked to reference buffer " 7246c8d8eccSSepherosa Ziehau "that we don't manage!"); 7256c8d8eccSSepherosa Ziehau } else if (entry->bnx_inuse == 0) { 7266c8d8eccSSepherosa Ziehau panic("bnx_jref: buffer already free!"); 7276c8d8eccSSepherosa Ziehau } else { 7286c8d8eccSSepherosa Ziehau atomic_add_int(&entry->bnx_inuse, 1); 7296c8d8eccSSepherosa Ziehau } 7306c8d8eccSSepherosa Ziehau } 7316c8d8eccSSepherosa Ziehau 7326c8d8eccSSepherosa Ziehau /* 7336c8d8eccSSepherosa Ziehau * Release a jumbo buffer. 7346c8d8eccSSepherosa Ziehau */ 7356c8d8eccSSepherosa Ziehau static void 7366c8d8eccSSepherosa Ziehau bnx_jfree(void *arg) 7376c8d8eccSSepherosa Ziehau { 7386c8d8eccSSepherosa Ziehau struct bnx_jslot *entry = (struct bnx_jslot *)arg; 7396c8d8eccSSepherosa Ziehau struct bnx_softc *sc = entry->bnx_sc; 7406c8d8eccSSepherosa Ziehau 7416c8d8eccSSepherosa Ziehau if (sc == NULL) 7426c8d8eccSSepherosa Ziehau panic("bnx_jfree: can't find softc pointer!"); 7436c8d8eccSSepherosa Ziehau 7446c8d8eccSSepherosa Ziehau if (&sc->bnx_cdata.bnx_jslots[entry->bnx_slot] != entry) { 7456c8d8eccSSepherosa Ziehau panic("bnx_jfree: asked to free buffer that we don't manage!"); 7466c8d8eccSSepherosa Ziehau } else if (entry->bnx_inuse == 0) { 7476c8d8eccSSepherosa Ziehau panic("bnx_jfree: buffer already free!"); 7486c8d8eccSSepherosa Ziehau } else { 7496c8d8eccSSepherosa Ziehau /* 7506c8d8eccSSepherosa Ziehau * Possible MP race to 0, use the serializer. The atomic insn 7516c8d8eccSSepherosa Ziehau * is still needed for races against bnx_jref(). 7526c8d8eccSSepherosa Ziehau */ 7536c8d8eccSSepherosa Ziehau lwkt_serialize_enter(&sc->bnx_jslot_serializer); 7546c8d8eccSSepherosa Ziehau atomic_subtract_int(&entry->bnx_inuse, 1); 7556c8d8eccSSepherosa Ziehau if (entry->bnx_inuse == 0) { 7566c8d8eccSSepherosa Ziehau SLIST_INSERT_HEAD(&sc->bnx_jfree_listhead, 7576c8d8eccSSepherosa Ziehau entry, jslot_link); 7586c8d8eccSSepherosa Ziehau } 7596c8d8eccSSepherosa Ziehau lwkt_serialize_exit(&sc->bnx_jslot_serializer); 7606c8d8eccSSepherosa Ziehau } 7616c8d8eccSSepherosa Ziehau } 7626c8d8eccSSepherosa Ziehau 7636c8d8eccSSepherosa Ziehau 7646c8d8eccSSepherosa Ziehau /* 7656c8d8eccSSepherosa Ziehau * Intialize a standard receive ring descriptor. 7666c8d8eccSSepherosa Ziehau */ 7676c8d8eccSSepherosa Ziehau static int 768beedf5beSSepherosa Ziehau bnx_newbuf_std(struct bnx_rx_ret_ring *ret, int i, int init) 7696c8d8eccSSepherosa Ziehau { 7706c8d8eccSSepherosa Ziehau struct mbuf *m_new = NULL; 7716c8d8eccSSepherosa Ziehau bus_dma_segment_t seg; 7726c8d8eccSSepherosa Ziehau bus_dmamap_t map; 7736c8d8eccSSepherosa Ziehau int error, nsegs; 774beedf5beSSepherosa Ziehau struct bnx_rx_buf *rb; 7756c8d8eccSSepherosa Ziehau 776841cdf08SSepherosa Ziehau rb = &ret->bnx_std->bnx_rx_std_buf[i]; 777841cdf08SSepherosa Ziehau KASSERT(!rb->bnx_rx_refilled, ("RX buf %dth has been refilled", i)); 778841cdf08SSepherosa Ziehau 7796c8d8eccSSepherosa Ziehau m_new = m_getcl(init ? MB_WAIT : MB_DONTWAIT, MT_DATA, M_PKTHDR); 780841cdf08SSepherosa Ziehau if (m_new == NULL) { 781841cdf08SSepherosa Ziehau error = ENOBUFS; 782841cdf08SSepherosa Ziehau goto back; 783841cdf08SSepherosa Ziehau } 7846c8d8eccSSepherosa Ziehau m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 7856c8d8eccSSepherosa Ziehau m_adj(m_new, ETHER_ALIGN); 7866c8d8eccSSepherosa Ziehau 787beedf5beSSepherosa Ziehau error = bus_dmamap_load_mbuf_segment(ret->bnx_rx_mtag, 788beedf5beSSepherosa Ziehau ret->bnx_rx_tmpmap, m_new, &seg, 1, &nsegs, BUS_DMA_NOWAIT); 7896c8d8eccSSepherosa Ziehau if (error) { 7906c8d8eccSSepherosa Ziehau m_freem(m_new); 791841cdf08SSepherosa Ziehau goto back; 7926c8d8eccSSepherosa Ziehau } 7936c8d8eccSSepherosa Ziehau 7946c8d8eccSSepherosa Ziehau if (!init) { 795beedf5beSSepherosa Ziehau bus_dmamap_sync(ret->bnx_rx_mtag, rb->bnx_rx_dmamap, 7966c8d8eccSSepherosa Ziehau BUS_DMASYNC_POSTREAD); 797beedf5beSSepherosa Ziehau bus_dmamap_unload(ret->bnx_rx_mtag, rb->bnx_rx_dmamap); 7986c8d8eccSSepherosa Ziehau } 7996c8d8eccSSepherosa Ziehau 800beedf5beSSepherosa Ziehau map = ret->bnx_rx_tmpmap; 801beedf5beSSepherosa Ziehau ret->bnx_rx_tmpmap = rb->bnx_rx_dmamap; 8026c8d8eccSSepherosa Ziehau 803841cdf08SSepherosa Ziehau rb->bnx_rx_dmamap = map; 804beedf5beSSepherosa Ziehau rb->bnx_rx_mbuf = m_new; 805beedf5beSSepherosa Ziehau rb->bnx_rx_paddr = seg.ds_addr; 806695a8586SSepherosa Ziehau rb->bnx_rx_len = m_new->m_len; 807841cdf08SSepherosa Ziehau back: 808841cdf08SSepherosa Ziehau cpu_sfence(); 809841cdf08SSepherosa Ziehau rb->bnx_rx_refilled = 1; 810841cdf08SSepherosa Ziehau return error; 8116c8d8eccSSepherosa Ziehau } 8126c8d8eccSSepherosa Ziehau 8136c8d8eccSSepherosa Ziehau static void 814beedf5beSSepherosa Ziehau bnx_setup_rxdesc_std(struct bnx_rx_std_ring *std, int i) 8156c8d8eccSSepherosa Ziehau { 816841cdf08SSepherosa Ziehau struct bnx_rx_buf *rb; 8176c8d8eccSSepherosa Ziehau struct bge_rx_bd *r; 818695a8586SSepherosa Ziehau bus_addr_t paddr; 819695a8586SSepherosa Ziehau int len; 8206c8d8eccSSepherosa Ziehau 821beedf5beSSepherosa Ziehau rb = &std->bnx_rx_std_buf[i]; 822841cdf08SSepherosa Ziehau KASSERT(rb->bnx_rx_refilled, ("RX buf %dth is not refilled", i)); 823695a8586SSepherosa Ziehau 824695a8586SSepherosa Ziehau paddr = rb->bnx_rx_paddr; 825695a8586SSepherosa Ziehau len = rb->bnx_rx_len; 826695a8586SSepherosa Ziehau 827695a8586SSepherosa Ziehau cpu_mfence(); 828695a8586SSepherosa Ziehau 829841cdf08SSepherosa Ziehau rb->bnx_rx_refilled = 0; 8306c8d8eccSSepherosa Ziehau 831841cdf08SSepherosa Ziehau r = &std->bnx_rx_std_ring[i]; 832695a8586SSepherosa Ziehau r->bge_addr.bge_addr_lo = BGE_ADDR_LO(paddr); 833695a8586SSepherosa Ziehau r->bge_addr.bge_addr_hi = BGE_ADDR_HI(paddr); 834695a8586SSepherosa Ziehau r->bge_len = len; 8356c8d8eccSSepherosa Ziehau r->bge_idx = i; 8366c8d8eccSSepherosa Ziehau r->bge_flags = BGE_RXBDFLAG_END; 8376c8d8eccSSepherosa Ziehau } 8386c8d8eccSSepherosa Ziehau 8396c8d8eccSSepherosa Ziehau /* 8406c8d8eccSSepherosa Ziehau * Initialize a jumbo receive ring descriptor. This allocates 8416c8d8eccSSepherosa Ziehau * a jumbo buffer from the pool managed internally by the driver. 8426c8d8eccSSepherosa Ziehau */ 8436c8d8eccSSepherosa Ziehau static int 8446c8d8eccSSepherosa Ziehau bnx_newbuf_jumbo(struct bnx_softc *sc, int i, int init) 8456c8d8eccSSepherosa Ziehau { 8466c8d8eccSSepherosa Ziehau struct mbuf *m_new = NULL; 8476c8d8eccSSepherosa Ziehau struct bnx_jslot *buf; 8486c8d8eccSSepherosa Ziehau bus_addr_t paddr; 8496c8d8eccSSepherosa Ziehau 8506c8d8eccSSepherosa Ziehau /* Allocate the mbuf. */ 8516c8d8eccSSepherosa Ziehau MGETHDR(m_new, init ? MB_WAIT : MB_DONTWAIT, MT_DATA); 8526c8d8eccSSepherosa Ziehau if (m_new == NULL) 8536c8d8eccSSepherosa Ziehau return ENOBUFS; 8546c8d8eccSSepherosa Ziehau 8556c8d8eccSSepherosa Ziehau /* Allocate the jumbo buffer */ 8566c8d8eccSSepherosa Ziehau buf = bnx_jalloc(sc); 8576c8d8eccSSepherosa Ziehau if (buf == NULL) { 8586c8d8eccSSepherosa Ziehau m_freem(m_new); 8596c8d8eccSSepherosa Ziehau return ENOBUFS; 8606c8d8eccSSepherosa Ziehau } 8616c8d8eccSSepherosa Ziehau 8626c8d8eccSSepherosa Ziehau /* Attach the buffer to the mbuf. */ 8636c8d8eccSSepherosa Ziehau m_new->m_ext.ext_arg = buf; 8646c8d8eccSSepherosa Ziehau m_new->m_ext.ext_buf = buf->bnx_buf; 8656c8d8eccSSepherosa Ziehau m_new->m_ext.ext_free = bnx_jfree; 8666c8d8eccSSepherosa Ziehau m_new->m_ext.ext_ref = bnx_jref; 8676c8d8eccSSepherosa Ziehau m_new->m_ext.ext_size = BNX_JUMBO_FRAMELEN; 8686c8d8eccSSepherosa Ziehau 8696c8d8eccSSepherosa Ziehau m_new->m_flags |= M_EXT; 8706c8d8eccSSepherosa Ziehau 8716c8d8eccSSepherosa Ziehau m_new->m_data = m_new->m_ext.ext_buf; 8726c8d8eccSSepherosa Ziehau m_new->m_len = m_new->m_pkthdr.len = m_new->m_ext.ext_size; 8736c8d8eccSSepherosa Ziehau 8746c8d8eccSSepherosa Ziehau paddr = buf->bnx_paddr; 8756c8d8eccSSepherosa Ziehau m_adj(m_new, ETHER_ALIGN); 8766c8d8eccSSepherosa Ziehau paddr += ETHER_ALIGN; 8776c8d8eccSSepherosa Ziehau 8786c8d8eccSSepherosa Ziehau /* Save necessary information */ 879beedf5beSSepherosa Ziehau sc->bnx_cdata.bnx_rx_jumbo_chain[i].bnx_rx_mbuf = m_new; 880beedf5beSSepherosa Ziehau sc->bnx_cdata.bnx_rx_jumbo_chain[i].bnx_rx_paddr = paddr; 8816c8d8eccSSepherosa Ziehau 8826c8d8eccSSepherosa Ziehau /* Set up the descriptor. */ 8836c8d8eccSSepherosa Ziehau bnx_setup_rxdesc_jumbo(sc, i); 8846c8d8eccSSepherosa Ziehau return 0; 8856c8d8eccSSepherosa Ziehau } 8866c8d8eccSSepherosa Ziehau 8876c8d8eccSSepherosa Ziehau static void 8886c8d8eccSSepherosa Ziehau bnx_setup_rxdesc_jumbo(struct bnx_softc *sc, int i) 8896c8d8eccSSepherosa Ziehau { 8906c8d8eccSSepherosa Ziehau struct bge_rx_bd *r; 891beedf5beSSepherosa Ziehau struct bnx_rx_buf *rc; 8926c8d8eccSSepherosa Ziehau 8936c8d8eccSSepherosa Ziehau r = &sc->bnx_ldata.bnx_rx_jumbo_ring[i]; 8946c8d8eccSSepherosa Ziehau rc = &sc->bnx_cdata.bnx_rx_jumbo_chain[i]; 8956c8d8eccSSepherosa Ziehau 896beedf5beSSepherosa Ziehau r->bge_addr.bge_addr_lo = BGE_ADDR_LO(rc->bnx_rx_paddr); 897beedf5beSSepherosa Ziehau r->bge_addr.bge_addr_hi = BGE_ADDR_HI(rc->bnx_rx_paddr); 898beedf5beSSepherosa Ziehau r->bge_len = rc->bnx_rx_mbuf->m_len; 8996c8d8eccSSepherosa Ziehau r->bge_idx = i; 9006c8d8eccSSepherosa Ziehau r->bge_flags = BGE_RXBDFLAG_END|BGE_RXBDFLAG_JUMBO_RING; 9016c8d8eccSSepherosa Ziehau } 9026c8d8eccSSepherosa Ziehau 9036c8d8eccSSepherosa Ziehau static int 904beedf5beSSepherosa Ziehau bnx_init_rx_ring_std(struct bnx_rx_std_ring *std) 9056c8d8eccSSepherosa Ziehau { 9066c8d8eccSSepherosa Ziehau int i, error; 9076c8d8eccSSepherosa Ziehau 9086c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_STD_RX_RING_CNT; i++) { 909beedf5beSSepherosa Ziehau /* Use the first RX return ring's tmp RX mbuf DMA map */ 910beedf5beSSepherosa Ziehau error = bnx_newbuf_std(&std->bnx_sc->bnx_rx_ret_ring[0], i, 1); 9116c8d8eccSSepherosa Ziehau if (error) 9126c8d8eccSSepherosa Ziehau return error; 913841cdf08SSepherosa Ziehau bnx_setup_rxdesc_std(std, i); 91487c7a7cfSSascha Wildner } 9156c8d8eccSSepherosa Ziehau 916625c3ba3SSepherosa Ziehau std->bnx_rx_std_used = 0; 917841cdf08SSepherosa Ziehau std->bnx_rx_std_refill = 0; 918841cdf08SSepherosa Ziehau std->bnx_rx_std_running = 0; 919841cdf08SSepherosa Ziehau cpu_sfence(); 920841cdf08SSepherosa Ziehau lwkt_serialize_handler_enable(&std->bnx_rx_std_serialize); 921841cdf08SSepherosa Ziehau 922beedf5beSSepherosa Ziehau std->bnx_rx_std = BGE_STD_RX_RING_CNT - 1; 923beedf5beSSepherosa Ziehau bnx_writembx(std->bnx_sc, BGE_MBX_RX_STD_PROD_LO, std->bnx_rx_std); 9246c8d8eccSSepherosa Ziehau 9256c8d8eccSSepherosa Ziehau return(0); 9266c8d8eccSSepherosa Ziehau } 9276c8d8eccSSepherosa Ziehau 9286c8d8eccSSepherosa Ziehau static void 929beedf5beSSepherosa Ziehau bnx_free_rx_ring_std(struct bnx_rx_std_ring *std) 9306c8d8eccSSepherosa Ziehau { 9316c8d8eccSSepherosa Ziehau int i; 9326c8d8eccSSepherosa Ziehau 933841cdf08SSepherosa Ziehau lwkt_serialize_handler_disable(&std->bnx_rx_std_serialize); 934841cdf08SSepherosa Ziehau 9356c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_STD_RX_RING_CNT; i++) { 936beedf5beSSepherosa Ziehau struct bnx_rx_buf *rb = &std->bnx_rx_std_buf[i]; 9376c8d8eccSSepherosa Ziehau 938841cdf08SSepherosa Ziehau rb->bnx_rx_refilled = 0; 939beedf5beSSepherosa Ziehau if (rb->bnx_rx_mbuf != NULL) { 940beedf5beSSepherosa Ziehau bus_dmamap_unload(std->bnx_rx_mtag, rb->bnx_rx_dmamap); 941beedf5beSSepherosa Ziehau m_freem(rb->bnx_rx_mbuf); 942beedf5beSSepherosa Ziehau rb->bnx_rx_mbuf = NULL; 9436c8d8eccSSepherosa Ziehau } 944beedf5beSSepherosa Ziehau bzero(&std->bnx_rx_std_ring[i], sizeof(struct bge_rx_bd)); 9456c8d8eccSSepherosa Ziehau } 9466c8d8eccSSepherosa Ziehau } 9476c8d8eccSSepherosa Ziehau 9486c8d8eccSSepherosa Ziehau static int 9496c8d8eccSSepherosa Ziehau bnx_init_rx_ring_jumbo(struct bnx_softc *sc) 9506c8d8eccSSepherosa Ziehau { 9516c8d8eccSSepherosa Ziehau struct bge_rcb *rcb; 9526c8d8eccSSepherosa Ziehau int i, error; 9536c8d8eccSSepherosa Ziehau 9546c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) { 9556c8d8eccSSepherosa Ziehau error = bnx_newbuf_jumbo(sc, i, 1); 9566c8d8eccSSepherosa Ziehau if (error) 9576c8d8eccSSepherosa Ziehau return error; 95887c7a7cfSSascha Wildner } 9596c8d8eccSSepherosa Ziehau 9606c8d8eccSSepherosa Ziehau sc->bnx_jumbo = BGE_JUMBO_RX_RING_CNT - 1; 9616c8d8eccSSepherosa Ziehau 9626c8d8eccSSepherosa Ziehau rcb = &sc->bnx_ldata.bnx_info.bnx_jumbo_rx_rcb; 9636c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(0, 0); 9646c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags); 9656c8d8eccSSepherosa Ziehau 9666c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bnx_jumbo); 9676c8d8eccSSepherosa Ziehau 9686c8d8eccSSepherosa Ziehau return(0); 9696c8d8eccSSepherosa Ziehau } 9706c8d8eccSSepherosa Ziehau 9716c8d8eccSSepherosa Ziehau static void 9726c8d8eccSSepherosa Ziehau bnx_free_rx_ring_jumbo(struct bnx_softc *sc) 9736c8d8eccSSepherosa Ziehau { 9746c8d8eccSSepherosa Ziehau int i; 9756c8d8eccSSepherosa Ziehau 9766c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) { 977beedf5beSSepherosa Ziehau struct bnx_rx_buf *rc = &sc->bnx_cdata.bnx_rx_jumbo_chain[i]; 9786c8d8eccSSepherosa Ziehau 979beedf5beSSepherosa Ziehau if (rc->bnx_rx_mbuf != NULL) { 980beedf5beSSepherosa Ziehau m_freem(rc->bnx_rx_mbuf); 981beedf5beSSepherosa Ziehau rc->bnx_rx_mbuf = NULL; 9826c8d8eccSSepherosa Ziehau } 9836c8d8eccSSepherosa Ziehau bzero(&sc->bnx_ldata.bnx_rx_jumbo_ring[i], 9846c8d8eccSSepherosa Ziehau sizeof(struct bge_rx_bd)); 9856c8d8eccSSepherosa Ziehau } 9866c8d8eccSSepherosa Ziehau } 9876c8d8eccSSepherosa Ziehau 9886c8d8eccSSepherosa Ziehau static void 98933a04907SSepherosa Ziehau bnx_free_tx_ring(struct bnx_tx_ring *txr) 9906c8d8eccSSepherosa Ziehau { 9916c8d8eccSSepherosa Ziehau int i; 9926c8d8eccSSepherosa Ziehau 9936c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_TX_RING_CNT; i++) { 994fa4b1067SSepherosa Ziehau struct bnx_tx_buf *buf = &txr->bnx_tx_buf[i]; 995fa4b1067SSepherosa Ziehau 996fa4b1067SSepherosa Ziehau if (buf->bnx_tx_mbuf != NULL) { 99733a04907SSepherosa Ziehau bus_dmamap_unload(txr->bnx_tx_mtag, 998fa4b1067SSepherosa Ziehau buf->bnx_tx_dmamap); 999fa4b1067SSepherosa Ziehau m_freem(buf->bnx_tx_mbuf); 1000fa4b1067SSepherosa Ziehau buf->bnx_tx_mbuf = NULL; 10016c8d8eccSSepherosa Ziehau } 100233a04907SSepherosa Ziehau bzero(&txr->bnx_tx_ring[i], sizeof(struct bge_tx_bd)); 10036c8d8eccSSepherosa Ziehau } 100433a04907SSepherosa Ziehau txr->bnx_tx_saved_considx = BNX_TXCONS_UNSET; 10056c8d8eccSSepherosa Ziehau } 10066c8d8eccSSepherosa Ziehau 10076c8d8eccSSepherosa Ziehau static int 100833a04907SSepherosa Ziehau bnx_init_tx_ring(struct bnx_tx_ring *txr) 10096c8d8eccSSepherosa Ziehau { 1010fa639b88SSepherosa Ziehau txr->bnx_tx_cnt = 0; 101133a04907SSepherosa Ziehau txr->bnx_tx_saved_considx = 0; 101233a04907SSepherosa Ziehau txr->bnx_tx_prodidx = 0; 10136c8d8eccSSepherosa Ziehau 10146c8d8eccSSepherosa Ziehau /* Initialize transmit producer index for host-memory send ring. */ 10158bd43d5dSSepherosa Ziehau bnx_writembx(txr->bnx_sc, txr->bnx_tx_mbx, txr->bnx_tx_prodidx); 10166c8d8eccSSepherosa Ziehau 10176c8d8eccSSepherosa Ziehau return(0); 10186c8d8eccSSepherosa Ziehau } 10196c8d8eccSSepherosa Ziehau 10206c8d8eccSSepherosa Ziehau static void 10216c8d8eccSSepherosa Ziehau bnx_setmulti(struct bnx_softc *sc) 10226c8d8eccSSepherosa Ziehau { 10236c8d8eccSSepherosa Ziehau struct ifnet *ifp; 10246c8d8eccSSepherosa Ziehau struct ifmultiaddr *ifma; 10256c8d8eccSSepherosa Ziehau uint32_t hashes[4] = { 0, 0, 0, 0 }; 10266c8d8eccSSepherosa Ziehau int h, i; 10276c8d8eccSSepherosa Ziehau 10286c8d8eccSSepherosa Ziehau ifp = &sc->arpcom.ac_if; 10296c8d8eccSSepherosa Ziehau 10306c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 10316c8d8eccSSepherosa Ziehau for (i = 0; i < 4; i++) 10326c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0xFFFFFFFF); 10336c8d8eccSSepherosa Ziehau return; 10346c8d8eccSSepherosa Ziehau } 10356c8d8eccSSepherosa Ziehau 10366c8d8eccSSepherosa Ziehau /* First, zot all the existing filters. */ 10376c8d8eccSSepherosa Ziehau for (i = 0; i < 4; i++) 10386c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0); 10396c8d8eccSSepherosa Ziehau 10406c8d8eccSSepherosa Ziehau /* Now program new ones. */ 10416c8d8eccSSepherosa Ziehau TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 10426c8d8eccSSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 10436c8d8eccSSepherosa Ziehau continue; 10446c8d8eccSSepherosa Ziehau h = ether_crc32_le( 10456c8d8eccSSepherosa Ziehau LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 10466c8d8eccSSepherosa Ziehau ETHER_ADDR_LEN) & 0x7f; 10476c8d8eccSSepherosa Ziehau hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F); 10486c8d8eccSSepherosa Ziehau } 10496c8d8eccSSepherosa Ziehau 10506c8d8eccSSepherosa Ziehau for (i = 0; i < 4; i++) 10516c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), hashes[i]); 10526c8d8eccSSepherosa Ziehau } 10536c8d8eccSSepherosa Ziehau 10546c8d8eccSSepherosa Ziehau /* 10556c8d8eccSSepherosa Ziehau * Do endian, PCI and DMA initialization. Also check the on-board ROM 10566c8d8eccSSepherosa Ziehau * self-test results. 10576c8d8eccSSepherosa Ziehau */ 10586c8d8eccSSepherosa Ziehau static int 10596c8d8eccSSepherosa Ziehau bnx_chipinit(struct bnx_softc *sc) 10606c8d8eccSSepherosa Ziehau { 10616c8d8eccSSepherosa Ziehau uint32_t dma_rw_ctl, mode_ctl; 10626c8d8eccSSepherosa Ziehau int i; 10636c8d8eccSSepherosa Ziehau 10646c8d8eccSSepherosa Ziehau /* Set endian type before we access any non-PCI registers. */ 10656c8d8eccSSepherosa Ziehau pci_write_config(sc->bnx_dev, BGE_PCI_MISC_CTL, 10666c8d8eccSSepherosa Ziehau BGE_INIT | BGE_PCIMISCCTL_TAGGED_STATUS, 4); 10676c8d8eccSSepherosa Ziehau 10686c8d8eccSSepherosa Ziehau /* Clear the MAC control register */ 10696c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_MODE, 0); 10706c8d8eccSSepherosa Ziehau 10716c8d8eccSSepherosa Ziehau /* 10726c8d8eccSSepherosa Ziehau * Clear the MAC statistics block in the NIC's 10736c8d8eccSSepherosa Ziehau * internal memory. 10746c8d8eccSSepherosa Ziehau */ 10756c8d8eccSSepherosa Ziehau for (i = BGE_STATS_BLOCK; 10766c8d8eccSSepherosa Ziehau i < BGE_STATS_BLOCK_END + 1; i += sizeof(uint32_t)) 10776c8d8eccSSepherosa Ziehau BNX_MEMWIN_WRITE(sc, i, 0); 10786c8d8eccSSepherosa Ziehau 10796c8d8eccSSepherosa Ziehau for (i = BGE_STATUS_BLOCK; 10806c8d8eccSSepherosa Ziehau i < BGE_STATUS_BLOCK_END + 1; i += sizeof(uint32_t)) 10816c8d8eccSSepherosa Ziehau BNX_MEMWIN_WRITE(sc, i, 0); 10826c8d8eccSSepherosa Ziehau 1083d7872545SSepherosa Ziehau if (BNX_IS_57765_FAMILY(sc)) { 1084d7872545SSepherosa Ziehau uint32_t val; 1085d7872545SSepherosa Ziehau 1086d7872545SSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM57765_A0) { 1087d7872545SSepherosa Ziehau mode_ctl = CSR_READ_4(sc, BGE_MODE_CTL); 1088d7872545SSepherosa Ziehau val = mode_ctl & ~BGE_MODECTL_PCIE_PORTS; 1089d7872545SSepherosa Ziehau 1090d7872545SSepherosa Ziehau /* Access the lower 1K of PL PCI-E block registers. */ 1091d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, 1092d7872545SSepherosa Ziehau val | BGE_MODECTL_PCIE_PL_SEL); 1093d7872545SSepherosa Ziehau 1094d7872545SSepherosa Ziehau val = CSR_READ_4(sc, BGE_PCIE_PL_LO_PHYCTL5); 1095d7872545SSepherosa Ziehau val |= BGE_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ; 1096d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_PCIE_PL_LO_PHYCTL5, val); 1097d7872545SSepherosa Ziehau 1098d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, mode_ctl); 1099d7872545SSepherosa Ziehau } 1100d7872545SSepherosa Ziehau if (sc->bnx_chiprev != BGE_CHIPREV_57765_AX) { 11011749651bSSepherosa Ziehau /* Fix transmit hangs */ 11021749651bSSepherosa Ziehau val = CSR_READ_4(sc, BGE_CPMU_PADRNG_CTL); 11031749651bSSepherosa Ziehau val |= BGE_CPMU_PADRNG_CTL_RDIV2; 11041749651bSSepherosa Ziehau CSR_WRITE_4(sc, BGE_CPMU_PADRNG_CTL, val); 11051749651bSSepherosa Ziehau 1106d7872545SSepherosa Ziehau mode_ctl = CSR_READ_4(sc, BGE_MODE_CTL); 1107d7872545SSepherosa Ziehau val = mode_ctl & ~BGE_MODECTL_PCIE_PORTS; 1108d7872545SSepherosa Ziehau 1109d7872545SSepherosa Ziehau /* Access the lower 1K of DL PCI-E block registers. */ 1110d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, 1111d7872545SSepherosa Ziehau val | BGE_MODECTL_PCIE_DL_SEL); 1112d7872545SSepherosa Ziehau 1113d7872545SSepherosa Ziehau val = CSR_READ_4(sc, BGE_PCIE_DL_LO_FTSMAX); 1114d7872545SSepherosa Ziehau val &= ~BGE_PCIE_DL_LO_FTSMAX_MASK; 1115d7872545SSepherosa Ziehau val |= BGE_PCIE_DL_LO_FTSMAX_VAL; 1116d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_PCIE_DL_LO_FTSMAX, val); 1117d7872545SSepherosa Ziehau 1118d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, mode_ctl); 1119d7872545SSepherosa Ziehau } 1120d7872545SSepherosa Ziehau 1121d7872545SSepherosa Ziehau val = CSR_READ_4(sc, BGE_CPMU_LSPD_10MB_CLK); 1122d7872545SSepherosa Ziehau val &= ~BGE_CPMU_LSPD_10MB_MACCLK_MASK; 1123d7872545SSepherosa Ziehau val |= BGE_CPMU_LSPD_10MB_MACCLK_6_25; 1124d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_CPMU_LSPD_10MB_CLK, val); 1125d7872545SSepherosa Ziehau } 1126d7872545SSepherosa Ziehau 11272890cca3SSepherosa Ziehau /* 11282890cca3SSepherosa Ziehau * Set up the PCI DMA control register. 11292890cca3SSepherosa Ziehau */ 11302890cca3SSepherosa Ziehau dma_rw_ctl = pci_read_config(sc->bnx_dev, BGE_PCI_DMA_RW_CTL, 4); 11312890cca3SSepherosa Ziehau /* 11322890cca3SSepherosa Ziehau * Disable 32bytes cache alignment for DMA write to host memory 11332890cca3SSepherosa Ziehau * 11342890cca3SSepherosa Ziehau * NOTE: 11352890cca3SSepherosa Ziehau * 64bytes cache alignment for DMA write to host memory is still 11362890cca3SSepherosa Ziehau * enabled. 11372890cca3SSepherosa Ziehau */ 11382890cca3SSepherosa Ziehau dma_rw_ctl |= BGE_PCIDMARWCTL_DIS_CACHE_ALIGNMENT; 11396c8d8eccSSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM57765_A0) 11406c8d8eccSSepherosa Ziehau dma_rw_ctl &= ~BGE_PCIDMARWCTL_CRDRDR_RDMA_MRRS_MSK; 11416c8d8eccSSepherosa Ziehau /* 11426c8d8eccSSepherosa Ziehau * Enable HW workaround for controllers that misinterpret 11436c8d8eccSSepherosa Ziehau * a status tag update and leave interrupts permanently 11446c8d8eccSSepherosa Ziehau * disabled. 11456c8d8eccSSepherosa Ziehau */ 11466c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev != BGE_ASICREV_BCM5717 && 1147b96cbbb6SSepherosa Ziehau sc->bnx_asicrev != BGE_ASICREV_BCM5762 && 11482890cca3SSepherosa Ziehau !BNX_IS_57765_FAMILY(sc)) 11496c8d8eccSSepherosa Ziehau dma_rw_ctl |= BGE_PCIDMARWCTL_TAGGED_STATUS_WA; 11502890cca3SSepherosa Ziehau if (bootverbose) { 11512890cca3SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "DMA read/write %#x\n", 11522890cca3SSepherosa Ziehau dma_rw_ctl); 11536c8d8eccSSepherosa Ziehau } 11546c8d8eccSSepherosa Ziehau pci_write_config(sc->bnx_dev, BGE_PCI_DMA_RW_CTL, dma_rw_ctl, 4); 11556c8d8eccSSepherosa Ziehau 11566c8d8eccSSepherosa Ziehau /* 11576c8d8eccSSepherosa Ziehau * Set up general mode register. 11586c8d8eccSSepherosa Ziehau */ 11596c8d8eccSSepherosa Ziehau mode_ctl = bnx_dma_swap_options(sc) | BGE_MODECTL_MAC_ATTN_INTR | 11606c8d8eccSSepherosa Ziehau BGE_MODECTL_HOST_SEND_BDS | BGE_MODECTL_TX_NO_PHDR_CSUM; 11616c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, mode_ctl); 11626c8d8eccSSepherosa Ziehau 11636c8d8eccSSepherosa Ziehau /* 11646c8d8eccSSepherosa Ziehau * Disable memory write invalidate. Apparently it is not supported 11656c8d8eccSSepherosa Ziehau * properly by these devices. Also ensure that INTx isn't disabled, 11666c8d8eccSSepherosa Ziehau * as these chips need it even when using MSI. 11676c8d8eccSSepherosa Ziehau */ 11686c8d8eccSSepherosa Ziehau PCI_CLRBIT(sc->bnx_dev, BGE_PCI_CMD, 11696c8d8eccSSepherosa Ziehau (PCIM_CMD_MWRICEN | PCIM_CMD_INTxDIS), 4); 11706c8d8eccSSepherosa Ziehau 11716c8d8eccSSepherosa Ziehau /* Set the timer prescaler (always 66Mhz) */ 11726c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MISC_CFG, 65 << 1/*BGE_32BITTIME_66MHZ*/); 11736c8d8eccSSepherosa Ziehau 11746c8d8eccSSepherosa Ziehau return(0); 11756c8d8eccSSepherosa Ziehau } 11766c8d8eccSSepherosa Ziehau 11776c8d8eccSSepherosa Ziehau static int 11786c8d8eccSSepherosa Ziehau bnx_blockinit(struct bnx_softc *sc) 11796c8d8eccSSepherosa Ziehau { 1180695a8586SSepherosa Ziehau struct bnx_intr_data *intr; 11816c8d8eccSSepherosa Ziehau struct bge_rcb *rcb; 11826c8d8eccSSepherosa Ziehau bus_size_t vrcb; 11836c8d8eccSSepherosa Ziehau bge_hostaddr taddr; 11846c8d8eccSSepherosa Ziehau uint32_t val; 11856c8d8eccSSepherosa Ziehau int i, limit; 11866c8d8eccSSepherosa Ziehau 11876c8d8eccSSepherosa Ziehau /* 11886c8d8eccSSepherosa Ziehau * Initialize the memory window pointer register so that 11896c8d8eccSSepherosa Ziehau * we can access the first 32K of internal NIC RAM. This will 11906c8d8eccSSepherosa Ziehau * allow us to set up the TX send ring RCBs and the RX return 11916c8d8eccSSepherosa Ziehau * ring RCBs, plus other things which live in NIC memory. 11926c8d8eccSSepherosa Ziehau */ 11936c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_PCI_MEMWIN_BASEADDR, 0); 11946c8d8eccSSepherosa Ziehau 11956c8d8eccSSepherosa Ziehau /* Configure mbuf pool watermarks */ 1196f368d0d9SSepherosa Ziehau if (BNX_IS_57765_PLUS(sc)) { 11976c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0); 11986c8d8eccSSepherosa Ziehau if (sc->arpcom.ac_if.if_mtu > ETHERMTU) { 11996c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x7e); 12006c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0xea); 12016c8d8eccSSepherosa Ziehau } else { 12026c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x2a); 12036c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0xa0); 12046c8d8eccSSepherosa Ziehau } 12056c8d8eccSSepherosa Ziehau } else { 12066c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0); 12076c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x10); 12086c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0x60); 12096c8d8eccSSepherosa Ziehau } 12106c8d8eccSSepherosa Ziehau 12116c8d8eccSSepherosa Ziehau /* Configure DMA resource watermarks */ 12126c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_LOWAT, 5); 12136c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_HIWAT, 10); 12146c8d8eccSSepherosa Ziehau 12156c8d8eccSSepherosa Ziehau /* Enable buffer manager */ 12166c8d8eccSSepherosa Ziehau val = BGE_BMANMODE_ENABLE | BGE_BMANMODE_LOMBUF_ATTN; 12176c8d8eccSSepherosa Ziehau /* 12186c8d8eccSSepherosa Ziehau * Change the arbitration algorithm of TXMBUF read request to 12196c8d8eccSSepherosa Ziehau * round-robin instead of priority based for BCM5719. When 12206c8d8eccSSepherosa Ziehau * TXFIFO is almost empty, RDMA will hold its request until 12216c8d8eccSSepherosa Ziehau * TXFIFO is not almost empty. 12226c8d8eccSSepherosa Ziehau */ 12236c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719) 12246c8d8eccSSepherosa Ziehau val |= BGE_BMANMODE_NO_TX_UNDERRUN; 1225e5eebe34SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5717 || 1226e5eebe34SSepherosa Ziehau sc->bnx_chipid == BGE_CHIPID_BCM5719_A0 || 1227e5eebe34SSepherosa Ziehau sc->bnx_chipid == BGE_CHIPID_BCM5720_A0) 1228e5eebe34SSepherosa Ziehau val |= BGE_BMANMODE_LOMBUF_ATTN; 12296c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MODE, val); 12306c8d8eccSSepherosa Ziehau 12316c8d8eccSSepherosa Ziehau /* Poll for buffer manager start indication */ 12326c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 12336c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_BMAN_MODE) & BGE_BMANMODE_ENABLE) 12346c8d8eccSSepherosa Ziehau break; 12356c8d8eccSSepherosa Ziehau DELAY(10); 12366c8d8eccSSepherosa Ziehau } 12376c8d8eccSSepherosa Ziehau 12386c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 12396c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 12406c8d8eccSSepherosa Ziehau "buffer manager failed to start\n"); 12416c8d8eccSSepherosa Ziehau return(ENXIO); 12426c8d8eccSSepherosa Ziehau } 12436c8d8eccSSepherosa Ziehau 12446c8d8eccSSepherosa Ziehau /* Enable flow-through queues */ 12456c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_FTQ_RESET, 0xFFFFFFFF); 12466c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_FTQ_RESET, 0); 12476c8d8eccSSepherosa Ziehau 12486c8d8eccSSepherosa Ziehau /* Wait until queue initialization is complete */ 12496c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 12506c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_FTQ_RESET) == 0) 12516c8d8eccSSepherosa Ziehau break; 12526c8d8eccSSepherosa Ziehau DELAY(10); 12536c8d8eccSSepherosa Ziehau } 12546c8d8eccSSepherosa Ziehau 12556c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 12566c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 12576c8d8eccSSepherosa Ziehau "flow-through queue init failed\n"); 12586c8d8eccSSepherosa Ziehau return(ENXIO); 12596c8d8eccSSepherosa Ziehau } 12606c8d8eccSSepherosa Ziehau 12616c8d8eccSSepherosa Ziehau /* 12626c8d8eccSSepherosa Ziehau * Summary of rings supported by the controller: 12636c8d8eccSSepherosa Ziehau * 12646c8d8eccSSepherosa Ziehau * Standard Receive Producer Ring 12656c8d8eccSSepherosa Ziehau * - This ring is used to feed receive buffers for "standard" 12666c8d8eccSSepherosa Ziehau * sized frames (typically 1536 bytes) to the controller. 12676c8d8eccSSepherosa Ziehau * 12686c8d8eccSSepherosa Ziehau * Jumbo Receive Producer Ring 12696c8d8eccSSepherosa Ziehau * - This ring is used to feed receive buffers for jumbo sized 12706c8d8eccSSepherosa Ziehau * frames (i.e. anything bigger than the "standard" frames) 12716c8d8eccSSepherosa Ziehau * to the controller. 12726c8d8eccSSepherosa Ziehau * 12736c8d8eccSSepherosa Ziehau * Mini Receive Producer Ring 12746c8d8eccSSepherosa Ziehau * - This ring is used to feed receive buffers for "mini" 12756c8d8eccSSepherosa Ziehau * sized frames to the controller. 12766c8d8eccSSepherosa Ziehau * - This feature required external memory for the controller 12776c8d8eccSSepherosa Ziehau * but was never used in a production system. Should always 12786c8d8eccSSepherosa Ziehau * be disabled. 12796c8d8eccSSepherosa Ziehau * 12806c8d8eccSSepherosa Ziehau * Receive Return Ring 12816c8d8eccSSepherosa Ziehau * - After the controller has placed an incoming frame into a 12826c8d8eccSSepherosa Ziehau * receive buffer that buffer is moved into a receive return 12836c8d8eccSSepherosa Ziehau * ring. The driver is then responsible to passing the 12842a581495SSepherosa Ziehau * buffer up to the stack. BCM5718/BCM57785 families support 12852a581495SSepherosa Ziehau * multiple receive return rings. 12866c8d8eccSSepherosa Ziehau * 12876c8d8eccSSepherosa Ziehau * Send Ring 12882a581495SSepherosa Ziehau * - This ring is used for outgoing frames. BCM5719/BCM5720 12892a581495SSepherosa Ziehau * support multiple send rings. 12906c8d8eccSSepherosa Ziehau */ 12916c8d8eccSSepherosa Ziehau 12926c8d8eccSSepherosa Ziehau /* Initialize the standard receive producer ring control block. */ 12936c8d8eccSSepherosa Ziehau rcb = &sc->bnx_ldata.bnx_info.bnx_std_rx_rcb; 12946c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_lo = 1295beedf5beSSepherosa Ziehau BGE_ADDR_LO(sc->bnx_rx_std_ring.bnx_rx_std_ring_paddr); 12966c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_hi = 1297beedf5beSSepherosa Ziehau BGE_ADDR_HI(sc->bnx_rx_std_ring.bnx_rx_std_ring_paddr); 1298f368d0d9SSepherosa Ziehau if (BNX_IS_57765_PLUS(sc)) { 12996c8d8eccSSepherosa Ziehau /* 13006c8d8eccSSepherosa Ziehau * Bits 31-16: Programmable ring size (2048, 1024, 512, .., 32) 13016c8d8eccSSepherosa Ziehau * Bits 15-2 : Maximum RX frame size 13026c8d8eccSSepherosa Ziehau * Bit 1 : 1 = Ring Disabled, 0 = Ring ENabled 13036c8d8eccSSepherosa Ziehau * Bit 0 : Reserved 13046c8d8eccSSepherosa Ziehau */ 13056c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags = 13066c8d8eccSSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(512, BNX_MAX_FRAMELEN << 2); 13076c8d8eccSSepherosa Ziehau } else { 13086c8d8eccSSepherosa Ziehau /* 13096c8d8eccSSepherosa Ziehau * Bits 31-16: Programmable ring size (512, 256, 128, 64, 32) 13106c8d8eccSSepherosa Ziehau * Bits 15-2 : Reserved (should be 0) 13116c8d8eccSSepherosa Ziehau * Bit 1 : 1 = Ring Disabled, 0 = Ring Enabled 13126c8d8eccSSepherosa Ziehau * Bit 0 : Reserved 13136c8d8eccSSepherosa Ziehau */ 13146c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(512, 0); 13156c8d8eccSSepherosa Ziehau } 1316303fdc72SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) 13176c8d8eccSSepherosa Ziehau rcb->bge_nicaddr = BGE_STD_RX_RINGS_5717; 13186c8d8eccSSepherosa Ziehau else 13196c8d8eccSSepherosa Ziehau rcb->bge_nicaddr = BGE_STD_RX_RINGS; 13206c8d8eccSSepherosa Ziehau /* Write the standard receive producer ring control block. */ 13216c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_HI, rcb->bge_hostaddr.bge_addr_hi); 13226c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_LO, rcb->bge_hostaddr.bge_addr_lo); 13236c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_STD_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags); 1324695a8586SSepherosa Ziehau if (!BNX_IS_5717_PLUS(sc)) 13256c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_STD_RCB_NICADDR, rcb->bge_nicaddr); 13266c8d8eccSSepherosa Ziehau /* Reset the standard receive producer ring producer index. */ 13276c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_RX_STD_PROD_LO, 0); 13286c8d8eccSSepherosa Ziehau 13296c8d8eccSSepherosa Ziehau /* 13306c8d8eccSSepherosa Ziehau * Initialize the jumbo RX producer ring control 13316c8d8eccSSepherosa Ziehau * block. We set the 'ring disabled' bit in the 13326c8d8eccSSepherosa Ziehau * flags field until we're actually ready to start 13336c8d8eccSSepherosa Ziehau * using this ring (i.e. once we set the MTU 13346c8d8eccSSepherosa Ziehau * high enough to require it). 13356c8d8eccSSepherosa Ziehau */ 13366c8d8eccSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) { 13376c8d8eccSSepherosa Ziehau rcb = &sc->bnx_ldata.bnx_info.bnx_jumbo_rx_rcb; 13386c8d8eccSSepherosa Ziehau /* Get the jumbo receive producer ring RCB parameters. */ 13396c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_lo = 13406c8d8eccSSepherosa Ziehau BGE_ADDR_LO(sc->bnx_ldata.bnx_rx_jumbo_ring_paddr); 13416c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_hi = 13426c8d8eccSSepherosa Ziehau BGE_ADDR_HI(sc->bnx_ldata.bnx_rx_jumbo_ring_paddr); 13436c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags = 13446c8d8eccSSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(BNX_MAX_FRAMELEN, 13456c8d8eccSSepherosa Ziehau BGE_RCB_FLAG_RING_DISABLED); 1346303fdc72SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) 13476c8d8eccSSepherosa Ziehau rcb->bge_nicaddr = BGE_JUMBO_RX_RINGS_5717; 13486c8d8eccSSepherosa Ziehau else 13496c8d8eccSSepherosa Ziehau rcb->bge_nicaddr = BGE_JUMBO_RX_RINGS; 13506c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_HADDR_HI, 13516c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_hi); 13526c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_HADDR_LO, 13536c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_lo); 13546c8d8eccSSepherosa Ziehau /* Program the jumbo receive producer ring RCB parameters. */ 13556c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, 13566c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags); 13576c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_NICADDR, rcb->bge_nicaddr); 13586c8d8eccSSepherosa Ziehau /* Reset the jumbo receive producer ring producer index. */ 13596c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, 0); 13606c8d8eccSSepherosa Ziehau } 13616c8d8eccSSepherosa Ziehau 13626c8d8eccSSepherosa Ziehau /* 13636c8d8eccSSepherosa Ziehau * The BD ring replenish thresholds control how often the 13646c8d8eccSSepherosa Ziehau * hardware fetches new BD's from the producer rings in host 13656c8d8eccSSepherosa Ziehau * memory. Setting the value too low on a busy system can 13666c8d8eccSSepherosa Ziehau * starve the hardware and recue the throughpout. 13676c8d8eccSSepherosa Ziehau * 13686c8d8eccSSepherosa Ziehau * Set the BD ring replentish thresholds. The recommended 13696c8d8eccSSepherosa Ziehau * values are 1/8th the number of descriptors allocated to 13706c8d8eccSSepherosa Ziehau * each ring. 13716c8d8eccSSepherosa Ziehau */ 13726c8d8eccSSepherosa Ziehau val = 8; 13736c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RBDI_STD_REPL_THRESH, val); 13746c8d8eccSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) { 13756c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RBDI_JUMBO_REPL_THRESH, 13766c8d8eccSSepherosa Ziehau BGE_JUMBO_RX_RING_CNT/8); 13776c8d8eccSSepherosa Ziehau } 1378f368d0d9SSepherosa Ziehau if (BNX_IS_57765_PLUS(sc)) { 13796c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_STD_REPLENISH_LWM, 32); 13806c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_JMB_REPLENISH_LWM, 16); 13816c8d8eccSSepherosa Ziehau } 13826c8d8eccSSepherosa Ziehau 13836c8d8eccSSepherosa Ziehau /* 13846c8d8eccSSepherosa Ziehau * Disable all send rings by setting the 'ring disabled' bit 13856c8d8eccSSepherosa Ziehau * in the flags field of all the TX send ring control blocks, 13866c8d8eccSSepherosa Ziehau * located in NIC memory. 13876c8d8eccSSepherosa Ziehau */ 138880969639SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) 138980969639SSepherosa Ziehau limit = 4; 1390b96cbbb6SSepherosa Ziehau else if (BNX_IS_57765_FAMILY(sc) || 1391b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) 13924f23029eSSepherosa Ziehau limit = 2; 139380969639SSepherosa Ziehau else 13946c8d8eccSSepherosa Ziehau limit = 1; 13956c8d8eccSSepherosa Ziehau vrcb = BGE_MEMWIN_START + BGE_SEND_RING_RCB; 13966c8d8eccSSepherosa Ziehau for (i = 0; i < limit; i++) { 13976c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, 13986c8d8eccSSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_RING_DISABLED)); 13996c8d8eccSSepherosa Ziehau vrcb += sizeof(struct bge_rcb); 14006c8d8eccSSepherosa Ziehau } 14016c8d8eccSSepherosa Ziehau 1402695a8586SSepherosa Ziehau /* 1403695a8586SSepherosa Ziehau * Configure send ring RCBs 1404695a8586SSepherosa Ziehau */ 14056c8d8eccSSepherosa Ziehau vrcb = BGE_MEMWIN_START + BGE_SEND_RING_RCB; 1406695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 1407695a8586SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 1408695a8586SSepherosa Ziehau 140933a04907SSepherosa Ziehau BGE_HOSTADDR(taddr, txr->bnx_tx_ring_paddr); 1410695a8586SSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, 1411695a8586SSepherosa Ziehau taddr.bge_addr_hi); 1412695a8586SSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, 1413695a8586SSepherosa Ziehau taddr.bge_addr_lo); 14146c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, 14156c8d8eccSSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(BGE_TX_RING_CNT, 0)); 1416695a8586SSepherosa Ziehau vrcb += sizeof(struct bge_rcb); 1417695a8586SSepherosa Ziehau } 14186c8d8eccSSepherosa Ziehau 14196c8d8eccSSepherosa Ziehau /* 14206c8d8eccSSepherosa Ziehau * Disable all receive return rings by setting the 14216c8d8eccSSepherosa Ziehau * 'ring disabled' bit in the flags field of all the receive 14226c8d8eccSSepherosa Ziehau * return ring control blocks, located in NIC memory. 14236c8d8eccSSepherosa Ziehau */ 142480969639SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) { 14256c8d8eccSSepherosa Ziehau /* Should be 17, use 16 until we get an SRAM map. */ 14266c8d8eccSSepherosa Ziehau limit = 16; 1427b96cbbb6SSepherosa Ziehau } else if (BNX_IS_57765_FAMILY(sc) || 1428b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 14296c8d8eccSSepherosa Ziehau limit = 4; 14306c8d8eccSSepherosa Ziehau } else { 14316c8d8eccSSepherosa Ziehau limit = 1; 14326c8d8eccSSepherosa Ziehau } 14336c8d8eccSSepherosa Ziehau /* Disable all receive return rings. */ 14346c8d8eccSSepherosa Ziehau vrcb = BGE_MEMWIN_START + BGE_RX_RETURN_RING_RCB; 14356c8d8eccSSepherosa Ziehau for (i = 0; i < limit; i++) { 14366c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, 0); 14376c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, 0); 14386c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, 14396c8d8eccSSepherosa Ziehau BGE_RCB_FLAG_RING_DISABLED); 14406c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_RX_CONS0_LO + 14416c8d8eccSSepherosa Ziehau (i * (sizeof(uint64_t))), 0); 14426c8d8eccSSepherosa Ziehau vrcb += sizeof(struct bge_rcb); 14436c8d8eccSSepherosa Ziehau } 14446c8d8eccSSepherosa Ziehau 14456c8d8eccSSepherosa Ziehau /* 14462a581495SSepherosa Ziehau * Set up receive return rings. 14476c8d8eccSSepherosa Ziehau */ 14486c8d8eccSSepherosa Ziehau vrcb = BGE_MEMWIN_START + BGE_RX_RETURN_RING_RCB; 1449695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 1450695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[i]; 1451695a8586SSepherosa Ziehau 1452beedf5beSSepherosa Ziehau BGE_HOSTADDR(taddr, ret->bnx_rx_ret_ring_paddr); 1453695a8586SSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, 1454695a8586SSepherosa Ziehau taddr.bge_addr_hi); 1455695a8586SSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, 1456695a8586SSepherosa Ziehau taddr.bge_addr_lo); 14576c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, 1458e0f74fc8SSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(BNX_RETURN_RING_CNT, 0)); 1459695a8586SSepherosa Ziehau vrcb += sizeof(struct bge_rcb); 1460695a8586SSepherosa Ziehau } 14616c8d8eccSSepherosa Ziehau 14626c8d8eccSSepherosa Ziehau /* Set random backoff seed for TX */ 14636c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_TX_RANDOM_BACKOFF, 14646c8d8eccSSepherosa Ziehau sc->arpcom.ac_enaddr[0] + sc->arpcom.ac_enaddr[1] + 14656c8d8eccSSepherosa Ziehau sc->arpcom.ac_enaddr[2] + sc->arpcom.ac_enaddr[3] + 14666c8d8eccSSepherosa Ziehau sc->arpcom.ac_enaddr[4] + sc->arpcom.ac_enaddr[5] + 14676c8d8eccSSepherosa Ziehau BGE_TX_BACKOFF_SEED_MASK); 14686c8d8eccSSepherosa Ziehau 14696c8d8eccSSepherosa Ziehau /* Set inter-packet gap */ 14706c8d8eccSSepherosa Ziehau val = 0x2620; 1471b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 1472b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 14736c8d8eccSSepherosa Ziehau val |= CSR_READ_4(sc, BGE_TX_LENGTHS) & 14746c8d8eccSSepherosa Ziehau (BGE_TXLEN_JMB_FRM_LEN_MSK | BGE_TXLEN_CNT_DN_VAL_MSK); 14756c8d8eccSSepherosa Ziehau } 14766c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_TX_LENGTHS, val); 14776c8d8eccSSepherosa Ziehau 14786c8d8eccSSepherosa Ziehau /* 14796c8d8eccSSepherosa Ziehau * Specify which ring to use for packets that don't match 14806c8d8eccSSepherosa Ziehau * any RX rules. 14816c8d8eccSSepherosa Ziehau */ 14826c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_RULES_CFG, 0x08); 14836c8d8eccSSepherosa Ziehau 14846c8d8eccSSepherosa Ziehau /* 14856c8d8eccSSepherosa Ziehau * Configure number of RX lists. One interrupt distribution 14866c8d8eccSSepherosa Ziehau * list, sixteen active lists, one bad frames class. 14876c8d8eccSSepherosa Ziehau */ 14886c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RXLP_CFG, 0x181); 14896c8d8eccSSepherosa Ziehau 14906c8d8eccSSepherosa Ziehau /* Inialize RX list placement stats mask. */ 14916c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RXLP_STATS_ENABLE_MASK, 0x007FFFFF); 14926c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RXLP_STATS_CTL, 0x1); 14936c8d8eccSSepherosa Ziehau 14946c8d8eccSSepherosa Ziehau /* Disable host coalescing until we get it set up */ 14956c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_MODE, 0x00000000); 14966c8d8eccSSepherosa Ziehau 14976c8d8eccSSepherosa Ziehau /* Poll to make sure it's shut down. */ 14986c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 14996c8d8eccSSepherosa Ziehau if (!(CSR_READ_4(sc, BGE_HCC_MODE) & BGE_HCCMODE_ENABLE)) 15006c8d8eccSSepherosa Ziehau break; 15016c8d8eccSSepherosa Ziehau DELAY(10); 15026c8d8eccSSepherosa Ziehau } 15036c8d8eccSSepherosa Ziehau 15046c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 15056c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 15066c8d8eccSSepherosa Ziehau "host coalescing engine failed to idle\n"); 15076c8d8eccSSepherosa Ziehau return(ENXIO); 15086c8d8eccSSepherosa Ziehau } 15096c8d8eccSSepherosa Ziehau 15106c8d8eccSSepherosa Ziehau /* Set up host coalescing defaults */ 1511695a8586SSepherosa Ziehau sc->bnx_coal_chg = BNX_RX_COAL_TICKS_CHG | 1512695a8586SSepherosa Ziehau BNX_TX_COAL_TICKS_CHG | 1513695a8586SSepherosa Ziehau BNX_RX_COAL_BDS_CHG | 1514695a8586SSepherosa Ziehau BNX_TX_COAL_BDS_CHG | 1515695a8586SSepherosa Ziehau BNX_RX_COAL_BDS_INT_CHG | 1516695a8586SSepherosa Ziehau BNX_TX_COAL_BDS_INT_CHG; 1517695a8586SSepherosa Ziehau bnx_coal_change(sc); 15186c8d8eccSSepherosa Ziehau 1519695a8586SSepherosa Ziehau /* 1520695a8586SSepherosa Ziehau * Set up addresses of status blocks 1521695a8586SSepherosa Ziehau */ 1522695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 15230a806e3aSSepherosa Ziehau bzero(intr->bnx_status_block, BGE_STATUS_BLK_SZ); 15246c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_HI, 15250a806e3aSSepherosa Ziehau BGE_ADDR_HI(intr->bnx_status_block_paddr)); 15266c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_LO, 15270a806e3aSSepherosa Ziehau BGE_ADDR_LO(intr->bnx_status_block_paddr)); 1528695a8586SSepherosa Ziehau for (i = 1; i < sc->bnx_intr_cnt; ++i) { 1529695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[i]; 1530695a8586SSepherosa Ziehau bzero(intr->bnx_status_block, BGE_STATUS_BLK_SZ); 1531695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_STATUSBLK_ADDR_HI + ((i - 1) * 8), 1532695a8586SSepherosa Ziehau BGE_ADDR_HI(intr->bnx_status_block_paddr)); 1533695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_STATUSBLK_ADDR_LO + ((i - 1) * 8), 1534695a8586SSepherosa Ziehau BGE_ADDR_LO(intr->bnx_status_block_paddr)); 1535695a8586SSepherosa Ziehau } 15366c8d8eccSSepherosa Ziehau 15376c8d8eccSSepherosa Ziehau /* Set up status block partail update size. */ 15386c8d8eccSSepherosa Ziehau val = BGE_STATBLKSZ_32BYTE; 15396c8d8eccSSepherosa Ziehau #if 0 15406c8d8eccSSepherosa Ziehau /* 15416c8d8eccSSepherosa Ziehau * Does not seem to have visible effect in both 15426c8d8eccSSepherosa Ziehau * bulk data (1472B UDP datagram) and tiny data 15436c8d8eccSSepherosa Ziehau * (18B UDP datagram) TX tests. 15446c8d8eccSSepherosa Ziehau */ 15456c8d8eccSSepherosa Ziehau val |= BGE_HCCMODE_CLRTICK_TX; 15466c8d8eccSSepherosa Ziehau #endif 15476c8d8eccSSepherosa Ziehau /* Turn on host coalescing state machine */ 15486c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_MODE, val | BGE_HCCMODE_ENABLE); 15496c8d8eccSSepherosa Ziehau 15506c8d8eccSSepherosa Ziehau /* Turn on RX BD completion state machine and enable attentions */ 15516c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RBDC_MODE, 15526c8d8eccSSepherosa Ziehau BGE_RBDCMODE_ENABLE|BGE_RBDCMODE_ATTN); 15536c8d8eccSSepherosa Ziehau 15546c8d8eccSSepherosa Ziehau /* Turn on RX list placement state machine */ 15556c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RXLP_MODE, BGE_RXLPMODE_ENABLE); 15566c8d8eccSSepherosa Ziehau 15576c8d8eccSSepherosa Ziehau val = BGE_MACMODE_TXDMA_ENB | BGE_MACMODE_RXDMA_ENB | 15586c8d8eccSSepherosa Ziehau BGE_MACMODE_RX_STATS_CLEAR | BGE_MACMODE_TX_STATS_CLEAR | 15596c8d8eccSSepherosa Ziehau BGE_MACMODE_RX_STATS_ENB | BGE_MACMODE_TX_STATS_ENB | 15606c8d8eccSSepherosa Ziehau BGE_MACMODE_FRMHDR_DMA_ENB; 15616c8d8eccSSepherosa Ziehau 15626c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) 15636c8d8eccSSepherosa Ziehau val |= BGE_PORTMODE_TBI; 15646c8d8eccSSepherosa Ziehau else if (sc->bnx_flags & BNX_FLAG_MII_SERDES) 15656c8d8eccSSepherosa Ziehau val |= BGE_PORTMODE_GMII; 15666c8d8eccSSepherosa Ziehau else 15676c8d8eccSSepherosa Ziehau val |= BGE_PORTMODE_MII; 15686c8d8eccSSepherosa Ziehau 15696c8d8eccSSepherosa Ziehau /* Turn on DMA, clear stats */ 15706c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_MODE, val); 15716c8d8eccSSepherosa Ziehau 15726c8d8eccSSepherosa Ziehau /* Set misc. local control, enable interrupts on attentions */ 15736c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_ONATTN); 15746c8d8eccSSepherosa Ziehau 15756c8d8eccSSepherosa Ziehau #ifdef notdef 15766c8d8eccSSepherosa Ziehau /* Assert GPIO pins for PHY reset */ 15776c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_MISCIO_OUT0| 15786c8d8eccSSepherosa Ziehau BGE_MLC_MISCIO_OUT1|BGE_MLC_MISCIO_OUT2); 15796c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_MISCIO_OUTEN0| 15806c8d8eccSSepherosa Ziehau BGE_MLC_MISCIO_OUTEN1|BGE_MLC_MISCIO_OUTEN2); 15816c8d8eccSSepherosa Ziehau #endif 15826c8d8eccSSepherosa Ziehau 1583695a8586SSepherosa Ziehau if (sc->bnx_intr_type == PCI_INTR_TYPE_MSIX) 1584695a8586SSepherosa Ziehau bnx_enable_msi(sc, TRUE); 1585695a8586SSepherosa Ziehau 15866c8d8eccSSepherosa Ziehau /* Turn on write DMA state machine */ 15876c8d8eccSSepherosa Ziehau val = BGE_WDMAMODE_ENABLE|BGE_WDMAMODE_ALL_ATTNS; 15886c8d8eccSSepherosa Ziehau /* Enable host coalescing bug fix. */ 15896c8d8eccSSepherosa Ziehau val |= BGE_WDMAMODE_STATUS_TAG_FIX; 15906c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5785) { 15916c8d8eccSSepherosa Ziehau /* Request larger DMA burst size to get better performance. */ 15926c8d8eccSSepherosa Ziehau val |= BGE_WDMAMODE_BURST_ALL_DATA; 15936c8d8eccSSepherosa Ziehau } 15946c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_WDMA_MODE, val); 15956c8d8eccSSepherosa Ziehau DELAY(40); 15966c8d8eccSSepherosa Ziehau 15973730a14dSSepherosa Ziehau if (BNX_IS_57765_PLUS(sc)) { 1598b96cbbb6SSepherosa Ziehau uint32_t dmactl, dmactl_reg; 15996c8d8eccSSepherosa Ziehau 1600b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5762) 1601b96cbbb6SSepherosa Ziehau dmactl_reg = BGE_RDMA_RSRVCTRL2; 1602b96cbbb6SSepherosa Ziehau else 1603b96cbbb6SSepherosa Ziehau dmactl_reg = BGE_RDMA_RSRVCTRL; 1604b96cbbb6SSepherosa Ziehau 1605b96cbbb6SSepherosa Ziehau dmactl = CSR_READ_4(sc, dmactl_reg); 16066c8d8eccSSepherosa Ziehau /* 16076c8d8eccSSepherosa Ziehau * Adjust tx margin to prevent TX data corruption and 16086c8d8eccSSepherosa Ziehau * fix internal FIFO overflow. 16096c8d8eccSSepherosa Ziehau */ 16106c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719 || 1611b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 1612b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 16136c8d8eccSSepherosa Ziehau dmactl &= ~(BGE_RDMA_RSRVCTRL_FIFO_LWM_MASK | 16146c8d8eccSSepherosa Ziehau BGE_RDMA_RSRVCTRL_FIFO_HWM_MASK | 16156c8d8eccSSepherosa Ziehau BGE_RDMA_RSRVCTRL_TXMRGN_MASK); 16166c8d8eccSSepherosa Ziehau dmactl |= BGE_RDMA_RSRVCTRL_FIFO_LWM_1_5K | 16176c8d8eccSSepherosa Ziehau BGE_RDMA_RSRVCTRL_FIFO_HWM_1_5K | 16186c8d8eccSSepherosa Ziehau BGE_RDMA_RSRVCTRL_TXMRGN_320B; 16196c8d8eccSSepherosa Ziehau } 16206c8d8eccSSepherosa Ziehau /* 16216c8d8eccSSepherosa Ziehau * Enable fix for read DMA FIFO overruns. 16226c8d8eccSSepherosa Ziehau * The fix is to limit the number of RX BDs 16236c8d8eccSSepherosa Ziehau * the hardware would fetch at a fime. 16246c8d8eccSSepherosa Ziehau */ 1625b96cbbb6SSepherosa Ziehau CSR_WRITE_4(sc, dmactl_reg, 16266c8d8eccSSepherosa Ziehau dmactl | BGE_RDMA_RSRVCTRL_FIFO_OFLW_FIX); 16276c8d8eccSSepherosa Ziehau } 16286c8d8eccSSepherosa Ziehau 16296c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719) { 16306c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL, 16316c8d8eccSSepherosa Ziehau CSR_READ_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL) | 16326c8d8eccSSepherosa Ziehau BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_BD_4K | 16336c8d8eccSSepherosa Ziehau BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_LSO_4K); 1634b96cbbb6SSepherosa Ziehau } else if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 1635b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 1636b96cbbb6SSepherosa Ziehau uint32_t ctrl_reg; 1637b96cbbb6SSepherosa Ziehau 1638b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5762) 1639b96cbbb6SSepherosa Ziehau ctrl_reg = BGE_RDMA_LSO_CRPTEN_CTRL2; 1640b96cbbb6SSepherosa Ziehau else 1641b96cbbb6SSepherosa Ziehau ctrl_reg = BGE_RDMA_LSO_CRPTEN_CTRL; 1642b96cbbb6SSepherosa Ziehau 16436c8d8eccSSepherosa Ziehau /* 16446c8d8eccSSepherosa Ziehau * Allow 4KB burst length reads for non-LSO frames. 16456c8d8eccSSepherosa Ziehau * Enable 512B burst length reads for buffer descriptors. 16466c8d8eccSSepherosa Ziehau */ 1647b96cbbb6SSepherosa Ziehau CSR_WRITE_4(sc, ctrl_reg, 1648b96cbbb6SSepherosa Ziehau CSR_READ_4(sc, ctrl_reg) | 16496c8d8eccSSepherosa Ziehau BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_BD_512 | 16506c8d8eccSSepherosa Ziehau BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_LSO_4K); 16516c8d8eccSSepherosa Ziehau } 16526c8d8eccSSepherosa Ziehau 16536c8d8eccSSepherosa Ziehau /* Turn on read DMA state machine */ 16546c8d8eccSSepherosa Ziehau val = BGE_RDMAMODE_ENABLE | BGE_RDMAMODE_ALL_ATTNS; 16556c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5717) 16566c8d8eccSSepherosa Ziehau val |= BGE_RDMAMODE_MULT_DMA_RD_DIS; 16576c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5784 || 16586c8d8eccSSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5785 || 16596c8d8eccSSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM57780) { 16606c8d8eccSSepherosa Ziehau val |= BGE_RDMAMODE_BD_SBD_CRPT_ATTN | 16616c8d8eccSSepherosa Ziehau BGE_RDMAMODE_MBUF_RBD_CRPT_ATTN | 16626c8d8eccSSepherosa Ziehau BGE_RDMAMODE_MBUF_SBD_CRPT_ATTN; 16636c8d8eccSSepherosa Ziehau } 1664b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 1665b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 16666c8d8eccSSepherosa Ziehau val |= CSR_READ_4(sc, BGE_RDMA_MODE) & 16676c8d8eccSSepherosa Ziehau BGE_RDMAMODE_H2BNC_VLAN_DET; 16686c8d8eccSSepherosa Ziehau /* 16696c8d8eccSSepherosa Ziehau * Allow multiple outstanding read requests from 16706c8d8eccSSepherosa Ziehau * non-LSO read DMA engine. 16716c8d8eccSSepherosa Ziehau */ 16726c8d8eccSSepherosa Ziehau val &= ~BGE_RDMAMODE_MULT_DMA_RD_DIS; 16736c8d8eccSSepherosa Ziehau } 167460e67e3fSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM57766) 167560e67e3fSSepherosa Ziehau val |= BGE_RDMAMODE_JMB_2K_MMRR; 167666deb1c1SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TSO) 167766deb1c1SSepherosa Ziehau val |= BGE_RDMAMODE_TSO4_ENABLE; 16786c8d8eccSSepherosa Ziehau val |= BGE_RDMAMODE_FIFO_LONG_BURST; 16796c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RDMA_MODE, val); 16806c8d8eccSSepherosa Ziehau DELAY(40); 16816c8d8eccSSepherosa Ziehau 16826c8d8eccSSepherosa Ziehau /* Turn on RX data completion state machine */ 16836c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RDC_MODE, BGE_RDCMODE_ENABLE); 16846c8d8eccSSepherosa Ziehau 16856c8d8eccSSepherosa Ziehau /* Turn on RX BD initiator state machine */ 16866c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RBDI_MODE, BGE_RBDIMODE_ENABLE); 16876c8d8eccSSepherosa Ziehau 16886c8d8eccSSepherosa Ziehau /* Turn on RX data and RX BD initiator state machine */ 16896c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RDBDI_MODE, BGE_RDBDIMODE_ENABLE); 16906c8d8eccSSepherosa Ziehau 16916c8d8eccSSepherosa Ziehau /* Turn on send BD completion state machine */ 16926c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SBDC_MODE, BGE_SBDCMODE_ENABLE); 16936c8d8eccSSepherosa Ziehau 16946c8d8eccSSepherosa Ziehau /* Turn on send data completion state machine */ 16956c8d8eccSSepherosa Ziehau val = BGE_SDCMODE_ENABLE; 16966c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5761) 16976c8d8eccSSepherosa Ziehau val |= BGE_SDCMODE_CDELAY; 16986c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDC_MODE, val); 16996c8d8eccSSepherosa Ziehau 17006c8d8eccSSepherosa Ziehau /* Turn on send data initiator state machine */ 170166deb1c1SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TSO) { 170266deb1c1SSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE | 170366deb1c1SSepherosa Ziehau BGE_SDIMODE_HW_LSO_PRE_DMA); 170466deb1c1SSepherosa Ziehau } else { 17056c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE); 170666deb1c1SSepherosa Ziehau } 17076c8d8eccSSepherosa Ziehau 17086c8d8eccSSepherosa Ziehau /* Turn on send BD initiator state machine */ 1709695a8586SSepherosa Ziehau val = BGE_SBDIMODE_ENABLE; 1710695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt > 1) 1711695a8586SSepherosa Ziehau val |= BGE_SBDIMODE_MULTI_TXR; 1712695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_SBDI_MODE, val); 17136c8d8eccSSepherosa Ziehau 17146c8d8eccSSepherosa Ziehau /* Turn on send BD selector state machine */ 17156c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SRS_MODE, BGE_SRSMODE_ENABLE); 17166c8d8eccSSepherosa Ziehau 17176c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDI_STATS_ENABLE_MASK, 0x007FFFFF); 17186c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDI_STATS_CTL, 17196c8d8eccSSepherosa Ziehau BGE_SDISTATSCTL_ENABLE|BGE_SDISTATSCTL_FASTER); 17206c8d8eccSSepherosa Ziehau 17216c8d8eccSSepherosa Ziehau /* ack/clear link change events */ 17226c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED| 17236c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED|BGE_MACSTAT_MI_COMPLETE| 17246c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 17256c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_STS, 0); 17266c8d8eccSSepherosa Ziehau 17276c8d8eccSSepherosa Ziehau /* 17286c8d8eccSSepherosa Ziehau * Enable attention when the link has changed state for 17296c8d8eccSSepherosa Ziehau * devices that use auto polling. 17306c8d8eccSSepherosa Ziehau */ 17316c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 17326c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_STS, BGE_MISTS_LINK); 17336c8d8eccSSepherosa Ziehau } else { 17346c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 17356c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, sc->bnx_mi_mode); 17366c8d8eccSSepherosa Ziehau DELAY(80); 17376c8d8eccSSepherosa Ziehau } 17386c8d8eccSSepherosa Ziehau } 17396c8d8eccSSepherosa Ziehau 17406c8d8eccSSepherosa Ziehau /* 17416c8d8eccSSepherosa Ziehau * Clear any pending link state attention. 17426c8d8eccSSepherosa Ziehau * Otherwise some link state change events may be lost until attention 17436c8d8eccSSepherosa Ziehau * is cleared by bnx_intr() -> bnx_softc.bnx_link_upd() sequence. 17446c8d8eccSSepherosa Ziehau * It's not necessary on newer BCM chips - perhaps enabling link 17456c8d8eccSSepherosa Ziehau * state change attentions implies clearing pending attention. 17466c8d8eccSSepherosa Ziehau */ 17476c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED| 17486c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED|BGE_MACSTAT_MI_COMPLETE| 17496c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 17506c8d8eccSSepherosa Ziehau 17516c8d8eccSSepherosa Ziehau /* Enable link state change attentions. */ 17526c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MAC_EVT_ENB, BGE_EVTENB_LINK_CHANGED); 17536c8d8eccSSepherosa Ziehau 17546c8d8eccSSepherosa Ziehau return(0); 17556c8d8eccSSepherosa Ziehau } 17566c8d8eccSSepherosa Ziehau 17576c8d8eccSSepherosa Ziehau /* 17586c8d8eccSSepherosa Ziehau * Probe for a Broadcom chip. Check the PCI vendor and device IDs 17596c8d8eccSSepherosa Ziehau * against our list and return its name if we find a match. Note 17606c8d8eccSSepherosa Ziehau * that since the Broadcom controller contains VPD support, we 17616c8d8eccSSepherosa Ziehau * can get the device name string from the controller itself instead 17626c8d8eccSSepherosa Ziehau * of the compiled-in string. This is a little slow, but it guarantees 17636c8d8eccSSepherosa Ziehau * we'll always announce the right product name. 17646c8d8eccSSepherosa Ziehau */ 17656c8d8eccSSepherosa Ziehau static int 17666c8d8eccSSepherosa Ziehau bnx_probe(device_t dev) 17676c8d8eccSSepherosa Ziehau { 17686c8d8eccSSepherosa Ziehau const struct bnx_type *t; 17696c8d8eccSSepherosa Ziehau uint16_t product, vendor; 17706c8d8eccSSepherosa Ziehau 17716c8d8eccSSepherosa Ziehau if (!pci_is_pcie(dev)) 17726c8d8eccSSepherosa Ziehau return ENXIO; 17736c8d8eccSSepherosa Ziehau 17746c8d8eccSSepherosa Ziehau product = pci_get_device(dev); 17756c8d8eccSSepherosa Ziehau vendor = pci_get_vendor(dev); 17766c8d8eccSSepherosa Ziehau 17776c8d8eccSSepherosa Ziehau for (t = bnx_devs; t->bnx_name != NULL; t++) { 17786c8d8eccSSepherosa Ziehau if (vendor == t->bnx_vid && product == t->bnx_did) 17796c8d8eccSSepherosa Ziehau break; 17806c8d8eccSSepherosa Ziehau } 17816c8d8eccSSepherosa Ziehau if (t->bnx_name == NULL) 17826c8d8eccSSepherosa Ziehau return ENXIO; 17836c8d8eccSSepherosa Ziehau 17846c8d8eccSSepherosa Ziehau device_set_desc(dev, t->bnx_name); 17856c8d8eccSSepherosa Ziehau return 0; 17866c8d8eccSSepherosa Ziehau } 17876c8d8eccSSepherosa Ziehau 17886c8d8eccSSepherosa Ziehau static int 17896c8d8eccSSepherosa Ziehau bnx_attach(device_t dev) 17906c8d8eccSSepherosa Ziehau { 17916c8d8eccSSepherosa Ziehau struct ifnet *ifp; 17926c8d8eccSSepherosa Ziehau struct bnx_softc *sc; 1793841cdf08SSepherosa Ziehau struct bnx_rx_std_ring *std; 1794e594b5c4SSepherosa Ziehau uint32_t hwcfg = 0; 1795841cdf08SSepherosa Ziehau int error = 0, rid, capmask, i, std_cpuid, std_cpuid_def; 17966c8d8eccSSepherosa Ziehau uint8_t ether_addr[ETHER_ADDR_LEN]; 179707e9f7c0SSascha Wildner uint16_t product; 17986c8d8eccSSepherosa Ziehau uintptr_t mii_priv = 0; 1799695a8586SSepherosa Ziehau #if defined(BNX_TSO_DEBUG) || defined(BNX_RSS_DEBUG) || defined(BNX_TSS_DEBUG) 180066deb1c1SSepherosa Ziehau char desc[32]; 180166deb1c1SSepherosa Ziehau #endif 18024fa38985SSepherosa Ziehau #ifdef IFPOLL_ENABLE 18034fa38985SSepherosa Ziehau int offset, offset_def; 18044fa38985SSepherosa Ziehau #endif 18056c8d8eccSSepherosa Ziehau 18066c8d8eccSSepherosa Ziehau sc = device_get_softc(dev); 18076c8d8eccSSepherosa Ziehau sc->bnx_dev = dev; 18087dbaa833SSepherosa Ziehau callout_init_mp(&sc->bnx_tick_timer); 18096c8d8eccSSepherosa Ziehau lwkt_serialize_init(&sc->bnx_jslot_serializer); 1810f33ac8a4SSepherosa Ziehau lwkt_serialize_init(&sc->bnx_main_serialize); 18116c8d8eccSSepherosa Ziehau 1812695a8586SSepherosa Ziehau /* Always setup interrupt mailboxes */ 1813695a8586SSepherosa Ziehau for (i = 0; i < BNX_INTR_MAX; ++i) { 1814695a8586SSepherosa Ziehau callout_init_mp(&sc->bnx_intr_data[i].bnx_intr_timer); 1815695a8586SSepherosa Ziehau sc->bnx_intr_data[i].bnx_sc = sc; 1816695a8586SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_mbx = BGE_MBX_IRQ0_LO + (i * 8); 1817695a8586SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_rid = -1; 1818695a8586SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_cpuid = -1; 1819695a8586SSepherosa Ziehau } 1820695a8586SSepherosa Ziehau 18216c8d8eccSSepherosa Ziehau product = pci_get_device(dev); 18226c8d8eccSSepherosa Ziehau 18236c8d8eccSSepherosa Ziehau #ifndef BURN_BRIDGES 18246c8d8eccSSepherosa Ziehau if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 18256c8d8eccSSepherosa Ziehau uint32_t irq, mem; 18266c8d8eccSSepherosa Ziehau 18276c8d8eccSSepherosa Ziehau irq = pci_read_config(dev, PCIR_INTLINE, 4); 18286c8d8eccSSepherosa Ziehau mem = pci_read_config(dev, BGE_PCI_BAR0, 4); 18296c8d8eccSSepherosa Ziehau 18306c8d8eccSSepherosa Ziehau device_printf(dev, "chip is in D%d power mode " 18316c8d8eccSSepherosa Ziehau "-- setting to D0\n", pci_get_powerstate(dev)); 18326c8d8eccSSepherosa Ziehau 18336c8d8eccSSepherosa Ziehau pci_set_powerstate(dev, PCI_POWERSTATE_D0); 18346c8d8eccSSepherosa Ziehau 18356c8d8eccSSepherosa Ziehau pci_write_config(dev, PCIR_INTLINE, irq, 4); 18366c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_BAR0, mem, 4); 18376c8d8eccSSepherosa Ziehau } 18386c8d8eccSSepherosa Ziehau #endif /* !BURN_BRIDGE */ 18396c8d8eccSSepherosa Ziehau 18406c8d8eccSSepherosa Ziehau /* 18416c8d8eccSSepherosa Ziehau * Map control/status registers. 18426c8d8eccSSepherosa Ziehau */ 18436c8d8eccSSepherosa Ziehau pci_enable_busmaster(dev); 18446c8d8eccSSepherosa Ziehau 18456c8d8eccSSepherosa Ziehau rid = BGE_PCI_BAR0; 18466c8d8eccSSepherosa Ziehau sc->bnx_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 18476c8d8eccSSepherosa Ziehau RF_ACTIVE); 18486c8d8eccSSepherosa Ziehau 18496c8d8eccSSepherosa Ziehau if (sc->bnx_res == NULL) { 18506c8d8eccSSepherosa Ziehau device_printf(dev, "couldn't map memory\n"); 18516c8d8eccSSepherosa Ziehau return ENXIO; 18526c8d8eccSSepherosa Ziehau } 18536c8d8eccSSepherosa Ziehau 18546c8d8eccSSepherosa Ziehau sc->bnx_btag = rman_get_bustag(sc->bnx_res); 18556c8d8eccSSepherosa Ziehau sc->bnx_bhandle = rman_get_bushandle(sc->bnx_res); 18566c8d8eccSSepherosa Ziehau 18576c8d8eccSSepherosa Ziehau /* Save various chip information */ 18586c8d8eccSSepherosa Ziehau sc->bnx_chipid = 18596c8d8eccSSepherosa Ziehau pci_read_config(dev, BGE_PCI_MISC_CTL, 4) >> 18606c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_ASICREV_SHIFT; 18616c8d8eccSSepherosa Ziehau if (BGE_ASICREV(sc->bnx_chipid) == BGE_ASICREV_USE_PRODID_REG) { 18626c8d8eccSSepherosa Ziehau /* All chips having dedicated ASICREV register have CPMU */ 18636c8d8eccSSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_CPMU; 18646c8d8eccSSepherosa Ziehau 18656c8d8eccSSepherosa Ziehau switch (product) { 18666c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5717: 1867d79f5d8fSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5717C: 18686c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5718: 18696c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5719: 18706c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5720_ALT: 1871b96cbbb6SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5725: 1872b96cbbb6SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5727: 1873b96cbbb6SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5762: 18746c8d8eccSSepherosa Ziehau sc->bnx_chipid = pci_read_config(dev, 18756c8d8eccSSepherosa Ziehau BGE_PCI_GEN2_PRODID_ASICREV, 4); 18766c8d8eccSSepherosa Ziehau break; 18776c8d8eccSSepherosa Ziehau 18786c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57761: 187932ff3c80SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57762: 18806c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57765: 188132ff3c80SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57766: 18826c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57781: 188332ff3c80SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57782: 18846c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57785: 188532ff3c80SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57786: 18866c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57791: 18876c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57795: 18886c8d8eccSSepherosa Ziehau sc->bnx_chipid = pci_read_config(dev, 18896c8d8eccSSepherosa Ziehau BGE_PCI_GEN15_PRODID_ASICREV, 4); 18906c8d8eccSSepherosa Ziehau break; 18916c8d8eccSSepherosa Ziehau 18926c8d8eccSSepherosa Ziehau default: 18936c8d8eccSSepherosa Ziehau sc->bnx_chipid = pci_read_config(dev, 18946c8d8eccSSepherosa Ziehau BGE_PCI_PRODID_ASICREV, 4); 18956c8d8eccSSepherosa Ziehau break; 18966c8d8eccSSepherosa Ziehau } 18976c8d8eccSSepherosa Ziehau } 1898d79f5d8fSSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM5717_C0) 1899d79f5d8fSSepherosa Ziehau sc->bnx_chipid = BGE_CHIPID_BCM5720_A0; 1900d79f5d8fSSepherosa Ziehau 19016c8d8eccSSepherosa Ziehau sc->bnx_asicrev = BGE_ASICREV(sc->bnx_chipid); 19026c8d8eccSSepherosa Ziehau sc->bnx_chiprev = BGE_CHIPREV(sc->bnx_chipid); 19036c8d8eccSSepherosa Ziehau 19046c8d8eccSSepherosa Ziehau switch (sc->bnx_asicrev) { 19056c8d8eccSSepherosa Ziehau case BGE_ASICREV_BCM5717: 19066c8d8eccSSepherosa Ziehau case BGE_ASICREV_BCM5719: 19076c8d8eccSSepherosa Ziehau case BGE_ASICREV_BCM5720: 1908f368d0d9SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_5717_PLUS | BNX_FLAG_57765_PLUS; 1909f368d0d9SSepherosa Ziehau break; 1910f368d0d9SSepherosa Ziehau 1911b96cbbb6SSepherosa Ziehau case BGE_ASICREV_BCM5762: 1912b96cbbb6SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_57765_PLUS; 1913b96cbbb6SSepherosa Ziehau break; 1914b96cbbb6SSepherosa Ziehau 19156c8d8eccSSepherosa Ziehau case BGE_ASICREV_BCM57765: 191632ff3c80SSepherosa Ziehau case BGE_ASICREV_BCM57766: 1917f368d0d9SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_57765_FAMILY | BNX_FLAG_57765_PLUS; 19186c8d8eccSSepherosa Ziehau break; 19196c8d8eccSSepherosa Ziehau } 19206c8d8eccSSepherosa Ziehau 192166deb1c1SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_TSO; 192266deb1c1SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719 && 192366deb1c1SSepherosa Ziehau sc->bnx_chipid == BGE_CHIPID_BCM5719_A0) 192466deb1c1SSepherosa Ziehau sc->bnx_flags &= ~BNX_FLAG_TSO; 192566deb1c1SSepherosa Ziehau 1926df9ccc98SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5717 || 1927df9ccc98SSepherosa Ziehau BNX_IS_57765_FAMILY(sc)) { 1928df9ccc98SSepherosa Ziehau /* 1929df9ccc98SSepherosa Ziehau * All BCM57785 and BCM5718 families chips have a bug that 1930df9ccc98SSepherosa Ziehau * under certain situation interrupt will not be enabled 193197ba8fc5SSepherosa Ziehau * even if status tag is written to interrupt mailbox. 1932df9ccc98SSepherosa Ziehau * 1933df9ccc98SSepherosa Ziehau * While BCM5719 and BCM5720 have a hardware workaround 1934df9ccc98SSepherosa Ziehau * which could fix the above bug. 1935df9ccc98SSepherosa Ziehau * See the comment near BGE_PCIDMARWCTL_TAGGED_STATUS_WA in 1936df9ccc98SSepherosa Ziehau * bnx_chipinit(). 1937df9ccc98SSepherosa Ziehau * 1938df9ccc98SSepherosa Ziehau * For the rest of the chips in these two families, we will 1939df9ccc98SSepherosa Ziehau * have to poll the status block at high rate (10ms currently) 1940df9ccc98SSepherosa Ziehau * to check whether the interrupt is hosed or not. 1941695a8586SSepherosa Ziehau * See bnx_check_intr_*() for details. 1942df9ccc98SSepherosa Ziehau */ 1943df9ccc98SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_STATUSTAG_BUG; 1944df9ccc98SSepherosa Ziehau } 1945df9ccc98SSepherosa Ziehau 19466c8d8eccSSepherosa Ziehau sc->bnx_pciecap = pci_get_pciecap_ptr(sc->bnx_dev); 19476c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719 || 19486c8d8eccSSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5720) 19496c8d8eccSSepherosa Ziehau pcie_set_max_readrq(dev, PCIEM_DEVCTL_MAX_READRQ_2048); 19506c8d8eccSSepherosa Ziehau else 19516c8d8eccSSepherosa Ziehau pcie_set_max_readrq(dev, PCIEM_DEVCTL_MAX_READRQ_4096); 19526c8d8eccSSepherosa Ziehau device_printf(dev, "CHIP ID 0x%08x; " 19536c8d8eccSSepherosa Ziehau "ASIC REV 0x%02x; CHIP REV 0x%02x\n", 19546c8d8eccSSepherosa Ziehau sc->bnx_chipid, sc->bnx_asicrev, sc->bnx_chiprev); 19556c8d8eccSSepherosa Ziehau 19566c8d8eccSSepherosa Ziehau /* 19576c8d8eccSSepherosa Ziehau * Set various PHY quirk flags. 19586c8d8eccSSepherosa Ziehau */ 19596c8d8eccSSepherosa Ziehau 19606c8d8eccSSepherosa Ziehau capmask = MII_CAPMASK_DEFAULT; 196146283a40SSepherosa Ziehau if (product == PCI_PRODUCT_BROADCOM_BCM57791 || 196246283a40SSepherosa Ziehau product == PCI_PRODUCT_BROADCOM_BCM57795) { 19636c8d8eccSSepherosa Ziehau /* 10/100 only */ 19646c8d8eccSSepherosa Ziehau capmask &= ~BMSR_EXTSTAT; 19656c8d8eccSSepherosa Ziehau } 19666c8d8eccSSepherosa Ziehau 19676c8d8eccSSepherosa Ziehau mii_priv |= BRGPHY_FLAG_WIRESPEED; 1968b96cbbb6SSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM5762_A0) 1969b96cbbb6SSepherosa Ziehau mii_priv |= BRGPHY_FLAG_5762_A0; 19706c8d8eccSSepherosa Ziehau 19716c8d8eccSSepherosa Ziehau /* Initialize if_name earlier, so if_printf could be used */ 19726c8d8eccSSepherosa Ziehau ifp = &sc->arpcom.ac_if; 19736c8d8eccSSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 19746c8d8eccSSepherosa Ziehau 19756c8d8eccSSepherosa Ziehau /* Try to reset the chip. */ 19766c8d8eccSSepherosa Ziehau bnx_reset(sc); 19776c8d8eccSSepherosa Ziehau 19786c8d8eccSSepherosa Ziehau if (bnx_chipinit(sc)) { 19796c8d8eccSSepherosa Ziehau device_printf(dev, "chip initialization failed\n"); 19806c8d8eccSSepherosa Ziehau error = ENXIO; 19816c8d8eccSSepherosa Ziehau goto fail; 19826c8d8eccSSepherosa Ziehau } 19836c8d8eccSSepherosa Ziehau 19846c8d8eccSSepherosa Ziehau /* 19856c8d8eccSSepherosa Ziehau * Get station address 19866c8d8eccSSepherosa Ziehau */ 19876c8d8eccSSepherosa Ziehau error = bnx_get_eaddr(sc, ether_addr); 19886c8d8eccSSepherosa Ziehau if (error) { 19896c8d8eccSSepherosa Ziehau device_printf(dev, "failed to read station address\n"); 19906c8d8eccSSepherosa Ziehau goto fail; 19916c8d8eccSSepherosa Ziehau } 19926c8d8eccSSepherosa Ziehau 1993695a8586SSepherosa Ziehau /* Setup RX/TX and interrupt count */ 1994695a8586SSepherosa Ziehau bnx_setup_ring_cnt(sc); 199533a04907SSepherosa Ziehau 19964fa38985SSepherosa Ziehau if ((sc->bnx_rx_retcnt == 1 && sc->bnx_tx_ringcnt == 1) || 19974fa38985SSepherosa Ziehau (sc->bnx_rx_retcnt > 1 && sc->bnx_tx_ringcnt > 1)) { 19984fa38985SSepherosa Ziehau /* 19994fa38985SSepherosa Ziehau * The RX ring and the corresponding TX ring processing 20004fa38985SSepherosa Ziehau * should be on the same CPU, since they share the same 20014fa38985SSepherosa Ziehau * status block. 20024fa38985SSepherosa Ziehau */ 20034fa38985SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_RXTX_BUNDLE; 20044fa38985SSepherosa Ziehau if (bootverbose) 20054fa38985SSepherosa Ziehau device_printf(dev, "RX/TX bundle\n"); 2006695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt > 1) { 2007695a8586SSepherosa Ziehau /* 2008695a8586SSepherosa Ziehau * Multiple TX rings do not share status block 2009695a8586SSepherosa Ziehau * with link status, so link status will have 2010695a8586SSepherosa Ziehau * to save its own status_tag. 2011695a8586SSepherosa Ziehau */ 2012695a8586SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_STATUS_HASTAG; 2013695a8586SSepherosa Ziehau if (bootverbose) 2014695a8586SSepherosa Ziehau device_printf(dev, "status needs tag\n"); 2015695a8586SSepherosa Ziehau } 20164fa38985SSepherosa Ziehau } else { 20174fa38985SSepherosa Ziehau KKASSERT(sc->bnx_rx_retcnt > 1 && sc->bnx_tx_ringcnt == 1); 2018695a8586SSepherosa Ziehau if (bootverbose) 2019695a8586SSepherosa Ziehau device_printf(dev, "RX/TX not bundled\n"); 20204fa38985SSepherosa Ziehau } 20214fa38985SSepherosa Ziehau 2022beedf5beSSepherosa Ziehau error = bnx_dma_alloc(dev); 20236c8d8eccSSepherosa Ziehau if (error) 20246c8d8eccSSepherosa Ziehau goto fail; 20256c8d8eccSSepherosa Ziehau 20264fa38985SSepherosa Ziehau #ifdef IFPOLL_ENABLE 20274fa38985SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_RXTX_BUNDLE) { 20284fa38985SSepherosa Ziehau /* 20294fa38985SSepherosa Ziehau * NPOLLING RX/TX CPU offset 20304fa38985SSepherosa Ziehau */ 20314fa38985SSepherosa Ziehau if (sc->bnx_rx_retcnt == ncpus2) { 20324fa38985SSepherosa Ziehau offset = 0; 20334fa38985SSepherosa Ziehau } else { 20344fa38985SSepherosa Ziehau offset_def = 20354fa38985SSepherosa Ziehau (sc->bnx_rx_retcnt * device_get_unit(dev)) % ncpus2; 20364fa38985SSepherosa Ziehau offset = device_getenv_int(dev, "npoll.offset", 20374fa38985SSepherosa Ziehau offset_def); 20384fa38985SSepherosa Ziehau if (offset >= ncpus2 || 20394fa38985SSepherosa Ziehau offset % sc->bnx_rx_retcnt != 0) { 20404fa38985SSepherosa Ziehau device_printf(dev, "invalid npoll.offset %d, " 20414fa38985SSepherosa Ziehau "use %d\n", offset, offset_def); 20424fa38985SSepherosa Ziehau offset = offset_def; 20434fa38985SSepherosa Ziehau } 20444fa38985SSepherosa Ziehau } 20454fa38985SSepherosa Ziehau sc->bnx_npoll_rxoff = offset; 20464fa38985SSepherosa Ziehau sc->bnx_npoll_txoff = offset; 20474fa38985SSepherosa Ziehau } else { 20484fa38985SSepherosa Ziehau /* 20494fa38985SSepherosa Ziehau * NPOLLING RX CPU offset 20504fa38985SSepherosa Ziehau */ 20514fa38985SSepherosa Ziehau if (sc->bnx_rx_retcnt == ncpus2) { 20524fa38985SSepherosa Ziehau offset = 0; 20534fa38985SSepherosa Ziehau } else { 20544fa38985SSepherosa Ziehau offset_def = 20554fa38985SSepherosa Ziehau (sc->bnx_rx_retcnt * device_get_unit(dev)) % ncpus2; 20564fa38985SSepherosa Ziehau offset = device_getenv_int(dev, "npoll.rxoff", 20574fa38985SSepherosa Ziehau offset_def); 20584fa38985SSepherosa Ziehau if (offset >= ncpus2 || 20594fa38985SSepherosa Ziehau offset % sc->bnx_rx_retcnt != 0) { 20604fa38985SSepherosa Ziehau device_printf(dev, "invalid npoll.rxoff %d, " 20614fa38985SSepherosa Ziehau "use %d\n", offset, offset_def); 20624fa38985SSepherosa Ziehau offset = offset_def; 20634fa38985SSepherosa Ziehau } 20644fa38985SSepherosa Ziehau } 20654fa38985SSepherosa Ziehau sc->bnx_npoll_rxoff = offset; 20664fa38985SSepherosa Ziehau 20674fa38985SSepherosa Ziehau /* 20684fa38985SSepherosa Ziehau * NPOLLING TX CPU offset 20694fa38985SSepherosa Ziehau */ 20704fa38985SSepherosa Ziehau offset_def = device_get_unit(dev) % ncpus2; 20714fa38985SSepherosa Ziehau offset = device_getenv_int(dev, "npoll.txoff", offset_def); 20724fa38985SSepherosa Ziehau if (offset >= ncpus2) { 20734fa38985SSepherosa Ziehau device_printf(dev, "invalid npoll.txoff %d, use %d\n", 20744fa38985SSepherosa Ziehau offset, offset_def); 20754fa38985SSepherosa Ziehau offset = offset_def; 20764fa38985SSepherosa Ziehau } 20774fa38985SSepherosa Ziehau sc->bnx_npoll_txoff = offset; 20784fa38985SSepherosa Ziehau } 20794fa38985SSepherosa Ziehau #endif /* IFPOLL_ENABLE */ 20804fa38985SSepherosa Ziehau 208116b32c4cSSepherosa Ziehau /* 208216b32c4cSSepherosa Ziehau * Allocate interrupt 208316b32c4cSSepherosa Ziehau */ 20840c7da01dSSepherosa Ziehau error = bnx_alloc_intr(sc); 20850c7da01dSSepherosa Ziehau if (error) 208616b32c4cSSepherosa Ziehau goto fail; 208716b32c4cSSepherosa Ziehau 2088329f9016SSepherosa Ziehau /* Setup serializers */ 2089329f9016SSepherosa Ziehau bnx_setup_serialize(sc); 2090329f9016SSepherosa Ziehau 20916c8d8eccSSepherosa Ziehau /* Set default tuneable values. */ 20926c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_ticks = BNX_RX_COAL_TICKS_DEF; 20936c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_ticks = BNX_TX_COAL_TICKS_DEF; 20946c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_bds = BNX_RX_COAL_BDS_DEF; 2095a86cc105SSepherosa Ziehau sc->bnx_rx_coal_bds_poll = sc->bnx_rx_ret_ring[0].bnx_rx_cntmax; 20966c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_bds = BNX_TX_COAL_BDS_DEF; 209727357d84SSepherosa Ziehau sc->bnx_tx_coal_bds_poll = BNX_TX_COAL_BDS_POLL_DEF; 2098306e5498SSepherosa Ziehau sc->bnx_rx_coal_bds_int = BNX_RX_COAL_BDS_INT_DEF; 2099306e5498SSepherosa Ziehau sc->bnx_tx_coal_bds_int = BNX_TX_COAL_BDS_INT_DEF; 21006c8d8eccSSepherosa Ziehau 21016c8d8eccSSepherosa Ziehau /* Set up ifnet structure */ 21026c8d8eccSSepherosa Ziehau ifp->if_softc = sc; 21036c8d8eccSSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 21046c8d8eccSSepherosa Ziehau ifp->if_ioctl = bnx_ioctl; 21056c8d8eccSSepherosa Ziehau ifp->if_start = bnx_start; 210639a8d43aSSepherosa Ziehau #ifdef IFPOLL_ENABLE 210739a8d43aSSepherosa Ziehau ifp->if_npoll = bnx_npoll; 21086c8d8eccSSepherosa Ziehau #endif 21096c8d8eccSSepherosa Ziehau ifp->if_init = bnx_init; 2110329f9016SSepherosa Ziehau ifp->if_serialize = bnx_serialize; 2111329f9016SSepherosa Ziehau ifp->if_deserialize = bnx_deserialize; 2112329f9016SSepherosa Ziehau ifp->if_tryserialize = bnx_tryserialize; 2113329f9016SSepherosa Ziehau #ifdef INVARIANTS 2114329f9016SSepherosa Ziehau ifp->if_serialize_assert = bnx_serialize_assert; 2115329f9016SSepherosa Ziehau #endif 21166c8d8eccSSepherosa Ziehau ifp->if_mtu = ETHERMTU; 21176c8d8eccSSepherosa Ziehau ifp->if_capabilities = IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 21186c8d8eccSSepherosa Ziehau 21196c8d8eccSSepherosa Ziehau ifp->if_capabilities |= IFCAP_HWCSUM; 21206c8d8eccSSepherosa Ziehau ifp->if_hwassist = BNX_CSUM_FEATURES; 212166deb1c1SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TSO) { 212266deb1c1SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO; 212366deb1c1SSepherosa Ziehau ifp->if_hwassist |= CSUM_TSO; 212466deb1c1SSepherosa Ziehau } 2125b19ddf7eSSepherosa Ziehau if (BNX_RSS_ENABLED(sc)) 2126b19ddf7eSSepherosa Ziehau ifp->if_capabilities |= IFCAP_RSS; 21276c8d8eccSSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 21286c8d8eccSSepherosa Ziehau 2129329f9016SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, BGE_TX_RING_CNT - 1); 2130329f9016SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 2131329f9016SSepherosa Ziehau ifq_set_subq_cnt(&ifp->if_snd, sc->bnx_tx_ringcnt); 2132329f9016SSepherosa Ziehau 2133695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt > 1) { 2134695a8586SSepherosa Ziehau ifp->if_mapsubq = ifq_mapsubq_mask; 2135695a8586SSepherosa Ziehau ifq_set_subq_mask(&ifp->if_snd, sc->bnx_tx_ringcnt - 1); 2136695a8586SSepherosa Ziehau } 2137695a8586SSepherosa Ziehau 21386c8d8eccSSepherosa Ziehau /* 21396c8d8eccSSepherosa Ziehau * Figure out what sort of media we have by checking the 21406c8d8eccSSepherosa Ziehau * hardware config word in the first 32k of NIC internal memory, 21416c8d8eccSSepherosa Ziehau * or fall back to examining the EEPROM if necessary. 21426c8d8eccSSepherosa Ziehau * Note: on some BCM5700 cards, this value appears to be unset. 21436c8d8eccSSepherosa Ziehau * If that's the case, we have to rely on identifying the NIC 21446c8d8eccSSepherosa Ziehau * by its PCI subsystem ID, as we do below for the SysKonnect 21456c8d8eccSSepherosa Ziehau * SK-9D41. 21466c8d8eccSSepherosa Ziehau */ 21476c8d8eccSSepherosa Ziehau if (bnx_readmem_ind(sc, BGE_SOFTWARE_GENCOMM_SIG) == BGE_MAGIC_NUMBER) { 21486c8d8eccSSepherosa Ziehau hwcfg = bnx_readmem_ind(sc, BGE_SOFTWARE_GENCOMM_NICCFG); 21496c8d8eccSSepherosa Ziehau } else { 21506c8d8eccSSepherosa Ziehau if (bnx_read_eeprom(sc, (caddr_t)&hwcfg, BGE_EE_HWCFG_OFFSET, 21516c8d8eccSSepherosa Ziehau sizeof(hwcfg))) { 21526c8d8eccSSepherosa Ziehau device_printf(dev, "failed to read EEPROM\n"); 21536c8d8eccSSepherosa Ziehau error = ENXIO; 21546c8d8eccSSepherosa Ziehau goto fail; 21556c8d8eccSSepherosa Ziehau } 21566c8d8eccSSepherosa Ziehau hwcfg = ntohl(hwcfg); 21576c8d8eccSSepherosa Ziehau } 21586c8d8eccSSepherosa Ziehau 21596c8d8eccSSepherosa Ziehau /* The SysKonnect SK-9D41 is a 1000baseSX card. */ 21606c8d8eccSSepherosa Ziehau if (pci_get_subvendor(dev) == PCI_PRODUCT_SCHNEIDERKOCH_SK_9D41 || 21616c8d8eccSSepherosa Ziehau (hwcfg & BGE_HWCFG_MEDIA) == BGE_MEDIA_FIBER) 21626c8d8eccSSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_TBI; 21636c8d8eccSSepherosa Ziehau 21646c8d8eccSSepherosa Ziehau /* Setup MI MODE */ 21656c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_CPMU) 21666c8d8eccSSepherosa Ziehau sc->bnx_mi_mode = BGE_MIMODE_500KHZ_CONST; 21676c8d8eccSSepherosa Ziehau else 21686c8d8eccSSepherosa Ziehau sc->bnx_mi_mode = BGE_MIMODE_BASE; 21696c8d8eccSSepherosa Ziehau 21706c8d8eccSSepherosa Ziehau /* Setup link status update stuffs */ 21716c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 21726c8d8eccSSepherosa Ziehau sc->bnx_link_upd = bnx_tbi_link_upd; 21736c8d8eccSSepherosa Ziehau sc->bnx_link_chg = BGE_MACSTAT_LINK_CHANGED; 21746c8d8eccSSepherosa Ziehau } else if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 21756c8d8eccSSepherosa Ziehau sc->bnx_link_upd = bnx_autopoll_link_upd; 21766c8d8eccSSepherosa Ziehau sc->bnx_link_chg = BGE_MACSTAT_LINK_CHANGED; 21776c8d8eccSSepherosa Ziehau } else { 21786c8d8eccSSepherosa Ziehau sc->bnx_link_upd = bnx_copper_link_upd; 21796c8d8eccSSepherosa Ziehau sc->bnx_link_chg = BGE_MACSTAT_LINK_CHANGED; 21806c8d8eccSSepherosa Ziehau } 21816c8d8eccSSepherosa Ziehau 21826c8d8eccSSepherosa Ziehau /* Set default PHY address */ 21836c8d8eccSSepherosa Ziehau sc->bnx_phyno = 1; 21846c8d8eccSSepherosa Ziehau 21856c8d8eccSSepherosa Ziehau /* 21866c8d8eccSSepherosa Ziehau * PHY address mapping for various devices. 21876c8d8eccSSepherosa Ziehau * 21886c8d8eccSSepherosa Ziehau * | F0 Cu | F0 Sr | F1 Cu | F1 Sr | 21896c8d8eccSSepherosa Ziehau * ---------+-------+-------+-------+-------+ 21906c8d8eccSSepherosa Ziehau * BCM57XX | 1 | X | X | X | 21916c8d8eccSSepherosa Ziehau * BCM5704 | 1 | X | 1 | X | 21926c8d8eccSSepherosa Ziehau * BCM5717 | 1 | 8 | 2 | 9 | 21936c8d8eccSSepherosa Ziehau * BCM5719 | 1 | 8 | 2 | 9 | 21946c8d8eccSSepherosa Ziehau * BCM5720 | 1 | 8 | 2 | 9 | 21956c8d8eccSSepherosa Ziehau * 21966c8d8eccSSepherosa Ziehau * Other addresses may respond but they are not 21976c8d8eccSSepherosa Ziehau * IEEE compliant PHYs and should be ignored. 21986c8d8eccSSepherosa Ziehau */ 219980969639SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) { 22006c8d8eccSSepherosa Ziehau int f; 22016c8d8eccSSepherosa Ziehau 22026c8d8eccSSepherosa Ziehau f = pci_get_function(dev); 22036c8d8eccSSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM5717_A0) { 22046c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_SGDIG_STS) & 22056c8d8eccSSepherosa Ziehau BGE_SGDIGSTS_IS_SERDES) 22066c8d8eccSSepherosa Ziehau sc->bnx_phyno = f + 8; 22076c8d8eccSSepherosa Ziehau else 22086c8d8eccSSepherosa Ziehau sc->bnx_phyno = f + 1; 22096c8d8eccSSepherosa Ziehau } else { 22106c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_CPMU_PHY_STRAP) & 22116c8d8eccSSepherosa Ziehau BGE_CPMU_PHY_STRAP_IS_SERDES) 22126c8d8eccSSepherosa Ziehau sc->bnx_phyno = f + 8; 22136c8d8eccSSepherosa Ziehau else 22146c8d8eccSSepherosa Ziehau sc->bnx_phyno = f + 1; 22156c8d8eccSSepherosa Ziehau } 22166c8d8eccSSepherosa Ziehau } 22176c8d8eccSSepherosa Ziehau 22186c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 22196c8d8eccSSepherosa Ziehau ifmedia_init(&sc->bnx_ifmedia, IFM_IMASK, 22206c8d8eccSSepherosa Ziehau bnx_ifmedia_upd, bnx_ifmedia_sts); 22216c8d8eccSSepherosa Ziehau ifmedia_add(&sc->bnx_ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL); 22226c8d8eccSSepherosa Ziehau ifmedia_add(&sc->bnx_ifmedia, 22236c8d8eccSSepherosa Ziehau IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL); 22246c8d8eccSSepherosa Ziehau ifmedia_add(&sc->bnx_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 22256c8d8eccSSepherosa Ziehau ifmedia_set(&sc->bnx_ifmedia, IFM_ETHER|IFM_AUTO); 22266c8d8eccSSepherosa Ziehau sc->bnx_ifmedia.ifm_media = sc->bnx_ifmedia.ifm_cur->ifm_media; 22276c8d8eccSSepherosa Ziehau } else { 22286c8d8eccSSepherosa Ziehau struct mii_probe_args mii_args; 22296c8d8eccSSepherosa Ziehau 22306c8d8eccSSepherosa Ziehau mii_probe_args_init(&mii_args, bnx_ifmedia_upd, bnx_ifmedia_sts); 22316c8d8eccSSepherosa Ziehau mii_args.mii_probemask = 1 << sc->bnx_phyno; 22326c8d8eccSSepherosa Ziehau mii_args.mii_capmask = capmask; 22336c8d8eccSSepherosa Ziehau mii_args.mii_privtag = MII_PRIVTAG_BRGPHY; 22346c8d8eccSSepherosa Ziehau mii_args.mii_priv = mii_priv; 22356c8d8eccSSepherosa Ziehau 22366c8d8eccSSepherosa Ziehau error = mii_probe(dev, &sc->bnx_miibus, &mii_args); 22376c8d8eccSSepherosa Ziehau if (error) { 22386c8d8eccSSepherosa Ziehau device_printf(dev, "MII without any PHY!\n"); 22396c8d8eccSSepherosa Ziehau goto fail; 22406c8d8eccSSepherosa Ziehau } 22416c8d8eccSSepherosa Ziehau } 22426c8d8eccSSepherosa Ziehau 22436c8d8eccSSepherosa Ziehau /* 22446c8d8eccSSepherosa Ziehau * Create sysctl nodes. 22456c8d8eccSSepherosa Ziehau */ 22466c8d8eccSSepherosa Ziehau sysctl_ctx_init(&sc->bnx_sysctl_ctx); 22476c8d8eccSSepherosa Ziehau sc->bnx_sysctl_tree = SYSCTL_ADD_NODE(&sc->bnx_sysctl_ctx, 22486c8d8eccSSepherosa Ziehau SYSCTL_STATIC_CHILDREN(_hw), 22496c8d8eccSSepherosa Ziehau OID_AUTO, 22506c8d8eccSSepherosa Ziehau device_get_nameunit(dev), 22516c8d8eccSSepherosa Ziehau CTLFLAG_RD, 0, ""); 22526c8d8eccSSepherosa Ziehau if (sc->bnx_sysctl_tree == NULL) { 22536c8d8eccSSepherosa Ziehau device_printf(dev, "can't add sysctl node\n"); 22546c8d8eccSSepherosa Ziehau error = ENXIO; 22556c8d8eccSSepherosa Ziehau goto fail; 22566c8d8eccSSepherosa Ziehau } 22576c8d8eccSSepherosa Ziehau 225893146551SSepherosa Ziehau SYSCTL_ADD_INT(&sc->bnx_sysctl_ctx, 225993146551SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 226093146551SSepherosa Ziehau "rx_rings", CTLFLAG_RD, &sc->bnx_rx_retcnt, 0, "# of RX rings"); 226193146551SSepherosa Ziehau SYSCTL_ADD_INT(&sc->bnx_sysctl_ctx, 226293146551SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 226393146551SSepherosa Ziehau "tx_rings", CTLFLAG_RD, &sc->bnx_tx_ringcnt, 0, "# of TX rings"); 226493146551SSepherosa Ziehau 22656c8d8eccSSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 22666c8d8eccSSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), 22676c8d8eccSSepherosa Ziehau OID_AUTO, "rx_coal_ticks", 22686c8d8eccSSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 22696c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_rx_coal_ticks, "I", 22706c8d8eccSSepherosa Ziehau "Receive coalescing ticks (usec)."); 22716c8d8eccSSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 22726c8d8eccSSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), 22736c8d8eccSSepherosa Ziehau OID_AUTO, "tx_coal_ticks", 22746c8d8eccSSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 22756c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_tx_coal_ticks, "I", 22766c8d8eccSSepherosa Ziehau "Transmit coalescing ticks (usec)."); 22776c8d8eccSSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 22786c8d8eccSSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), 22796c8d8eccSSepherosa Ziehau OID_AUTO, "rx_coal_bds", 22806c8d8eccSSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 22816c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_rx_coal_bds, "I", 22826c8d8eccSSepherosa Ziehau "Receive max coalesced BD count."); 22836c8d8eccSSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 22846c8d8eccSSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), 2285a86cc105SSepherosa Ziehau OID_AUTO, "rx_coal_bds_poll", 2286a86cc105SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 2287a86cc105SSepherosa Ziehau sc, 0, bnx_sysctl_rx_coal_bds_poll, "I", 2288a86cc105SSepherosa Ziehau "Receive max coalesced BD count in polling."); 2289a86cc105SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 2290a86cc105SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), 22916c8d8eccSSepherosa Ziehau OID_AUTO, "tx_coal_bds", 22926c8d8eccSSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 22936c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_tx_coal_bds, "I", 22946c8d8eccSSepherosa Ziehau "Transmit max coalesced BD count."); 229527357d84SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 229627357d84SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), 229727357d84SSepherosa Ziehau OID_AUTO, "tx_coal_bds_poll", 229827357d84SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 229927357d84SSepherosa Ziehau sc, 0, bnx_sysctl_tx_coal_bds_poll, "I", 230027357d84SSepherosa Ziehau "Transmit max coalesced BD count in polling."); 23016c8d8eccSSepherosa Ziehau /* 23026c8d8eccSSepherosa Ziehau * A common design characteristic for many Broadcom 23036c8d8eccSSepherosa Ziehau * client controllers is that they only support a 23046c8d8eccSSepherosa Ziehau * single outstanding DMA read operation on the PCIe 23056c8d8eccSSepherosa Ziehau * bus. This means that it will take twice as long to 23066c8d8eccSSepherosa Ziehau * fetch a TX frame that is split into header and 23076c8d8eccSSepherosa Ziehau * payload buffers as it does to fetch a single, 23086c8d8eccSSepherosa Ziehau * contiguous TX frame (2 reads vs. 1 read). For these 23096c8d8eccSSepherosa Ziehau * controllers, coalescing buffers to reduce the number 23106c8d8eccSSepherosa Ziehau * of memory reads is effective way to get maximum 23116c8d8eccSSepherosa Ziehau * performance(about 940Mbps). Without collapsing TX 23126c8d8eccSSepherosa Ziehau * buffers the maximum TCP bulk transfer performance 23136c8d8eccSSepherosa Ziehau * is about 850Mbps. However forcing coalescing mbufs 23146c8d8eccSSepherosa Ziehau * consumes a lot of CPU cycles, so leave it off by 23156c8d8eccSSepherosa Ziehau * default. 23166c8d8eccSSepherosa Ziehau */ 2317aad4de2bSSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 23186c8d8eccSSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2319aad4de2bSSepherosa Ziehau "force_defrag", CTLTYPE_INT | CTLFLAG_RW, 2320aad4de2bSSepherosa Ziehau sc, 0, bnx_sysctl_force_defrag, "I", 23216c8d8eccSSepherosa Ziehau "Force defragment on TX path"); 23226c8d8eccSSepherosa Ziehau 2323472c99c8SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 2324c9b7f592SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2325472c99c8SSepherosa Ziehau "tx_wreg", CTLTYPE_INT | CTLFLAG_RW, 2326472c99c8SSepherosa Ziehau sc, 0, bnx_sysctl_tx_wreg, "I", 2327c9b7f592SSepherosa Ziehau "# of segments before writing to hardware register"); 2328c9b7f592SSepherosa Ziehau 23296c8d8eccSSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 23306c8d8eccSSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2331841cdf08SSepherosa Ziehau "std_refill", CTLTYPE_INT | CTLFLAG_RW, 2332841cdf08SSepherosa Ziehau sc, 0, bnx_sysctl_std_refill, "I", 2333841cdf08SSepherosa Ziehau "# of packets received before scheduling standard refilling"); 2334841cdf08SSepherosa Ziehau 2335841cdf08SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 2336841cdf08SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 23376c8d8eccSSepherosa Ziehau "rx_coal_bds_int", CTLTYPE_INT | CTLFLAG_RW, 23386c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_rx_coal_bds_int, "I", 23396c8d8eccSSepherosa Ziehau "Receive max coalesced BD count during interrupt."); 23406c8d8eccSSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 23416c8d8eccSSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 23426c8d8eccSSepherosa Ziehau "tx_coal_bds_int", CTLTYPE_INT | CTLFLAG_RW, 23436c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_tx_coal_bds_int, "I", 23446c8d8eccSSepherosa Ziehau "Transmit max coalesced BD count during interrupt."); 23456c8d8eccSSepherosa Ziehau 23464fa38985SSepherosa Ziehau #ifdef IFPOLL_ENABLE 23474fa38985SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_RXTX_BUNDLE) { 23484fa38985SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 23494fa38985SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 23504fa38985SSepherosa Ziehau "npoll_offset", CTLTYPE_INT | CTLFLAG_RW, 23514fa38985SSepherosa Ziehau sc, 0, bnx_sysctl_npoll_offset, "I", 23524fa38985SSepherosa Ziehau "NPOLLING cpu offset"); 23534fa38985SSepherosa Ziehau } else { 23544fa38985SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 23554fa38985SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 23564fa38985SSepherosa Ziehau "npoll_rxoff", CTLTYPE_INT | CTLFLAG_RW, 23574fa38985SSepherosa Ziehau sc, 0, bnx_sysctl_npoll_rxoff, "I", 23584fa38985SSepherosa Ziehau "NPOLLING RX cpu offset"); 23594fa38985SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->bnx_sysctl_ctx, 23604fa38985SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 23614fa38985SSepherosa Ziehau "npoll_txoff", CTLTYPE_INT | CTLFLAG_RW, 23624fa38985SSepherosa Ziehau sc, 0, bnx_sysctl_npoll_txoff, "I", 23634fa38985SSepherosa Ziehau "NPOLLING TX cpu offset"); 23644fa38985SSepherosa Ziehau } 23654fa38985SSepherosa Ziehau #endif 23664fa38985SSepherosa Ziehau 2367695a8586SSepherosa Ziehau #ifdef BNX_RSS_DEBUG 2368695a8586SSepherosa Ziehau SYSCTL_ADD_INT(&sc->bnx_sysctl_ctx, 2369695a8586SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2370695a8586SSepherosa Ziehau "std_refill_mask", CTLFLAG_RD, 2371695a8586SSepherosa Ziehau &sc->bnx_rx_std_ring.bnx_rx_std_refill, 0, ""); 2372695a8586SSepherosa Ziehau SYSCTL_ADD_INT(&sc->bnx_sysctl_ctx, 2373695a8586SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2374625c3ba3SSepherosa Ziehau "std_used", CTLFLAG_RD, 2375625c3ba3SSepherosa Ziehau &sc->bnx_rx_std_ring.bnx_rx_std_used, 0, ""); 2376625c3ba3SSepherosa Ziehau SYSCTL_ADD_INT(&sc->bnx_sysctl_ctx, 2377625c3ba3SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2378695a8586SSepherosa Ziehau "rss_debug", CTLFLAG_RW, &sc->bnx_rss_debug, 0, ""); 2379695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 2380695a8586SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "rx_pkt%d", i); 2381695a8586SSepherosa Ziehau SYSCTL_ADD_ULONG(&sc->bnx_sysctl_ctx, 2382695a8586SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2383695a8586SSepherosa Ziehau desc, CTLFLAG_RW, &sc->bnx_rx_ret_ring[i].bnx_rx_pkt, ""); 2384625c3ba3SSepherosa Ziehau 2385625c3ba3SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "rx_force_sched%d", i); 2386625c3ba3SSepherosa Ziehau SYSCTL_ADD_ULONG(&sc->bnx_sysctl_ctx, 2387625c3ba3SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2388625c3ba3SSepherosa Ziehau desc, CTLFLAG_RW, 2389625c3ba3SSepherosa Ziehau &sc->bnx_rx_ret_ring[i].bnx_rx_force_sched, ""); 2390695a8586SSepherosa Ziehau } 2391695a8586SSepherosa Ziehau #endif 2392695a8586SSepherosa Ziehau #ifdef BNX_TSS_DEBUG 2393695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 2394695a8586SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "tx_pkt%d", i); 2395695a8586SSepherosa Ziehau SYSCTL_ADD_ULONG(&sc->bnx_sysctl_ctx, 2396695a8586SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2397695a8586SSepherosa Ziehau desc, CTLFLAG_RW, &sc->bnx_tx_ring[i].bnx_tx_pkt, ""); 2398695a8586SSepherosa Ziehau } 2399695a8586SSepherosa Ziehau #endif 2400695a8586SSepherosa Ziehau 2401695a8586SSepherosa Ziehau SYSCTL_ADD_ULONG(&sc->bnx_sysctl_ctx, 2402695a8586SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2403695a8586SSepherosa Ziehau "norxbds", CTLFLAG_RW, &sc->bnx_norxbds, ""); 2404695a8586SSepherosa Ziehau 2405695a8586SSepherosa Ziehau SYSCTL_ADD_ULONG(&sc->bnx_sysctl_ctx, 2406695a8586SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 2407695a8586SSepherosa Ziehau "errors", CTLFLAG_RW, &sc->bnx_errors, ""); 2408695a8586SSepherosa Ziehau 240966deb1c1SSepherosa Ziehau #ifdef BNX_TSO_DEBUG 241066deb1c1SSepherosa Ziehau for (i = 0; i < BNX_TSO_NSTATS; ++i) { 241166deb1c1SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "tso%d", i + 1); 241266deb1c1SSepherosa Ziehau SYSCTL_ADD_ULONG(&sc->bnx_sysctl_ctx, 241366deb1c1SSepherosa Ziehau SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, 241466deb1c1SSepherosa Ziehau desc, CTLFLAG_RW, &sc->bnx_tsosegs[i], ""); 241566deb1c1SSepherosa Ziehau } 241666deb1c1SSepherosa Ziehau #endif 241766deb1c1SSepherosa Ziehau 24186c8d8eccSSepherosa Ziehau /* 24196c8d8eccSSepherosa Ziehau * Call MI attach routine. 24206c8d8eccSSepherosa Ziehau */ 2421329f9016SSepherosa Ziehau ether_ifattach(ifp, ether_addr, NULL); 24226c8d8eccSSepherosa Ziehau 2423329f9016SSepherosa Ziehau /* Setup TX rings and subqueues */ 2424329f9016SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 2425329f9016SSepherosa Ziehau struct ifaltq_subque *ifsq = ifq_get_subq(&ifp->if_snd, i); 2426329f9016SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 2427329f9016SSepherosa Ziehau 2428329f9016SSepherosa Ziehau ifsq_set_cpuid(ifsq, txr->bnx_tx_cpuid); 2429329f9016SSepherosa Ziehau ifsq_set_hw_serialize(ifsq, &txr->bnx_tx_serialize); 2430329f9016SSepherosa Ziehau ifsq_set_priv(ifsq, txr); 24313397dea6SSepherosa Ziehau txr->bnx_ifsq = ifsq; 2432329f9016SSepherosa Ziehau 24333397dea6SSepherosa Ziehau ifsq_watchdog_init(&txr->bnx_tx_watchdog, ifsq, bnx_watchdog); 2434695a8586SSepherosa Ziehau 2435695a8586SSepherosa Ziehau if (bootverbose) { 2436695a8586SSepherosa Ziehau device_printf(dev, "txr %d -> cpu%d\n", i, 2437695a8586SSepherosa Ziehau txr->bnx_tx_cpuid); 2438695a8586SSepherosa Ziehau } 2439329f9016SSepherosa Ziehau } 24404c77af2dSSepherosa Ziehau 24410c7da01dSSepherosa Ziehau error = bnx_setup_intr(sc); 24426c8d8eccSSepherosa Ziehau if (error) { 24436c8d8eccSSepherosa Ziehau ether_ifdetach(ifp); 24446c8d8eccSSepherosa Ziehau goto fail; 24456c8d8eccSSepherosa Ziehau } 24467dbaa833SSepherosa Ziehau bnx_set_tick_cpuid(sc, FALSE); 24478ca0f604SSepherosa Ziehau 2448841cdf08SSepherosa Ziehau /* 2449841cdf08SSepherosa Ziehau * Create RX standard ring refilling thread 2450841cdf08SSepherosa Ziehau */ 2451841cdf08SSepherosa Ziehau std_cpuid_def = device_get_unit(dev) % ncpus; 2452841cdf08SSepherosa Ziehau std_cpuid = device_getenv_int(dev, "std.cpuid", std_cpuid_def); 2453841cdf08SSepherosa Ziehau if (std_cpuid < 0 || std_cpuid >= ncpus) { 2454841cdf08SSepherosa Ziehau device_printf(dev, "invalid std.cpuid %d, use %d\n", 2455841cdf08SSepherosa Ziehau std_cpuid, std_cpuid_def); 2456841cdf08SSepherosa Ziehau std_cpuid = std_cpuid_def; 2457841cdf08SSepherosa Ziehau } 2458841cdf08SSepherosa Ziehau 2459841cdf08SSepherosa Ziehau std = &sc->bnx_rx_std_ring; 2460841cdf08SSepherosa Ziehau lwkt_create(bnx_rx_std_refill_ithread, std, NULL, 2461841cdf08SSepherosa Ziehau &std->bnx_rx_std_ithread, TDF_NOSTART | TDF_INTTHREAD, std_cpuid, 2462841cdf08SSepherosa Ziehau "%s std", device_get_nameunit(dev)); 2463841cdf08SSepherosa Ziehau lwkt_setpri(&std->bnx_rx_std_ithread, TDPRI_INT_MED); 2464841cdf08SSepherosa Ziehau std->bnx_rx_std_ithread.td_preemptable = lwkt_preempt; 2465841cdf08SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_STD_THREAD; 2466841cdf08SSepherosa Ziehau 24676c8d8eccSSepherosa Ziehau return(0); 24686c8d8eccSSepherosa Ziehau fail: 24696c8d8eccSSepherosa Ziehau bnx_detach(dev); 24706c8d8eccSSepherosa Ziehau return(error); 24716c8d8eccSSepherosa Ziehau } 24726c8d8eccSSepherosa Ziehau 24736c8d8eccSSepherosa Ziehau static int 24746c8d8eccSSepherosa Ziehau bnx_detach(device_t dev) 24756c8d8eccSSepherosa Ziehau { 24766c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 24776c8d8eccSSepherosa Ziehau 24786c8d8eccSSepherosa Ziehau if (device_is_attached(dev)) { 24796c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 24806c8d8eccSSepherosa Ziehau 2481329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 24826c8d8eccSSepherosa Ziehau bnx_stop(sc); 24836c8d8eccSSepherosa Ziehau bnx_reset(sc); 2484f33ac8a4SSepherosa Ziehau bnx_teardown_intr(sc, sc->bnx_intr_cnt); 2485329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 24866c8d8eccSSepherosa Ziehau 24876c8d8eccSSepherosa Ziehau ether_ifdetach(ifp); 24886c8d8eccSSepherosa Ziehau } 24896c8d8eccSSepherosa Ziehau 2490841cdf08SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_STD_THREAD) { 2491841cdf08SSepherosa Ziehau struct bnx_rx_std_ring *std = &sc->bnx_rx_std_ring; 2492841cdf08SSepherosa Ziehau 2493841cdf08SSepherosa Ziehau tsleep_interlock(std, 0); 2494695a8586SSepherosa Ziehau 2495695a8586SSepherosa Ziehau if (std->bnx_rx_std_ithread.td_gd == mycpu) { 2496695a8586SSepherosa Ziehau bnx_rx_std_refill_stop(std); 2497695a8586SSepherosa Ziehau } else { 2498695a8586SSepherosa Ziehau lwkt_send_ipiq(std->bnx_rx_std_ithread.td_gd, 2499695a8586SSepherosa Ziehau bnx_rx_std_refill_stop, std); 2500695a8586SSepherosa Ziehau } 2501695a8586SSepherosa Ziehau 2502841cdf08SSepherosa Ziehau tsleep(std, PINTERLOCKED, "bnx_detach", 0); 2503841cdf08SSepherosa Ziehau if (bootverbose) 2504841cdf08SSepherosa Ziehau device_printf(dev, "RX std ithread exited\n"); 2505695a8586SSepherosa Ziehau 2506695a8586SSepherosa Ziehau lwkt_synchronize_ipiqs("bnx_detach_ipiq"); 2507841cdf08SSepherosa Ziehau } 2508841cdf08SSepherosa Ziehau 25096c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) 25106c8d8eccSSepherosa Ziehau ifmedia_removeall(&sc->bnx_ifmedia); 25116c8d8eccSSepherosa Ziehau if (sc->bnx_miibus) 25126c8d8eccSSepherosa Ziehau device_delete_child(dev, sc->bnx_miibus); 25136c8d8eccSSepherosa Ziehau bus_generic_detach(dev); 25146c8d8eccSSepherosa Ziehau 25150c7da01dSSepherosa Ziehau bnx_free_intr(sc); 25166c8d8eccSSepherosa Ziehau 2517695a8586SSepherosa Ziehau if (sc->bnx_msix_mem_res != NULL) { 2518695a8586SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->bnx_msix_mem_rid, 2519695a8586SSepherosa Ziehau sc->bnx_msix_mem_res); 2520695a8586SSepherosa Ziehau } 25216c8d8eccSSepherosa Ziehau if (sc->bnx_res != NULL) { 25226c8d8eccSSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, 25236c8d8eccSSepherosa Ziehau BGE_PCI_BAR0, sc->bnx_res); 25246c8d8eccSSepherosa Ziehau } 25256c8d8eccSSepherosa Ziehau 25266c8d8eccSSepherosa Ziehau if (sc->bnx_sysctl_tree != NULL) 25276c8d8eccSSepherosa Ziehau sysctl_ctx_free(&sc->bnx_sysctl_ctx); 25286c8d8eccSSepherosa Ziehau 25296c8d8eccSSepherosa Ziehau bnx_dma_free(sc); 25306c8d8eccSSepherosa Ziehau 2531329f9016SSepherosa Ziehau if (sc->bnx_serialize != NULL) 2532329f9016SSepherosa Ziehau kfree(sc->bnx_serialize, M_DEVBUF); 2533329f9016SSepherosa Ziehau 25346c8d8eccSSepherosa Ziehau return 0; 25356c8d8eccSSepherosa Ziehau } 25366c8d8eccSSepherosa Ziehau 25376c8d8eccSSepherosa Ziehau static void 25386c8d8eccSSepherosa Ziehau bnx_reset(struct bnx_softc *sc) 25396c8d8eccSSepherosa Ziehau { 25406c8d8eccSSepherosa Ziehau device_t dev; 25416c8d8eccSSepherosa Ziehau uint32_t cachesize, command, pcistate, reset; 25426c8d8eccSSepherosa Ziehau void (*write_op)(struct bnx_softc *, uint32_t, uint32_t); 25436c8d8eccSSepherosa Ziehau int i, val = 0; 25446c8d8eccSSepherosa Ziehau uint16_t devctl; 25456c8d8eccSSepherosa Ziehau 25466c8d8eccSSepherosa Ziehau dev = sc->bnx_dev; 25476c8d8eccSSepherosa Ziehau 25486c8d8eccSSepherosa Ziehau write_op = bnx_writemem_direct; 25496c8d8eccSSepherosa Ziehau 25506c8d8eccSSepherosa Ziehau /* Save some important PCI state. */ 25516c8d8eccSSepherosa Ziehau cachesize = pci_read_config(dev, BGE_PCI_CACHESZ, 4); 25526c8d8eccSSepherosa Ziehau command = pci_read_config(dev, BGE_PCI_CMD, 4); 25536c8d8eccSSepherosa Ziehau pcistate = pci_read_config(dev, BGE_PCI_PCISTATE, 4); 25546c8d8eccSSepherosa Ziehau 25556c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MISC_CTL, 25566c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_INDIRECT_ACCESS|BGE_PCIMISCCTL_MASK_PCI_INTR| 25576c8d8eccSSepherosa Ziehau BGE_HIF_SWAP_OPTIONS|BGE_PCIMISCCTL_PCISTATE_RW| 25586c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_TAGGED_STATUS, 4); 25596c8d8eccSSepherosa Ziehau 25606c8d8eccSSepherosa Ziehau /* Disable fastboot on controllers that support it. */ 25616c8d8eccSSepherosa Ziehau if (bootverbose) 25626c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "Disabling fastboot\n"); 25636c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_FASTBOOT_PC, 0x0); 25646c8d8eccSSepherosa Ziehau 25656c8d8eccSSepherosa Ziehau /* 25666c8d8eccSSepherosa Ziehau * Write the magic number to SRAM at offset 0xB50. 25676c8d8eccSSepherosa Ziehau * When firmware finishes its initialization it will 25686c8d8eccSSepherosa Ziehau * write ~BGE_MAGIC_NUMBER to the same location. 25696c8d8eccSSepherosa Ziehau */ 25706c8d8eccSSepherosa Ziehau bnx_writemem_ind(sc, BGE_SOFTWARE_GENCOMM, BGE_MAGIC_NUMBER); 25716c8d8eccSSepherosa Ziehau 25726c8d8eccSSepherosa Ziehau reset = BGE_MISCCFG_RESET_CORE_CLOCKS|(65<<1); 25736c8d8eccSSepherosa Ziehau 25746c8d8eccSSepherosa Ziehau /* XXX: Broadcom Linux driver. */ 25756c8d8eccSSepherosa Ziehau /* Force PCI-E 1.0a mode */ 25763730a14dSSepherosa Ziehau if (!BNX_IS_57765_PLUS(sc) && 25776c8d8eccSSepherosa Ziehau CSR_READ_4(sc, BGE_PCIE_PHY_TSTCTL) == 25786c8d8eccSSepherosa Ziehau (BGE_PCIE_PHY_TSTCTL_PSCRAM | 25796c8d8eccSSepherosa Ziehau BGE_PCIE_PHY_TSTCTL_PCIE10)) { 25806c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_PCIE_PHY_TSTCTL, 25816c8d8eccSSepherosa Ziehau BGE_PCIE_PHY_TSTCTL_PSCRAM); 25826c8d8eccSSepherosa Ziehau } 25836c8d8eccSSepherosa Ziehau if (sc->bnx_chipid != BGE_CHIPID_BCM5750_A0) { 25846c8d8eccSSepherosa Ziehau /* Prevent PCIE link training during global reset */ 25856c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MISC_CFG, (1<<29)); 25866c8d8eccSSepherosa Ziehau reset |= (1<<29); 25876c8d8eccSSepherosa Ziehau } 25886c8d8eccSSepherosa Ziehau 25896c8d8eccSSepherosa Ziehau /* 25906c8d8eccSSepherosa Ziehau * Set GPHY Power Down Override to leave GPHY 25916c8d8eccSSepherosa Ziehau * powered up in D0 uninitialized. 25926c8d8eccSSepherosa Ziehau */ 25936c8d8eccSSepherosa Ziehau if ((sc->bnx_flags & BNX_FLAG_CPMU) == 0) 25946c8d8eccSSepherosa Ziehau reset |= BGE_MISCCFG_GPHY_PD_OVERRIDE; 25956c8d8eccSSepherosa Ziehau 25966c8d8eccSSepherosa Ziehau /* Issue global reset */ 25976c8d8eccSSepherosa Ziehau write_op(sc, BGE_MISC_CFG, reset); 25986c8d8eccSSepherosa Ziehau 25996c8d8eccSSepherosa Ziehau DELAY(1000); 26006c8d8eccSSepherosa Ziehau 26016c8d8eccSSepherosa Ziehau /* XXX: Broadcom Linux driver. */ 26026c8d8eccSSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM5750_A0) { 26036c8d8eccSSepherosa Ziehau uint32_t v; 26046c8d8eccSSepherosa Ziehau 26056c8d8eccSSepherosa Ziehau DELAY(500000); /* wait for link training to complete */ 26066c8d8eccSSepherosa Ziehau v = pci_read_config(dev, 0xc4, 4); 26076c8d8eccSSepherosa Ziehau pci_write_config(dev, 0xc4, v | (1<<15), 4); 26086c8d8eccSSepherosa Ziehau } 26096c8d8eccSSepherosa Ziehau 26106c8d8eccSSepherosa Ziehau devctl = pci_read_config(dev, sc->bnx_pciecap + PCIER_DEVCTRL, 2); 26116c8d8eccSSepherosa Ziehau 26126c8d8eccSSepherosa Ziehau /* Disable no snoop and disable relaxed ordering. */ 26136c8d8eccSSepherosa Ziehau devctl &= ~(PCIEM_DEVCTL_RELAX_ORDER | PCIEM_DEVCTL_NOSNOOP); 26146c8d8eccSSepherosa Ziehau 26156c8d8eccSSepherosa Ziehau /* Old PCI-E chips only support 128 bytes Max PayLoad Size. */ 26166c8d8eccSSepherosa Ziehau if ((sc->bnx_flags & BNX_FLAG_CPMU) == 0) { 26176c8d8eccSSepherosa Ziehau devctl &= ~PCIEM_DEVCTL_MAX_PAYLOAD_MASK; 26186c8d8eccSSepherosa Ziehau devctl |= PCIEM_DEVCTL_MAX_PAYLOAD_128; 26196c8d8eccSSepherosa Ziehau } 26206c8d8eccSSepherosa Ziehau 26216c8d8eccSSepherosa Ziehau pci_write_config(dev, sc->bnx_pciecap + PCIER_DEVCTRL, 26226c8d8eccSSepherosa Ziehau devctl, 2); 26236c8d8eccSSepherosa Ziehau 26246c8d8eccSSepherosa Ziehau /* Clear error status. */ 26256c8d8eccSSepherosa Ziehau pci_write_config(dev, sc->bnx_pciecap + PCIER_DEVSTS, 26266c8d8eccSSepherosa Ziehau PCIEM_DEVSTS_CORR_ERR | 26276c8d8eccSSepherosa Ziehau PCIEM_DEVSTS_NFATAL_ERR | 26286c8d8eccSSepherosa Ziehau PCIEM_DEVSTS_FATAL_ERR | 26296c8d8eccSSepherosa Ziehau PCIEM_DEVSTS_UNSUPP_REQ, 2); 26306c8d8eccSSepherosa Ziehau 26316c8d8eccSSepherosa Ziehau /* Reset some of the PCI state that got zapped by reset */ 26326c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MISC_CTL, 26336c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_INDIRECT_ACCESS|BGE_PCIMISCCTL_MASK_PCI_INTR| 26346c8d8eccSSepherosa Ziehau BGE_HIF_SWAP_OPTIONS|BGE_PCIMISCCTL_PCISTATE_RW| 26356c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_TAGGED_STATUS, 4); 26366c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_CACHESZ, cachesize, 4); 26376c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_CMD, command, 4); 26386c8d8eccSSepherosa Ziehau write_op(sc, BGE_MISC_CFG, (65 << 1)); 26396c8d8eccSSepherosa Ziehau 26406c8d8eccSSepherosa Ziehau /* Enable memory arbiter */ 26416c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE); 26426c8d8eccSSepherosa Ziehau 26436c8d8eccSSepherosa Ziehau /* 26446c8d8eccSSepherosa Ziehau * Poll until we see the 1's complement of the magic number. 2645ddd93a5cSSepherosa Ziehau * This indicates that the firmware initialization is complete. 26466c8d8eccSSepherosa Ziehau */ 26476c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_FIRMWARE_TIMEOUT; i++) { 26486c8d8eccSSepherosa Ziehau val = bnx_readmem_ind(sc, BGE_SOFTWARE_GENCOMM); 26496c8d8eccSSepherosa Ziehau if (val == ~BGE_MAGIC_NUMBER) 26506c8d8eccSSepherosa Ziehau break; 26516c8d8eccSSepherosa Ziehau DELAY(10); 26526c8d8eccSSepherosa Ziehau } 26536c8d8eccSSepherosa Ziehau if (i == BNX_FIRMWARE_TIMEOUT) { 26546c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "firmware handshake " 26556c8d8eccSSepherosa Ziehau "timed out, found 0x%08x\n", val); 26566c8d8eccSSepherosa Ziehau } 26576c8d8eccSSepherosa Ziehau 26586c8d8eccSSepherosa Ziehau /* BCM57765 A0 needs additional time before accessing. */ 26596c8d8eccSSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM57765_A0) 26606c8d8eccSSepherosa Ziehau DELAY(10 * 1000); 26616c8d8eccSSepherosa Ziehau 26626c8d8eccSSepherosa Ziehau /* 26636c8d8eccSSepherosa Ziehau * XXX Wait for the value of the PCISTATE register to 26646c8d8eccSSepherosa Ziehau * return to its original pre-reset state. This is a 26656c8d8eccSSepherosa Ziehau * fairly good indicator of reset completion. If we don't 26666c8d8eccSSepherosa Ziehau * wait for the reset to fully complete, trying to read 26676c8d8eccSSepherosa Ziehau * from the device's non-PCI registers may yield garbage 26686c8d8eccSSepherosa Ziehau * results. 26696c8d8eccSSepherosa Ziehau */ 26706c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 26716c8d8eccSSepherosa Ziehau if (pci_read_config(dev, BGE_PCI_PCISTATE, 4) == pcistate) 26726c8d8eccSSepherosa Ziehau break; 26736c8d8eccSSepherosa Ziehau DELAY(10); 26746c8d8eccSSepherosa Ziehau } 26756c8d8eccSSepherosa Ziehau 26766c8d8eccSSepherosa Ziehau /* Fix up byte swapping */ 26776c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, bnx_dma_swap_options(sc)); 26786c8d8eccSSepherosa Ziehau 26796c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_MODE, 0); 26806c8d8eccSSepherosa Ziehau 26816c8d8eccSSepherosa Ziehau /* 26826c8d8eccSSepherosa Ziehau * The 5704 in TBI mode apparently needs some special 26836c8d8eccSSepherosa Ziehau * adjustment to insure the SERDES drive level is set 26846c8d8eccSSepherosa Ziehau * to 1.2V. 26856c8d8eccSSepherosa Ziehau */ 26866c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5704 && 26876c8d8eccSSepherosa Ziehau (sc->bnx_flags & BNX_FLAG_TBI)) { 26886c8d8eccSSepherosa Ziehau uint32_t serdescfg; 26896c8d8eccSSepherosa Ziehau 26906c8d8eccSSepherosa Ziehau serdescfg = CSR_READ_4(sc, BGE_SERDES_CFG); 26916c8d8eccSSepherosa Ziehau serdescfg = (serdescfg & ~0xFFF) | 0x880; 26926c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SERDES_CFG, serdescfg); 26936c8d8eccSSepherosa Ziehau } 26946c8d8eccSSepherosa Ziehau 26957892075dSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, 26967892075dSSepherosa Ziehau sc->bnx_mi_mode & ~BGE_MIMODE_AUTOPOLL); 26977892075dSSepherosa Ziehau DELAY(80); 26987892075dSSepherosa Ziehau 26996c8d8eccSSepherosa Ziehau /* XXX: Broadcom Linux driver. */ 27003730a14dSSepherosa Ziehau if (!BNX_IS_57765_PLUS(sc)) { 27016c8d8eccSSepherosa Ziehau uint32_t v; 27026c8d8eccSSepherosa Ziehau 27036c8d8eccSSepherosa Ziehau /* Enable Data FIFO protection. */ 2704f1f34fc4SSepherosa Ziehau v = CSR_READ_4(sc, BGE_PCIE_TLDLPL_PORT); 2705f1f34fc4SSepherosa Ziehau CSR_WRITE_4(sc, BGE_PCIE_TLDLPL_PORT, v | (1 << 25)); 27066c8d8eccSSepherosa Ziehau } 27076c8d8eccSSepherosa Ziehau 27086c8d8eccSSepherosa Ziehau DELAY(10000); 27096c8d8eccSSepherosa Ziehau 27106c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720) { 27116c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_CPMU_CLCK_ORIDE, 27126c8d8eccSSepherosa Ziehau CPMU_CLCK_ORIDE_MAC_ORIDE_EN); 27136c8d8eccSSepherosa Ziehau } 27146c8d8eccSSepherosa Ziehau } 27156c8d8eccSSepherosa Ziehau 27166c8d8eccSSepherosa Ziehau /* 27176c8d8eccSSepherosa Ziehau * Frame reception handling. This is called if there's a frame 27186c8d8eccSSepherosa Ziehau * on the receive return list. 27196c8d8eccSSepherosa Ziehau * 27206c8d8eccSSepherosa Ziehau * Note: we have to be able to handle two possibilities here: 27216c8d8eccSSepherosa Ziehau * 1) the frame is from the jumbo recieve ring 27226c8d8eccSSepherosa Ziehau * 2) the frame is from the standard receive ring 27236c8d8eccSSepherosa Ziehau */ 27246c8d8eccSSepherosa Ziehau 27256c8d8eccSSepherosa Ziehau static void 2726beedf5beSSepherosa Ziehau bnx_rxeof(struct bnx_rx_ret_ring *ret, uint16_t rx_prod, int count) 27276c8d8eccSSepherosa Ziehau { 2728beedf5beSSepherosa Ziehau struct bnx_softc *sc = ret->bnx_sc; 2729beedf5beSSepherosa Ziehau struct bnx_rx_std_ring *std = ret->bnx_std; 2730beedf5beSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2731625c3ba3SSepherosa Ziehau int std_used = 0; 27326c8d8eccSSepherosa Ziehau 2733beedf5beSSepherosa Ziehau while (ret->bnx_rx_saved_considx != rx_prod && count != 0) { 2734b19ddf7eSSepherosa Ziehau struct pktinfo pi0, *pi = NULL; 27356c8d8eccSSepherosa Ziehau struct bge_rx_bd *cur_rx; 2736841cdf08SSepherosa Ziehau struct bnx_rx_buf *rb; 27376c8d8eccSSepherosa Ziehau uint32_t rxidx; 27386c8d8eccSSepherosa Ziehau struct mbuf *m = NULL; 27396c8d8eccSSepherosa Ziehau uint16_t vlan_tag = 0; 27406c8d8eccSSepherosa Ziehau int have_tag = 0; 27416c8d8eccSSepherosa Ziehau 274297381780SSepherosa Ziehau --count; 274397381780SSepherosa Ziehau 2744beedf5beSSepherosa Ziehau cur_rx = &ret->bnx_rx_ret_ring[ret->bnx_rx_saved_considx]; 27456c8d8eccSSepherosa Ziehau 27466c8d8eccSSepherosa Ziehau rxidx = cur_rx->bge_idx; 2747695a8586SSepherosa Ziehau KKASSERT(rxidx < BGE_STD_RX_RING_CNT); 2748695a8586SSepherosa Ziehau 2749beedf5beSSepherosa Ziehau BNX_INC(ret->bnx_rx_saved_considx, BNX_RETURN_RING_CNT); 2750695a8586SSepherosa Ziehau #ifdef BNX_RSS_DEBUG 2751695a8586SSepherosa Ziehau ret->bnx_rx_pkt++; 2752695a8586SSepherosa Ziehau #endif 27536c8d8eccSSepherosa Ziehau 27546c8d8eccSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_VLAN_TAG) { 27556c8d8eccSSepherosa Ziehau have_tag = 1; 27566c8d8eccSSepherosa Ziehau vlan_tag = cur_rx->bge_vlan_tag; 27576c8d8eccSSepherosa Ziehau } 27586c8d8eccSSepherosa Ziehau 2759625c3ba3SSepherosa Ziehau if (ret->bnx_rx_cnt >= ret->bnx_rx_cntmax) { 2760625c3ba3SSepherosa Ziehau atomic_add_int(&std->bnx_rx_std_used, std_used); 2761625c3ba3SSepherosa Ziehau std_used = 0; 2762625c3ba3SSepherosa Ziehau 2763695a8586SSepherosa Ziehau bnx_rx_std_refill_sched(ret, std); 2764625c3ba3SSepherosa Ziehau } 2765841cdf08SSepherosa Ziehau ret->bnx_rx_cnt++; 2766625c3ba3SSepherosa Ziehau ++std_used; 27676c8d8eccSSepherosa Ziehau 2768841cdf08SSepherosa Ziehau rb = &std->bnx_rx_std_buf[rxidx]; 2769841cdf08SSepherosa Ziehau m = rb->bnx_rx_mbuf; 27706c8d8eccSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_ERROR) { 2771d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 2772841cdf08SSepherosa Ziehau cpu_sfence(); 2773841cdf08SSepherosa Ziehau rb->bnx_rx_refilled = 1; 27746c8d8eccSSepherosa Ziehau continue; 27756c8d8eccSSepherosa Ziehau } 2776841cdf08SSepherosa Ziehau if (bnx_newbuf_std(ret, rxidx, 0)) { 2777d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 27786c8d8eccSSepherosa Ziehau continue; 27796c8d8eccSSepherosa Ziehau } 27806c8d8eccSSepherosa Ziehau 2781d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 27826c8d8eccSSepherosa Ziehau m->m_pkthdr.len = m->m_len = cur_rx->bge_len - ETHER_CRC_LEN; 27836c8d8eccSSepherosa Ziehau m->m_pkthdr.rcvif = ifp; 27846c8d8eccSSepherosa Ziehau 27856c8d8eccSSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 27866c8d8eccSSepherosa Ziehau (cur_rx->bge_flags & BGE_RXBDFLAG_IPV6) == 0) { 27876c8d8eccSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_IP_CSUM) { 27886c8d8eccSSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 27896c8d8eccSSepherosa Ziehau if ((cur_rx->bge_error_flag & 27906c8d8eccSSepherosa Ziehau BGE_RXERRFLAG_IP_CSUM_NOK) == 0) 27916c8d8eccSSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 27926c8d8eccSSepherosa Ziehau } 27936c8d8eccSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_TCP_UDP_CSUM) { 27946c8d8eccSSepherosa Ziehau m->m_pkthdr.csum_data = 27956c8d8eccSSepherosa Ziehau cur_rx->bge_tcp_udp_csum; 27966c8d8eccSSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | 27976c8d8eccSSepherosa Ziehau CSUM_PSEUDO_HDR; 27986c8d8eccSSepherosa Ziehau } 27996c8d8eccSSepherosa Ziehau } 2800b19ddf7eSSepherosa Ziehau if (ifp->if_capenable & IFCAP_RSS) { 2801b19ddf7eSSepherosa Ziehau pi = bnx_rss_info(&pi0, cur_rx); 2802b19ddf7eSSepherosa Ziehau if (pi != NULL && 2803b19ddf7eSSepherosa Ziehau (cur_rx->bge_flags & BGE_RXBDFLAG_RSS_HASH)) { 2804b19ddf7eSSepherosa Ziehau m->m_flags |= M_HASH; 2805b19ddf7eSSepherosa Ziehau m->m_pkthdr.hash = 2806b19ddf7eSSepherosa Ziehau toeplitz_hash(cur_rx->bge_hash); 2807b19ddf7eSSepherosa Ziehau } 2808b19ddf7eSSepherosa Ziehau } 28096c8d8eccSSepherosa Ziehau 28106c8d8eccSSepherosa Ziehau /* 28116c8d8eccSSepherosa Ziehau * If we received a packet with a vlan tag, pass it 28126c8d8eccSSepherosa Ziehau * to vlan_input() instead of ether_input(). 28136c8d8eccSSepherosa Ziehau */ 28146c8d8eccSSepherosa Ziehau if (have_tag) { 28156c8d8eccSSepherosa Ziehau m->m_flags |= M_VLANTAG; 28166c8d8eccSSepherosa Ziehau m->m_pkthdr.ether_vlantag = vlan_tag; 28176c8d8eccSSepherosa Ziehau } 2818b19ddf7eSSepherosa Ziehau ether_input_pkt(ifp, m, pi); 28196c8d8eccSSepherosa Ziehau } 2820ac2936fdSSepherosa Ziehau bnx_writembx(sc, ret->bnx_rx_mbx, ret->bnx_rx_saved_considx); 2821695a8586SSepherosa Ziehau 2822625c3ba3SSepherosa Ziehau if (std_used > 0) { 2823625c3ba3SSepherosa Ziehau int cur_std_used; 2824625c3ba3SSepherosa Ziehau 2825625c3ba3SSepherosa Ziehau cur_std_used = atomic_fetchadd_int(&std->bnx_rx_std_used, 2826625c3ba3SSepherosa Ziehau std_used); 2827625c3ba3SSepherosa Ziehau if (cur_std_used + std_used >= (BGE_STD_RX_RING_CNT / 2)) { 2828625c3ba3SSepherosa Ziehau #ifdef BNX_RSS_DEBUG 2829625c3ba3SSepherosa Ziehau ret->bnx_rx_force_sched++; 2830625c3ba3SSepherosa Ziehau #endif 2831695a8586SSepherosa Ziehau bnx_rx_std_refill_sched(ret, std); 28326c8d8eccSSepherosa Ziehau } 2833625c3ba3SSepherosa Ziehau } 2834625c3ba3SSepherosa Ziehau } 28356c8d8eccSSepherosa Ziehau 28366c8d8eccSSepherosa Ziehau static void 283733a04907SSepherosa Ziehau bnx_txeof(struct bnx_tx_ring *txr, uint16_t tx_cons) 28386c8d8eccSSepherosa Ziehau { 283933a04907SSepherosa Ziehau struct ifnet *ifp = &txr->bnx_sc->arpcom.ac_if; 28406c8d8eccSSepherosa Ziehau 28416c8d8eccSSepherosa Ziehau /* 28426c8d8eccSSepherosa Ziehau * Go through our tx ring and free mbufs for those 28436c8d8eccSSepherosa Ziehau * frames that have been sent. 28446c8d8eccSSepherosa Ziehau */ 284533a04907SSepherosa Ziehau while (txr->bnx_tx_saved_considx != tx_cons) { 2846fa4b1067SSepherosa Ziehau struct bnx_tx_buf *buf; 28476c8d8eccSSepherosa Ziehau uint32_t idx = 0; 28486c8d8eccSSepherosa Ziehau 284933a04907SSepherosa Ziehau idx = txr->bnx_tx_saved_considx; 2850fa4b1067SSepherosa Ziehau buf = &txr->bnx_tx_buf[idx]; 2851fa4b1067SSepherosa Ziehau if (buf->bnx_tx_mbuf != NULL) { 2852d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 2853695a8586SSepherosa Ziehau #ifdef BNX_TSS_DEBUG 2854695a8586SSepherosa Ziehau txr->bnx_tx_pkt++; 2855695a8586SSepherosa Ziehau #endif 285633a04907SSepherosa Ziehau bus_dmamap_unload(txr->bnx_tx_mtag, 2857fa4b1067SSepherosa Ziehau buf->bnx_tx_dmamap); 2858fa4b1067SSepherosa Ziehau m_freem(buf->bnx_tx_mbuf); 2859fa4b1067SSepherosa Ziehau buf->bnx_tx_mbuf = NULL; 28606c8d8eccSSepherosa Ziehau } 2861fa639b88SSepherosa Ziehau txr->bnx_tx_cnt--; 286233a04907SSepherosa Ziehau BNX_INC(txr->bnx_tx_saved_considx, BGE_TX_RING_CNT); 28636c8d8eccSSepherosa Ziehau } 28646c8d8eccSSepherosa Ziehau 2865fa639b88SSepherosa Ziehau if ((BGE_TX_RING_CNT - txr->bnx_tx_cnt) >= 28666c8d8eccSSepherosa Ziehau (BNX_NSEG_RSVD + BNX_NSEG_SPARE)) 28673397dea6SSepherosa Ziehau ifsq_clr_oactive(txr->bnx_ifsq); 28686c8d8eccSSepherosa Ziehau 2869fa639b88SSepherosa Ziehau if (txr->bnx_tx_cnt == 0) 28703397dea6SSepherosa Ziehau txr->bnx_tx_watchdog.wd_timer = 0; 28716c8d8eccSSepherosa Ziehau 28723397dea6SSepherosa Ziehau if (!ifsq_is_empty(txr->bnx_ifsq)) 28733397dea6SSepherosa Ziehau ifsq_devstart(txr->bnx_ifsq); 28746c8d8eccSSepherosa Ziehau } 28756c8d8eccSSepherosa Ziehau 287624e16e4bSSepherosa Ziehau static int 2877695a8586SSepherosa Ziehau bnx_handle_status(struct bnx_softc *sc) 2878695a8586SSepherosa Ziehau { 2879695a8586SSepherosa Ziehau uint32_t status; 288024e16e4bSSepherosa Ziehau int handle = 0; 2881695a8586SSepherosa Ziehau 2882695a8586SSepherosa Ziehau status = *sc->bnx_hw_status; 2883695a8586SSepherosa Ziehau 2884695a8586SSepherosa Ziehau if (status & BGE_STATFLAG_ERROR) { 2885695a8586SSepherosa Ziehau uint32_t val; 2886695a8586SSepherosa Ziehau int reset = 0; 2887695a8586SSepherosa Ziehau 2888695a8586SSepherosa Ziehau sc->bnx_errors++; 2889695a8586SSepherosa Ziehau 2890695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_FLOW_ATTN); 2891695a8586SSepherosa Ziehau if (val & ~BGE_FLOWATTN_MB_LOWAT) { 2892695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2893695a8586SSepherosa Ziehau "flow attn 0x%08x\n", val); 2894695a8586SSepherosa Ziehau reset = 1; 2895695a8586SSepherosa Ziehau } 2896695a8586SSepherosa Ziehau 2897695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_MSI_STATUS); 2898695a8586SSepherosa Ziehau if (val & ~BGE_MSISTAT_MSI_PCI_REQ) { 2899695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2900695a8586SSepherosa Ziehau "msi status 0x%08x\n", val); 2901695a8586SSepherosa Ziehau reset = 1; 2902695a8586SSepherosa Ziehau } 2903695a8586SSepherosa Ziehau 2904695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_RDMA_STATUS); 2905695a8586SSepherosa Ziehau if (val) { 2906695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2907695a8586SSepherosa Ziehau "rmda status 0x%08x\n", val); 2908695a8586SSepherosa Ziehau reset = 1; 2909695a8586SSepherosa Ziehau } 2910695a8586SSepherosa Ziehau 2911695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_WDMA_STATUS); 2912695a8586SSepherosa Ziehau if (val) { 2913695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2914695a8586SSepherosa Ziehau "wdma status 0x%08x\n", val); 2915695a8586SSepherosa Ziehau reset = 1; 2916695a8586SSepherosa Ziehau } 2917695a8586SSepherosa Ziehau 2918695a8586SSepherosa Ziehau if (reset) { 2919695a8586SSepherosa Ziehau bnx_serialize_skipmain(sc); 2920695a8586SSepherosa Ziehau bnx_init(sc); 2921695a8586SSepherosa Ziehau bnx_deserialize_skipmain(sc); 2922695a8586SSepherosa Ziehau } 292324e16e4bSSepherosa Ziehau handle = 1; 2924695a8586SSepherosa Ziehau } 2925695a8586SSepherosa Ziehau 292624e16e4bSSepherosa Ziehau if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) || sc->bnx_link_evt) { 292724e16e4bSSepherosa Ziehau if (bootverbose) { 292824e16e4bSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "link change, " 292924e16e4bSSepherosa Ziehau "link_evt %d\n", sc->bnx_link_evt); 293024e16e4bSSepherosa Ziehau } 2931695a8586SSepherosa Ziehau bnx_link_poll(sc); 293224e16e4bSSepherosa Ziehau handle = 1; 293324e16e4bSSepherosa Ziehau } 293424e16e4bSSepherosa Ziehau 293524e16e4bSSepherosa Ziehau return handle; 2936695a8586SSepherosa Ziehau } 2937695a8586SSepherosa Ziehau 293839a8d43aSSepherosa Ziehau #ifdef IFPOLL_ENABLE 29396c8d8eccSSepherosa Ziehau 29406c8d8eccSSepherosa Ziehau static void 29414fa38985SSepherosa Ziehau bnx_npoll_rx(struct ifnet *ifp __unused, void *xret, int cycle) 29424fa38985SSepherosa Ziehau { 29434fa38985SSepherosa Ziehau struct bnx_rx_ret_ring *ret = xret; 29444fa38985SSepherosa Ziehau uint16_t rx_prod; 29454fa38985SSepherosa Ziehau 29464fa38985SSepherosa Ziehau ASSERT_SERIALIZED(&ret->bnx_rx_ret_serialize); 29474fa38985SSepherosa Ziehau 29484fa38985SSepherosa Ziehau ret->bnx_saved_status_tag = *ret->bnx_hw_status_tag; 29494fa38985SSepherosa Ziehau cpu_lfence(); 29504fa38985SSepherosa Ziehau 29514fa38985SSepherosa Ziehau rx_prod = *ret->bnx_rx_considx; 29524fa38985SSepherosa Ziehau if (ret->bnx_rx_saved_considx != rx_prod) 29534fa38985SSepherosa Ziehau bnx_rxeof(ret, rx_prod, cycle); 29544fa38985SSepherosa Ziehau } 29554fa38985SSepherosa Ziehau 29564fa38985SSepherosa Ziehau static void 2957695a8586SSepherosa Ziehau bnx_npoll_tx_notag(struct ifnet *ifp __unused, void *xtxr, int cycle __unused) 29584fa38985SSepherosa Ziehau { 29594fa38985SSepherosa Ziehau struct bnx_tx_ring *txr = xtxr; 29604fa38985SSepherosa Ziehau uint16_t tx_cons; 29614fa38985SSepherosa Ziehau 29624fa38985SSepherosa Ziehau ASSERT_SERIALIZED(&txr->bnx_tx_serialize); 29634fa38985SSepherosa Ziehau 29644fa38985SSepherosa Ziehau tx_cons = *txr->bnx_tx_considx; 29654fa38985SSepherosa Ziehau if (txr->bnx_tx_saved_considx != tx_cons) 29664fa38985SSepherosa Ziehau bnx_txeof(txr, tx_cons); 29674fa38985SSepherosa Ziehau } 29684fa38985SSepherosa Ziehau 29694fa38985SSepherosa Ziehau static void 2970695a8586SSepherosa Ziehau bnx_npoll_tx(struct ifnet *ifp, void *xtxr, int cycle) 2971695a8586SSepherosa Ziehau { 2972695a8586SSepherosa Ziehau struct bnx_tx_ring *txr = xtxr; 2973695a8586SSepherosa Ziehau 2974695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&txr->bnx_tx_serialize); 2975695a8586SSepherosa Ziehau 2976695a8586SSepherosa Ziehau txr->bnx_saved_status_tag = *txr->bnx_hw_status_tag; 2977695a8586SSepherosa Ziehau cpu_lfence(); 2978695a8586SSepherosa Ziehau bnx_npoll_tx_notag(ifp, txr, cycle); 2979695a8586SSepherosa Ziehau } 2980695a8586SSepherosa Ziehau 2981695a8586SSepherosa Ziehau static void 2982695a8586SSepherosa Ziehau bnx_npoll_status_notag(struct ifnet *ifp) 29834fa38985SSepherosa Ziehau { 29844fa38985SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 29854fa38985SSepherosa Ziehau 29864fa38985SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 29874fa38985SSepherosa Ziehau 298824e16e4bSSepherosa Ziehau if (bnx_handle_status(sc)) { 298924e16e4bSSepherosa Ziehau /* 299024e16e4bSSepherosa Ziehau * Status changes are handled; force the chip to 299124e16e4bSSepherosa Ziehau * update the status block to reflect whether there 299224e16e4bSSepherosa Ziehau * are more status changes or not, else staled status 299324e16e4bSSepherosa Ziehau * changes are always seen. 299424e16e4bSSepherosa Ziehau */ 299524e16e4bSSepherosa Ziehau BNX_SETBIT(sc, BGE_HCC_MODE, BGE_HCCMODE_COAL_NOW); 299624e16e4bSSepherosa Ziehau } 2997695a8586SSepherosa Ziehau } 2998695a8586SSepherosa Ziehau 2999695a8586SSepherosa Ziehau static void 3000695a8586SSepherosa Ziehau bnx_npoll_status(struct ifnet *ifp) 3001695a8586SSepherosa Ziehau { 3002695a8586SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 3003695a8586SSepherosa Ziehau 3004695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 3005695a8586SSepherosa Ziehau 3006695a8586SSepherosa Ziehau sc->bnx_saved_status_tag = *sc->bnx_hw_status_tag; 3007695a8586SSepherosa Ziehau cpu_lfence(); 3008695a8586SSepherosa Ziehau bnx_npoll_status_notag(ifp); 30094fa38985SSepherosa Ziehau } 30104fa38985SSepherosa Ziehau 30114fa38985SSepherosa Ziehau static void 301239a8d43aSSepherosa Ziehau bnx_npoll(struct ifnet *ifp, struct ifpoll_info *info) 301339a8d43aSSepherosa Ziehau { 301439a8d43aSSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 30154fa38985SSepherosa Ziehau int i; 301639a8d43aSSepherosa Ziehau 3017329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 301839a8d43aSSepherosa Ziehau 301939a8d43aSSepherosa Ziehau if (info != NULL) { 3020695a8586SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_STATUS_HASTAG) 30214fa38985SSepherosa Ziehau info->ifpi_status.status_func = bnx_npoll_status; 3022695a8586SSepherosa Ziehau else 3023695a8586SSepherosa Ziehau info->ifpi_status.status_func = bnx_npoll_status_notag; 30244fa38985SSepherosa Ziehau info->ifpi_status.serializer = &sc->bnx_main_serialize; 302539a8d43aSSepherosa Ziehau 30264fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 30274fa38985SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 30284fa38985SSepherosa Ziehau int idx = i + sc->bnx_npoll_txoff; 30294fa38985SSepherosa Ziehau 30304fa38985SSepherosa Ziehau KKASSERT(idx < ncpus2); 3031695a8586SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_RXTX_BUNDLE) { 3032695a8586SSepherosa Ziehau info->ifpi_tx[idx].poll_func = 3033695a8586SSepherosa Ziehau bnx_npoll_tx_notag; 3034695a8586SSepherosa Ziehau } else { 30354fa38985SSepherosa Ziehau info->ifpi_tx[idx].poll_func = bnx_npoll_tx; 3036695a8586SSepherosa Ziehau } 30374fa38985SSepherosa Ziehau info->ifpi_tx[idx].arg = txr; 30384fa38985SSepherosa Ziehau info->ifpi_tx[idx].serializer = &txr->bnx_tx_serialize; 30394fa38985SSepherosa Ziehau ifsq_set_cpuid(txr->bnx_ifsq, idx); 30404fa38985SSepherosa Ziehau } 30414fa38985SSepherosa Ziehau 30424fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 30434fa38985SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[i]; 30444fa38985SSepherosa Ziehau int idx = i + sc->bnx_npoll_rxoff; 30454fa38985SSepherosa Ziehau 30464fa38985SSepherosa Ziehau KKASSERT(idx < ncpus2); 30474fa38985SSepherosa Ziehau info->ifpi_rx[idx].poll_func = bnx_npoll_rx; 30484fa38985SSepherosa Ziehau info->ifpi_rx[idx].arg = ret; 30494fa38985SSepherosa Ziehau info->ifpi_rx[idx].serializer = 30504fa38985SSepherosa Ziehau &ret->bnx_rx_ret_serialize; 30514fa38985SSepherosa Ziehau } 305239a8d43aSSepherosa Ziehau 30537dbaa833SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 305439a8d43aSSepherosa Ziehau bnx_disable_intr(sc); 30557dbaa833SSepherosa Ziehau bnx_set_tick_cpuid(sc, TRUE); 305627357d84SSepherosa Ziehau 3057a86cc105SSepherosa Ziehau sc->bnx_coal_chg = BNX_TX_COAL_BDS_CHG | 3058a86cc105SSepherosa Ziehau BNX_RX_COAL_BDS_CHG; 305927357d84SSepherosa Ziehau bnx_coal_change(sc); 30607dbaa833SSepherosa Ziehau } 306139a8d43aSSepherosa Ziehau } else { 30624fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 30634fa38985SSepherosa Ziehau ifsq_set_cpuid(sc->bnx_tx_ring[i].bnx_ifsq, 30644fa38985SSepherosa Ziehau sc->bnx_tx_ring[i].bnx_tx_cpuid); 30654fa38985SSepherosa Ziehau } 30667dbaa833SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 3067a86cc105SSepherosa Ziehau sc->bnx_coal_chg = BNX_TX_COAL_BDS_CHG | 3068a86cc105SSepherosa Ziehau BNX_RX_COAL_BDS_CHG; 306927357d84SSepherosa Ziehau bnx_coal_change(sc); 307027357d84SSepherosa Ziehau 307139a8d43aSSepherosa Ziehau bnx_enable_intr(sc); 30727dbaa833SSepherosa Ziehau bnx_set_tick_cpuid(sc, FALSE); 30737dbaa833SSepherosa Ziehau } 307439a8d43aSSepherosa Ziehau } 307539a8d43aSSepherosa Ziehau } 307639a8d43aSSepherosa Ziehau 307739a8d43aSSepherosa Ziehau #endif /* IFPOLL_ENABLE */ 30786c8d8eccSSepherosa Ziehau 30796c8d8eccSSepherosa Ziehau static void 30806c8d8eccSSepherosa Ziehau bnx_intr_legacy(void *xsc) 30816c8d8eccSSepherosa Ziehau { 30826c8d8eccSSepherosa Ziehau struct bnx_softc *sc = xsc; 30834fa38985SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[0]; 30846c8d8eccSSepherosa Ziehau 30854fa38985SSepherosa Ziehau if (ret->bnx_saved_status_tag == *ret->bnx_hw_status_tag) { 30866c8d8eccSSepherosa Ziehau uint32_t val; 30876c8d8eccSSepherosa Ziehau 30886c8d8eccSSepherosa Ziehau val = pci_read_config(sc->bnx_dev, BGE_PCI_PCISTATE, 4); 30896c8d8eccSSepherosa Ziehau if (val & BGE_PCISTAT_INTR_NOTACT) 30906c8d8eccSSepherosa Ziehau return; 30916c8d8eccSSepherosa Ziehau } 30926c8d8eccSSepherosa Ziehau 30936c8d8eccSSepherosa Ziehau /* 30946c8d8eccSSepherosa Ziehau * NOTE: 30956c8d8eccSSepherosa Ziehau * Interrupt will have to be disabled if tagged status 30966c8d8eccSSepherosa Ziehau * is used, else interrupt will always be asserted on 30976c8d8eccSSepherosa Ziehau * certain chips (at least on BCM5750 AX/BX). 30986c8d8eccSSepherosa Ziehau */ 30996c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_IRQ0_LO, 1); 31006c8d8eccSSepherosa Ziehau 31016c8d8eccSSepherosa Ziehau bnx_intr(sc); 31026c8d8eccSSepherosa Ziehau } 31036c8d8eccSSepherosa Ziehau 31046c8d8eccSSepherosa Ziehau static void 310503cc99fdSSepherosa Ziehau bnx_msi(void *xsc) 31066c8d8eccSSepherosa Ziehau { 31076c8d8eccSSepherosa Ziehau bnx_intr(xsc); 31086c8d8eccSSepherosa Ziehau } 31096c8d8eccSSepherosa Ziehau 31106c8d8eccSSepherosa Ziehau static void 31116c8d8eccSSepherosa Ziehau bnx_intr(struct bnx_softc *sc) 31126c8d8eccSSepherosa Ziehau { 31136c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 31144fa38985SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[0]; 31156c8d8eccSSepherosa Ziehau 3116329f9016SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 3117329f9016SSepherosa Ziehau 31184fa38985SSepherosa Ziehau ret->bnx_saved_status_tag = *ret->bnx_hw_status_tag; 31196c8d8eccSSepherosa Ziehau /* 31206c8d8eccSSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 31216c8d8eccSSepherosa Ziehau * before rx_prod, tx_cons and status. 31226c8d8eccSSepherosa Ziehau */ 31236c8d8eccSSepherosa Ziehau cpu_lfence(); 31246c8d8eccSSepherosa Ziehau 3125695a8586SSepherosa Ziehau bnx_handle_status(sc); 31266c8d8eccSSepherosa Ziehau 31276c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 31284fa38985SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[0]; 31293a16b7b8SSepherosa Ziehau uint16_t rx_prod, tx_cons; 31303a16b7b8SSepherosa Ziehau 3131329f9016SSepherosa Ziehau lwkt_serialize_enter(&ret->bnx_rx_ret_serialize); 31323a16b7b8SSepherosa Ziehau rx_prod = *ret->bnx_rx_considx; 3133beedf5beSSepherosa Ziehau if (ret->bnx_rx_saved_considx != rx_prod) 3134beedf5beSSepherosa Ziehau bnx_rxeof(ret, rx_prod, -1); 3135329f9016SSepherosa Ziehau lwkt_serialize_exit(&ret->bnx_rx_ret_serialize); 31366c8d8eccSSepherosa Ziehau 3137329f9016SSepherosa Ziehau lwkt_serialize_enter(&txr->bnx_tx_serialize); 3138329f9016SSepherosa Ziehau tx_cons = *txr->bnx_tx_considx; 313933a04907SSepherosa Ziehau if (txr->bnx_tx_saved_considx != tx_cons) 314033a04907SSepherosa Ziehau bnx_txeof(txr, tx_cons); 3141329f9016SSepherosa Ziehau lwkt_serialize_exit(&txr->bnx_tx_serialize); 31426c8d8eccSSepherosa Ziehau } 31436c8d8eccSSepherosa Ziehau 31444fa38985SSepherosa Ziehau bnx_writembx(sc, BGE_MBX_IRQ0_LO, ret->bnx_saved_status_tag << 24); 31456c8d8eccSSepherosa Ziehau } 31466c8d8eccSSepherosa Ziehau 31476c8d8eccSSepherosa Ziehau static void 3148695a8586SSepherosa Ziehau bnx_msix_tx_status(void *xtxr) 3149695a8586SSepherosa Ziehau { 3150695a8586SSepherosa Ziehau struct bnx_tx_ring *txr = xtxr; 3151695a8586SSepherosa Ziehau struct bnx_softc *sc = txr->bnx_sc; 3152695a8586SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 3153695a8586SSepherosa Ziehau 3154695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 3155695a8586SSepherosa Ziehau 3156695a8586SSepherosa Ziehau txr->bnx_saved_status_tag = *txr->bnx_hw_status_tag; 3157695a8586SSepherosa Ziehau /* 3158695a8586SSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 3159695a8586SSepherosa Ziehau * before tx_cons and status. 3160695a8586SSepherosa Ziehau */ 3161695a8586SSepherosa Ziehau cpu_lfence(); 3162695a8586SSepherosa Ziehau 3163695a8586SSepherosa Ziehau bnx_handle_status(sc); 3164695a8586SSepherosa Ziehau 3165695a8586SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 3166695a8586SSepherosa Ziehau uint16_t tx_cons; 3167695a8586SSepherosa Ziehau 3168695a8586SSepherosa Ziehau lwkt_serialize_enter(&txr->bnx_tx_serialize); 3169695a8586SSepherosa Ziehau tx_cons = *txr->bnx_tx_considx; 3170695a8586SSepherosa Ziehau if (txr->bnx_tx_saved_considx != tx_cons) 3171695a8586SSepherosa Ziehau bnx_txeof(txr, tx_cons); 3172695a8586SSepherosa Ziehau lwkt_serialize_exit(&txr->bnx_tx_serialize); 3173695a8586SSepherosa Ziehau } 3174695a8586SSepherosa Ziehau 3175695a8586SSepherosa Ziehau bnx_writembx(sc, BGE_MBX_IRQ0_LO, txr->bnx_saved_status_tag << 24); 3176695a8586SSepherosa Ziehau } 3177695a8586SSepherosa Ziehau 3178695a8586SSepherosa Ziehau static void 3179695a8586SSepherosa Ziehau bnx_msix_rx(void *xret) 3180695a8586SSepherosa Ziehau { 3181695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret = xret; 3182695a8586SSepherosa Ziehau uint16_t rx_prod; 3183695a8586SSepherosa Ziehau 3184695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&ret->bnx_rx_ret_serialize); 3185695a8586SSepherosa Ziehau 3186695a8586SSepherosa Ziehau ret->bnx_saved_status_tag = *ret->bnx_hw_status_tag; 3187695a8586SSepherosa Ziehau /* 3188695a8586SSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 3189695a8586SSepherosa Ziehau * before rx_prod. 3190695a8586SSepherosa Ziehau */ 3191695a8586SSepherosa Ziehau cpu_lfence(); 3192695a8586SSepherosa Ziehau 3193695a8586SSepherosa Ziehau rx_prod = *ret->bnx_rx_considx; 3194695a8586SSepherosa Ziehau if (ret->bnx_rx_saved_considx != rx_prod) 3195695a8586SSepherosa Ziehau bnx_rxeof(ret, rx_prod, -1); 3196695a8586SSepherosa Ziehau 3197695a8586SSepherosa Ziehau bnx_writembx(ret->bnx_sc, ret->bnx_msix_mbx, 3198695a8586SSepherosa Ziehau ret->bnx_saved_status_tag << 24); 3199695a8586SSepherosa Ziehau } 3200695a8586SSepherosa Ziehau 3201695a8586SSepherosa Ziehau static void 3202695a8586SSepherosa Ziehau bnx_msix_rxtx(void *xret) 3203695a8586SSepherosa Ziehau { 3204695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret = xret; 3205695a8586SSepherosa Ziehau struct bnx_tx_ring *txr = ret->bnx_txr; 3206695a8586SSepherosa Ziehau uint16_t rx_prod, tx_cons; 3207695a8586SSepherosa Ziehau 3208695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&ret->bnx_rx_ret_serialize); 3209695a8586SSepherosa Ziehau 3210695a8586SSepherosa Ziehau ret->bnx_saved_status_tag = *ret->bnx_hw_status_tag; 3211695a8586SSepherosa Ziehau /* 3212695a8586SSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 3213695a8586SSepherosa Ziehau * before rx_prod and tx_cons. 3214695a8586SSepherosa Ziehau */ 3215695a8586SSepherosa Ziehau cpu_lfence(); 3216695a8586SSepherosa Ziehau 3217695a8586SSepherosa Ziehau rx_prod = *ret->bnx_rx_considx; 3218695a8586SSepherosa Ziehau if (ret->bnx_rx_saved_considx != rx_prod) 3219695a8586SSepherosa Ziehau bnx_rxeof(ret, rx_prod, -1); 3220695a8586SSepherosa Ziehau 3221695a8586SSepherosa Ziehau lwkt_serialize_enter(&txr->bnx_tx_serialize); 3222695a8586SSepherosa Ziehau tx_cons = *txr->bnx_tx_considx; 3223695a8586SSepherosa Ziehau if (txr->bnx_tx_saved_considx != tx_cons) 3224695a8586SSepherosa Ziehau bnx_txeof(txr, tx_cons); 3225695a8586SSepherosa Ziehau lwkt_serialize_exit(&txr->bnx_tx_serialize); 3226695a8586SSepherosa Ziehau 3227695a8586SSepherosa Ziehau bnx_writembx(ret->bnx_sc, ret->bnx_msix_mbx, 3228695a8586SSepherosa Ziehau ret->bnx_saved_status_tag << 24); 3229695a8586SSepherosa Ziehau } 3230695a8586SSepherosa Ziehau 3231695a8586SSepherosa Ziehau static void 3232695a8586SSepherosa Ziehau bnx_msix_status(void *xsc) 3233695a8586SSepherosa Ziehau { 3234695a8586SSepherosa Ziehau struct bnx_softc *sc = xsc; 3235695a8586SSepherosa Ziehau 3236695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 3237695a8586SSepherosa Ziehau 3238695a8586SSepherosa Ziehau sc->bnx_saved_status_tag = *sc->bnx_hw_status_tag; 3239695a8586SSepherosa Ziehau /* 3240695a8586SSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 3241695a8586SSepherosa Ziehau * before status. 3242695a8586SSepherosa Ziehau */ 3243695a8586SSepherosa Ziehau cpu_lfence(); 3244695a8586SSepherosa Ziehau 3245695a8586SSepherosa Ziehau bnx_handle_status(sc); 3246695a8586SSepherosa Ziehau 3247695a8586SSepherosa Ziehau bnx_writembx(sc, BGE_MBX_IRQ0_LO, sc->bnx_saved_status_tag << 24); 3248695a8586SSepherosa Ziehau } 3249695a8586SSepherosa Ziehau 3250695a8586SSepherosa Ziehau static void 32516c8d8eccSSepherosa Ziehau bnx_tick(void *xsc) 32526c8d8eccSSepherosa Ziehau { 32536c8d8eccSSepherosa Ziehau struct bnx_softc *sc = xsc; 32546c8d8eccSSepherosa Ziehau 3255329f9016SSepherosa Ziehau lwkt_serialize_enter(&sc->bnx_main_serialize); 32566c8d8eccSSepherosa Ziehau 32576c8d8eccSSepherosa Ziehau bnx_stats_update_regs(sc); 32586c8d8eccSSepherosa Ziehau 32596c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 32606c8d8eccSSepherosa Ziehau /* 32616c8d8eccSSepherosa Ziehau * Since in TBI mode auto-polling can't be used we should poll 32626c8d8eccSSepherosa Ziehau * link status manually. Here we register pending link event 32636c8d8eccSSepherosa Ziehau * and trigger interrupt. 32646c8d8eccSSepherosa Ziehau */ 32656c8d8eccSSepherosa Ziehau sc->bnx_link_evt++; 32666c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_HCC_MODE, BGE_HCCMODE_COAL_NOW); 32676c8d8eccSSepherosa Ziehau } else if (!sc->bnx_link) { 32686c8d8eccSSepherosa Ziehau mii_tick(device_get_softc(sc->bnx_miibus)); 32696c8d8eccSSepherosa Ziehau } 32706c8d8eccSSepherosa Ziehau 32717dbaa833SSepherosa Ziehau callout_reset_bycpu(&sc->bnx_tick_timer, hz, bnx_tick, sc, 32727dbaa833SSepherosa Ziehau sc->bnx_tick_cpuid); 32736c8d8eccSSepherosa Ziehau 3274329f9016SSepherosa Ziehau lwkt_serialize_exit(&sc->bnx_main_serialize); 32756c8d8eccSSepherosa Ziehau } 32766c8d8eccSSepherosa Ziehau 32776c8d8eccSSepherosa Ziehau static void 32786c8d8eccSSepherosa Ziehau bnx_stats_update_regs(struct bnx_softc *sc) 32796c8d8eccSSepherosa Ziehau { 32806c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 32816c8d8eccSSepherosa Ziehau struct bge_mac_stats_regs stats; 3282695a8586SSepherosa Ziehau uint32_t *s, val; 32836c8d8eccSSepherosa Ziehau int i; 32846c8d8eccSSepherosa Ziehau 32856c8d8eccSSepherosa Ziehau s = (uint32_t *)&stats; 32866c8d8eccSSepherosa Ziehau for (i = 0; i < sizeof(struct bge_mac_stats_regs); i += 4) { 32876c8d8eccSSepherosa Ziehau *s = CSR_READ_4(sc, BGE_RX_STATS + i); 32886c8d8eccSSepherosa Ziehau s++; 32896c8d8eccSSepherosa Ziehau } 32906c8d8eccSSepherosa Ziehau 3291d40991efSSepherosa Ziehau IFNET_STAT_SET(ifp, collisions, 32926c8d8eccSSepherosa Ziehau (stats.dot3StatsSingleCollisionFrames + 32936c8d8eccSSepherosa Ziehau stats.dot3StatsMultipleCollisionFrames + 32946c8d8eccSSepherosa Ziehau stats.dot3StatsExcessiveCollisions + 3295d40991efSSepherosa Ziehau stats.dot3StatsLateCollisions)); 3296695a8586SSepherosa Ziehau 3297695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_RXLP_LOCSTAT_OUT_OF_BDS); 3298695a8586SSepherosa Ziehau sc->bnx_norxbds += val; 32996c8d8eccSSepherosa Ziehau } 33006c8d8eccSSepherosa Ziehau 33016c8d8eccSSepherosa Ziehau /* 33026c8d8eccSSepherosa Ziehau * Encapsulate an mbuf chain in the tx ring by coupling the mbuf data 33036c8d8eccSSepherosa Ziehau * pointers to descriptors. 33046c8d8eccSSepherosa Ziehau */ 33056c8d8eccSSepherosa Ziehau static int 330633a04907SSepherosa Ziehau bnx_encap(struct bnx_tx_ring *txr, struct mbuf **m_head0, uint32_t *txidx, 3307c9b7f592SSepherosa Ziehau int *segs_used) 33086c8d8eccSSepherosa Ziehau { 33096c8d8eccSSepherosa Ziehau struct bge_tx_bd *d = NULL; 331066deb1c1SSepherosa Ziehau uint16_t csum_flags = 0, vlan_tag = 0, mss = 0; 33116c8d8eccSSepherosa Ziehau bus_dma_segment_t segs[BNX_NSEG_NEW]; 33126c8d8eccSSepherosa Ziehau bus_dmamap_t map; 33136c8d8eccSSepherosa Ziehau int error, maxsegs, nsegs, idx, i; 33146c8d8eccSSepherosa Ziehau struct mbuf *m_head = *m_head0, *m_new; 33156c8d8eccSSepherosa Ziehau 331666deb1c1SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 331766deb1c1SSepherosa Ziehau #ifdef BNX_TSO_DEBUG 331866deb1c1SSepherosa Ziehau int tso_nsegs; 331966deb1c1SSepherosa Ziehau #endif 332066deb1c1SSepherosa Ziehau 332133a04907SSepherosa Ziehau error = bnx_setup_tso(txr, m_head0, &mss, &csum_flags); 332266deb1c1SSepherosa Ziehau if (error) 332366deb1c1SSepherosa Ziehau return error; 332466deb1c1SSepherosa Ziehau m_head = *m_head0; 332566deb1c1SSepherosa Ziehau 332666deb1c1SSepherosa Ziehau #ifdef BNX_TSO_DEBUG 3327f0336d39SSepherosa Ziehau tso_nsegs = (m_head->m_pkthdr.len / 3328f0336d39SSepherosa Ziehau m_head->m_pkthdr.tso_segsz) - 1; 332966deb1c1SSepherosa Ziehau if (tso_nsegs > (BNX_TSO_NSTATS - 1)) 333066deb1c1SSepherosa Ziehau tso_nsegs = BNX_TSO_NSTATS - 1; 333166deb1c1SSepherosa Ziehau else if (tso_nsegs < 0) 333266deb1c1SSepherosa Ziehau tso_nsegs = 0; 33335a0c3c3aSSascha Wildner txr->bnx_sc->bnx_tsosegs[tso_nsegs]++; 333466deb1c1SSepherosa Ziehau #endif 333566deb1c1SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & BNX_CSUM_FEATURES) { 33366c8d8eccSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 33376c8d8eccSSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_IP_CSUM; 33386c8d8eccSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) 33396c8d8eccSSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_TCP_UDP_CSUM; 33406c8d8eccSSepherosa Ziehau if (m_head->m_flags & M_LASTFRAG) 33416c8d8eccSSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_IP_FRAG_END; 33426c8d8eccSSepherosa Ziehau else if (m_head->m_flags & M_FRAG) 33436c8d8eccSSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_IP_FRAG; 33446c8d8eccSSepherosa Ziehau } 334566deb1c1SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 334666deb1c1SSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_VLAN_TAG; 334766deb1c1SSepherosa Ziehau vlan_tag = m_head->m_pkthdr.ether_vlantag; 334866deb1c1SSepherosa Ziehau } 33496c8d8eccSSepherosa Ziehau 33506c8d8eccSSepherosa Ziehau idx = *txidx; 3351fa4b1067SSepherosa Ziehau map = txr->bnx_tx_buf[idx].bnx_tx_dmamap; 33526c8d8eccSSepherosa Ziehau 3353fa639b88SSepherosa Ziehau maxsegs = (BGE_TX_RING_CNT - txr->bnx_tx_cnt) - BNX_NSEG_RSVD; 33546c8d8eccSSepherosa Ziehau KASSERT(maxsegs >= BNX_NSEG_SPARE, 33556c8d8eccSSepherosa Ziehau ("not enough segments %d", maxsegs)); 33566c8d8eccSSepherosa Ziehau 33576c8d8eccSSepherosa Ziehau if (maxsegs > BNX_NSEG_NEW) 33586c8d8eccSSepherosa Ziehau maxsegs = BNX_NSEG_NEW; 33596c8d8eccSSepherosa Ziehau 33606c8d8eccSSepherosa Ziehau /* 33616c8d8eccSSepherosa Ziehau * Pad outbound frame to BGE_MIN_FRAMELEN for an unusual reason. 33626c8d8eccSSepherosa Ziehau * The bge hardware will pad out Tx runts to BGE_MIN_FRAMELEN, 33636c8d8eccSSepherosa Ziehau * but when such padded frames employ the bge IP/TCP checksum 33646c8d8eccSSepherosa Ziehau * offload, the hardware checksum assist gives incorrect results 33656c8d8eccSSepherosa Ziehau * (possibly from incorporating its own padding into the UDP/TCP 33666c8d8eccSSepherosa Ziehau * checksum; who knows). If we pad such runts with zeros, the 33676c8d8eccSSepherosa Ziehau * onboard checksum comes out correct. 33686c8d8eccSSepherosa Ziehau */ 33696c8d8eccSSepherosa Ziehau if ((csum_flags & BGE_TXBDFLAG_TCP_UDP_CSUM) && 33706c8d8eccSSepherosa Ziehau m_head->m_pkthdr.len < BNX_MIN_FRAMELEN) { 33716c8d8eccSSepherosa Ziehau error = m_devpad(m_head, BNX_MIN_FRAMELEN); 33726c8d8eccSSepherosa Ziehau if (error) 33736c8d8eccSSepherosa Ziehau goto back; 33746c8d8eccSSepherosa Ziehau } 33756c8d8eccSSepherosa Ziehau 337679a64343SSepherosa Ziehau if ((txr->bnx_tx_flags & BNX_TX_FLAG_SHORTDMA) && 337733a04907SSepherosa Ziehau m_head->m_next != NULL) { 33786c8d8eccSSepherosa Ziehau m_new = bnx_defrag_shortdma(m_head); 33796c8d8eccSSepherosa Ziehau if (m_new == NULL) { 33806c8d8eccSSepherosa Ziehau error = ENOBUFS; 33816c8d8eccSSepherosa Ziehau goto back; 33826c8d8eccSSepherosa Ziehau } 33836c8d8eccSSepherosa Ziehau *m_head0 = m_head = m_new; 33846c8d8eccSSepherosa Ziehau } 338566deb1c1SSepherosa Ziehau if ((m_head->m_pkthdr.csum_flags & CSUM_TSO) == 0 && 3386aad4de2bSSepherosa Ziehau (txr->bnx_tx_flags & BNX_TX_FLAG_FORCE_DEFRAG) && 3387aad4de2bSSepherosa Ziehau m_head->m_next != NULL) { 33886c8d8eccSSepherosa Ziehau /* 33896c8d8eccSSepherosa Ziehau * Forcefully defragment mbuf chain to overcome hardware 33906c8d8eccSSepherosa Ziehau * limitation which only support a single outstanding 33916c8d8eccSSepherosa Ziehau * DMA read operation. If it fails, keep moving on using 33926c8d8eccSSepherosa Ziehau * the original mbuf chain. 33936c8d8eccSSepherosa Ziehau */ 33946c8d8eccSSepherosa Ziehau m_new = m_defrag(m_head, MB_DONTWAIT); 33956c8d8eccSSepherosa Ziehau if (m_new != NULL) 33966c8d8eccSSepherosa Ziehau *m_head0 = m_head = m_new; 33976c8d8eccSSepherosa Ziehau } 33986c8d8eccSSepherosa Ziehau 339933a04907SSepherosa Ziehau error = bus_dmamap_load_mbuf_defrag(txr->bnx_tx_mtag, map, 34006c8d8eccSSepherosa Ziehau m_head0, segs, maxsegs, &nsegs, BUS_DMA_NOWAIT); 34016c8d8eccSSepherosa Ziehau if (error) 34026c8d8eccSSepherosa Ziehau goto back; 3403c9b7f592SSepherosa Ziehau *segs_used += nsegs; 34046c8d8eccSSepherosa Ziehau 34056c8d8eccSSepherosa Ziehau m_head = *m_head0; 340633a04907SSepherosa Ziehau bus_dmamap_sync(txr->bnx_tx_mtag, map, BUS_DMASYNC_PREWRITE); 34076c8d8eccSSepherosa Ziehau 34086c8d8eccSSepherosa Ziehau for (i = 0; ; i++) { 340933a04907SSepherosa Ziehau d = &txr->bnx_tx_ring[idx]; 34106c8d8eccSSepherosa Ziehau 34116c8d8eccSSepherosa Ziehau d->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[i].ds_addr); 34126c8d8eccSSepherosa Ziehau d->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[i].ds_addr); 34136c8d8eccSSepherosa Ziehau d->bge_len = segs[i].ds_len; 34146c8d8eccSSepherosa Ziehau d->bge_flags = csum_flags; 341566deb1c1SSepherosa Ziehau d->bge_vlan_tag = vlan_tag; 341666deb1c1SSepherosa Ziehau d->bge_mss = mss; 34176c8d8eccSSepherosa Ziehau 34186c8d8eccSSepherosa Ziehau if (i == nsegs - 1) 34196c8d8eccSSepherosa Ziehau break; 34206c8d8eccSSepherosa Ziehau BNX_INC(idx, BGE_TX_RING_CNT); 34216c8d8eccSSepherosa Ziehau } 34226c8d8eccSSepherosa Ziehau /* Mark the last segment as end of packet... */ 34236c8d8eccSSepherosa Ziehau d->bge_flags |= BGE_TXBDFLAG_END; 34246c8d8eccSSepherosa Ziehau 34256c8d8eccSSepherosa Ziehau /* 34266c8d8eccSSepherosa Ziehau * Insure that the map for this transmission is placed at 34276c8d8eccSSepherosa Ziehau * the array index of the last descriptor in this chain. 34286c8d8eccSSepherosa Ziehau */ 3429fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[*txidx].bnx_tx_dmamap = txr->bnx_tx_buf[idx].bnx_tx_dmamap; 3430fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[idx].bnx_tx_dmamap = map; 3431fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[idx].bnx_tx_mbuf = m_head; 3432fa639b88SSepherosa Ziehau txr->bnx_tx_cnt += nsegs; 34336c8d8eccSSepherosa Ziehau 34346c8d8eccSSepherosa Ziehau BNX_INC(idx, BGE_TX_RING_CNT); 34356c8d8eccSSepherosa Ziehau *txidx = idx; 34366c8d8eccSSepherosa Ziehau back: 34376c8d8eccSSepherosa Ziehau if (error) { 34386c8d8eccSSepherosa Ziehau m_freem(*m_head0); 34396c8d8eccSSepherosa Ziehau *m_head0 = NULL; 34406c8d8eccSSepherosa Ziehau } 34416c8d8eccSSepherosa Ziehau return error; 34426c8d8eccSSepherosa Ziehau } 34436c8d8eccSSepherosa Ziehau 34446c8d8eccSSepherosa Ziehau /* 34456c8d8eccSSepherosa Ziehau * Main transmit routine. To avoid having to do mbuf copies, we put pointers 34466c8d8eccSSepherosa Ziehau * to the mbuf data regions directly in the transmit descriptors. 34476c8d8eccSSepherosa Ziehau */ 34486c8d8eccSSepherosa Ziehau static void 3449f0a26983SSepherosa Ziehau bnx_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 34506c8d8eccSSepherosa Ziehau { 34513397dea6SSepherosa Ziehau struct bnx_tx_ring *txr = ifsq_get_priv(ifsq); 34526c8d8eccSSepherosa Ziehau struct mbuf *m_head = NULL; 34536c8d8eccSSepherosa Ziehau uint32_t prodidx; 3454c9b7f592SSepherosa Ziehau int nsegs = 0; 34556c8d8eccSSepherosa Ziehau 34563397dea6SSepherosa Ziehau KKASSERT(txr->bnx_ifsq == ifsq); 3457329f9016SSepherosa Ziehau ASSERT_SERIALIZED(&txr->bnx_tx_serialize); 3458f0a26983SSepherosa Ziehau 34593397dea6SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq)) 34606c8d8eccSSepherosa Ziehau return; 34616c8d8eccSSepherosa Ziehau 346233a04907SSepherosa Ziehau prodidx = txr->bnx_tx_prodidx; 34636c8d8eccSSepherosa Ziehau 3464fa4b1067SSepherosa Ziehau while (txr->bnx_tx_buf[prodidx].bnx_tx_mbuf == NULL) { 34656c8d8eccSSepherosa Ziehau /* 34666c8d8eccSSepherosa Ziehau * Sanity check: avoid coming within BGE_NSEG_RSVD 34676c8d8eccSSepherosa Ziehau * descriptors of the end of the ring. Also make 34686c8d8eccSSepherosa Ziehau * sure there are BGE_NSEG_SPARE descriptors for 3469a1bd58c9SSepherosa Ziehau * jumbo buffers' or TSO segments' defragmentation. 34706c8d8eccSSepherosa Ziehau */ 3471fa639b88SSepherosa Ziehau if ((BGE_TX_RING_CNT - txr->bnx_tx_cnt) < 34726c8d8eccSSepherosa Ziehau (BNX_NSEG_RSVD + BNX_NSEG_SPARE)) { 34733397dea6SSepherosa Ziehau ifsq_set_oactive(ifsq); 34746c8d8eccSSepherosa Ziehau break; 34756c8d8eccSSepherosa Ziehau } 34766c8d8eccSSepherosa Ziehau 34773397dea6SSepherosa Ziehau m_head = ifsq_dequeue(ifsq, NULL); 3478a1bd58c9SSepherosa Ziehau if (m_head == NULL) 3479a1bd58c9SSepherosa Ziehau break; 3480a1bd58c9SSepherosa Ziehau 34816c8d8eccSSepherosa Ziehau /* 34826c8d8eccSSepherosa Ziehau * Pack the data into the transmit ring. If we 34836c8d8eccSSepherosa Ziehau * don't have room, set the OACTIVE flag and wait 34846c8d8eccSSepherosa Ziehau * for the NIC to drain the ring. 34856c8d8eccSSepherosa Ziehau */ 348633a04907SSepherosa Ziehau if (bnx_encap(txr, &m_head, &prodidx, &nsegs)) { 34873397dea6SSepherosa Ziehau ifsq_set_oactive(ifsq); 3488d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 34896c8d8eccSSepherosa Ziehau break; 34906c8d8eccSSepherosa Ziehau } 34916c8d8eccSSepherosa Ziehau 349233a04907SSepherosa Ziehau if (nsegs >= txr->bnx_tx_wreg) { 34936c8d8eccSSepherosa Ziehau /* Transmit */ 34948bd43d5dSSepherosa Ziehau bnx_writembx(txr->bnx_sc, txr->bnx_tx_mbx, prodidx); 3495c9b7f592SSepherosa Ziehau nsegs = 0; 3496c9b7f592SSepherosa Ziehau } 34976c8d8eccSSepherosa Ziehau 3498c9b7f592SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m_head); 34996c8d8eccSSepherosa Ziehau 35006c8d8eccSSepherosa Ziehau /* 35016c8d8eccSSepherosa Ziehau * Set a timeout in case the chip goes out to lunch. 35026c8d8eccSSepherosa Ziehau */ 35033397dea6SSepherosa Ziehau txr->bnx_tx_watchdog.wd_timer = 5; 35046c8d8eccSSepherosa Ziehau } 35056c8d8eccSSepherosa Ziehau 3506c9b7f592SSepherosa Ziehau if (nsegs > 0) { 3507c9b7f592SSepherosa Ziehau /* Transmit */ 35088bd43d5dSSepherosa Ziehau bnx_writembx(txr->bnx_sc, txr->bnx_tx_mbx, prodidx); 3509c9b7f592SSepherosa Ziehau } 351033a04907SSepherosa Ziehau txr->bnx_tx_prodidx = prodidx; 3511c9b7f592SSepherosa Ziehau } 3512c9b7f592SSepherosa Ziehau 35136c8d8eccSSepherosa Ziehau static void 35146c8d8eccSSepherosa Ziehau bnx_init(void *xsc) 35156c8d8eccSSepherosa Ziehau { 35166c8d8eccSSepherosa Ziehau struct bnx_softc *sc = xsc; 35176c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 35186c8d8eccSSepherosa Ziehau uint16_t *m; 35196c8d8eccSSepherosa Ziehau uint32_t mode; 352033a04907SSepherosa Ziehau int i; 35217dbaa833SSepherosa Ziehau boolean_t polling; 35226c8d8eccSSepherosa Ziehau 3523329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 35246c8d8eccSSepherosa Ziehau 35256c8d8eccSSepherosa Ziehau /* Cancel pending I/O and flush buffers. */ 35266c8d8eccSSepherosa Ziehau bnx_stop(sc); 35276c8d8eccSSepherosa Ziehau bnx_reset(sc); 35286c8d8eccSSepherosa Ziehau bnx_chipinit(sc); 35296c8d8eccSSepherosa Ziehau 35306c8d8eccSSepherosa Ziehau /* 35316c8d8eccSSepherosa Ziehau * Init the various state machines, ring 35326c8d8eccSSepherosa Ziehau * control blocks and firmware. 35336c8d8eccSSepherosa Ziehau */ 35346c8d8eccSSepherosa Ziehau if (bnx_blockinit(sc)) { 35356c8d8eccSSepherosa Ziehau if_printf(ifp, "initialization failure\n"); 35366c8d8eccSSepherosa Ziehau bnx_stop(sc); 35376c8d8eccSSepherosa Ziehau return; 35386c8d8eccSSepherosa Ziehau } 35396c8d8eccSSepherosa Ziehau 35406c8d8eccSSepherosa Ziehau /* Specify MTU. */ 35416c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_MTU, ifp->if_mtu + 35426c8d8eccSSepherosa Ziehau ETHER_HDR_LEN + ETHER_CRC_LEN + EVL_ENCAPLEN); 35436c8d8eccSSepherosa Ziehau 35446c8d8eccSSepherosa Ziehau /* Load our MAC address. */ 35456c8d8eccSSepherosa Ziehau m = (uint16_t *)&sc->arpcom.ac_enaddr[0]; 35466c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_ADDR1_LO, htons(m[0])); 35476c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_ADDR1_HI, (htons(m[1]) << 16) | htons(m[2])); 35486c8d8eccSSepherosa Ziehau 35496c8d8eccSSepherosa Ziehau /* Enable or disable promiscuous mode as needed. */ 35506c8d8eccSSepherosa Ziehau bnx_setpromisc(sc); 35516c8d8eccSSepherosa Ziehau 35526c8d8eccSSepherosa Ziehau /* Program multicast filter. */ 35536c8d8eccSSepherosa Ziehau bnx_setmulti(sc); 35546c8d8eccSSepherosa Ziehau 35556c8d8eccSSepherosa Ziehau /* Init RX ring. */ 3556beedf5beSSepherosa Ziehau if (bnx_init_rx_ring_std(&sc->bnx_rx_std_ring)) { 35576c8d8eccSSepherosa Ziehau if_printf(ifp, "RX ring initialization failed\n"); 35586c8d8eccSSepherosa Ziehau bnx_stop(sc); 35596c8d8eccSSepherosa Ziehau return; 35606c8d8eccSSepherosa Ziehau } 35616c8d8eccSSepherosa Ziehau 35626c8d8eccSSepherosa Ziehau /* Init jumbo RX ring. */ 35636c8d8eccSSepherosa Ziehau if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN)) { 35646c8d8eccSSepherosa Ziehau if (bnx_init_rx_ring_jumbo(sc)) { 35656c8d8eccSSepherosa Ziehau if_printf(ifp, "Jumbo RX ring initialization failed\n"); 35666c8d8eccSSepherosa Ziehau bnx_stop(sc); 35676c8d8eccSSepherosa Ziehau return; 35686c8d8eccSSepherosa Ziehau } 35696c8d8eccSSepherosa Ziehau } 35706c8d8eccSSepherosa Ziehau 35716c8d8eccSSepherosa Ziehau /* Init our RX return ring index */ 3572841cdf08SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 3573841cdf08SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[i]; 3574841cdf08SSepherosa Ziehau 3575841cdf08SSepherosa Ziehau ret->bnx_rx_saved_considx = 0; 3576841cdf08SSepherosa Ziehau ret->bnx_rx_cnt = 0; 3577841cdf08SSepherosa Ziehau } 35786c8d8eccSSepherosa Ziehau 35796c8d8eccSSepherosa Ziehau /* Init TX ring. */ 358033a04907SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 358133a04907SSepherosa Ziehau bnx_init_tx_ring(&sc->bnx_tx_ring[i]); 35826c8d8eccSSepherosa Ziehau 35836c8d8eccSSepherosa Ziehau /* Enable TX MAC state machine lockup fix. */ 35846c8d8eccSSepherosa Ziehau mode = CSR_READ_4(sc, BGE_TX_MODE); 35856c8d8eccSSepherosa Ziehau mode |= BGE_TXMODE_MBUF_LOCKUP_FIX; 3586b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 3587b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 35886c8d8eccSSepherosa Ziehau mode &= ~(BGE_TXMODE_JMB_FRM_LEN | BGE_TXMODE_CNT_DN_MODE); 35896c8d8eccSSepherosa Ziehau mode |= CSR_READ_4(sc, BGE_TX_MODE) & 35906c8d8eccSSepherosa Ziehau (BGE_TXMODE_JMB_FRM_LEN | BGE_TXMODE_CNT_DN_MODE); 35916c8d8eccSSepherosa Ziehau } 35926c8d8eccSSepherosa Ziehau /* Turn on transmitter */ 35936c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_TX_MODE, mode | BGE_TXMODE_ENABLE); 35946c8d8eccSSepherosa Ziehau 3595695a8586SSepherosa Ziehau /* Initialize RSS */ 3596695a8586SSepherosa Ziehau mode = BGE_RXMODE_ENABLE; 3597695a8586SSepherosa Ziehau if (BNX_RSS_ENABLED(sc)) { 3598695a8586SSepherosa Ziehau bnx_init_rss(sc); 3599695a8586SSepherosa Ziehau mode |= BGE_RXMODE_RSS_ENABLE | 3600695a8586SSepherosa Ziehau BGE_RXMODE_RSS_HASH_MASK_BITS | 3601695a8586SSepherosa Ziehau BGE_RXMODE_RSS_IPV4_HASH | 3602695a8586SSepherosa Ziehau BGE_RXMODE_RSS_TCP_IPV4_HASH; 3603695a8586SSepherosa Ziehau } 36046c8d8eccSSepherosa Ziehau /* Turn on receiver */ 3605695a8586SSepherosa Ziehau BNX_SETBIT(sc, BGE_RX_MODE, mode); 36066c8d8eccSSepherosa Ziehau 36076c8d8eccSSepherosa Ziehau /* 36086c8d8eccSSepherosa Ziehau * Set the number of good frames to receive after RX MBUF 36096c8d8eccSSepherosa Ziehau * Low Watermark has been reached. After the RX MAC receives 36106c8d8eccSSepherosa Ziehau * this number of frames, it will drop subsequent incoming 36116c8d8eccSSepherosa Ziehau * frames until the MBUF High Watermark is reached. 36126c8d8eccSSepherosa Ziehau */ 3613bcb29629SSepherosa Ziehau if (BNX_IS_57765_FAMILY(sc)) 36146c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAX_RX_FRAME_LOWAT, 1); 36156c8d8eccSSepherosa Ziehau else 36166c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAX_RX_FRAME_LOWAT, 2); 36176c8d8eccSSepherosa Ziehau 3618695a8586SSepherosa Ziehau if (sc->bnx_intr_type == PCI_INTR_TYPE_MSI || 3619695a8586SSepherosa Ziehau sc->bnx_intr_type == PCI_INTR_TYPE_MSIX) { 36206c8d8eccSSepherosa Ziehau if (bootverbose) { 36216c8d8eccSSepherosa Ziehau if_printf(ifp, "MSI_MODE: %#x\n", 36226c8d8eccSSepherosa Ziehau CSR_READ_4(sc, BGE_MSI_MODE)); 36236c8d8eccSSepherosa Ziehau } 36246c8d8eccSSepherosa Ziehau } 36256c8d8eccSSepherosa Ziehau 36266c8d8eccSSepherosa Ziehau /* Tell firmware we're alive. */ 36276c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP); 36286c8d8eccSSepherosa Ziehau 36296c8d8eccSSepherosa Ziehau /* Enable host interrupts if polling(4) is not enabled. */ 36306c8d8eccSSepherosa Ziehau PCI_SETBIT(sc->bnx_dev, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_CLEAR_INTA, 4); 36317dbaa833SSepherosa Ziehau 36327dbaa833SSepherosa Ziehau polling = FALSE; 363339a8d43aSSepherosa Ziehau #ifdef IFPOLL_ENABLE 363439a8d43aSSepherosa Ziehau if (ifp->if_flags & IFF_NPOLLING) 36357dbaa833SSepherosa Ziehau polling = TRUE; 36367dbaa833SSepherosa Ziehau #endif 36377dbaa833SSepherosa Ziehau if (polling) 36386c8d8eccSSepherosa Ziehau bnx_disable_intr(sc); 36396c8d8eccSSepherosa Ziehau else 36406c8d8eccSSepherosa Ziehau bnx_enable_intr(sc); 36417dbaa833SSepherosa Ziehau bnx_set_tick_cpuid(sc, polling); 36426c8d8eccSSepherosa Ziehau 36436c8d8eccSSepherosa Ziehau bnx_ifmedia_upd(ifp); 36446c8d8eccSSepherosa Ziehau 36456c8d8eccSSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 36463397dea6SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 36473397dea6SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 36483397dea6SSepherosa Ziehau 36493397dea6SSepherosa Ziehau ifsq_clr_oactive(txr->bnx_ifsq); 36503397dea6SSepherosa Ziehau ifsq_watchdog_start(&txr->bnx_tx_watchdog); 36513397dea6SSepherosa Ziehau } 36526c8d8eccSSepherosa Ziehau 36537dbaa833SSepherosa Ziehau callout_reset_bycpu(&sc->bnx_tick_timer, hz, bnx_tick, sc, 36547dbaa833SSepherosa Ziehau sc->bnx_tick_cpuid); 36556c8d8eccSSepherosa Ziehau } 36566c8d8eccSSepherosa Ziehau 36576c8d8eccSSepherosa Ziehau /* 36586c8d8eccSSepherosa Ziehau * Set media options. 36596c8d8eccSSepherosa Ziehau */ 36606c8d8eccSSepherosa Ziehau static int 36616c8d8eccSSepherosa Ziehau bnx_ifmedia_upd(struct ifnet *ifp) 36626c8d8eccSSepherosa Ziehau { 36636c8d8eccSSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 36646c8d8eccSSepherosa Ziehau 36656c8d8eccSSepherosa Ziehau /* If this is a 1000baseX NIC, enable the TBI port. */ 36666c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 36676c8d8eccSSepherosa Ziehau struct ifmedia *ifm = &sc->bnx_ifmedia; 36686c8d8eccSSepherosa Ziehau 36696c8d8eccSSepherosa Ziehau if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 36706c8d8eccSSepherosa Ziehau return(EINVAL); 36716c8d8eccSSepherosa Ziehau 36726c8d8eccSSepherosa Ziehau switch(IFM_SUBTYPE(ifm->ifm_media)) { 36736c8d8eccSSepherosa Ziehau case IFM_AUTO: 36746c8d8eccSSepherosa Ziehau break; 36756c8d8eccSSepherosa Ziehau 36766c8d8eccSSepherosa Ziehau case IFM_1000_SX: 36776c8d8eccSSepherosa Ziehau if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) { 36786c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_MAC_MODE, 36796c8d8eccSSepherosa Ziehau BGE_MACMODE_HALF_DUPLEX); 36806c8d8eccSSepherosa Ziehau } else { 36816c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MAC_MODE, 36826c8d8eccSSepherosa Ziehau BGE_MACMODE_HALF_DUPLEX); 36836c8d8eccSSepherosa Ziehau } 36846c8d8eccSSepherosa Ziehau break; 36856c8d8eccSSepherosa Ziehau default: 36866c8d8eccSSepherosa Ziehau return(EINVAL); 36876c8d8eccSSepherosa Ziehau } 36886c8d8eccSSepherosa Ziehau } else { 36896c8d8eccSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->bnx_miibus); 36906c8d8eccSSepherosa Ziehau 36916c8d8eccSSepherosa Ziehau sc->bnx_link_evt++; 36926c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 36936c8d8eccSSepherosa Ziehau if (mii->mii_instance) { 36946c8d8eccSSepherosa Ziehau struct mii_softc *miisc; 36956c8d8eccSSepherosa Ziehau 36966c8d8eccSSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 36976c8d8eccSSepherosa Ziehau mii_phy_reset(miisc); 36986c8d8eccSSepherosa Ziehau } 36996c8d8eccSSepherosa Ziehau mii_mediachg(mii); 37006c8d8eccSSepherosa Ziehau 37016c8d8eccSSepherosa Ziehau /* 37026c8d8eccSSepherosa Ziehau * Force an interrupt so that we will call bnx_link_upd 37036c8d8eccSSepherosa Ziehau * if needed and clear any pending link state attention. 37046c8d8eccSSepherosa Ziehau * Without this we are not getting any further interrupts 37056c8d8eccSSepherosa Ziehau * for link state changes and thus will not UP the link and 37066c8d8eccSSepherosa Ziehau * not be able to send in bnx_start. The only way to get 37076c8d8eccSSepherosa Ziehau * things working was to receive a packet and get an RX 37086c8d8eccSSepherosa Ziehau * intr. 37096c8d8eccSSepherosa Ziehau * 37106c8d8eccSSepherosa Ziehau * bnx_tick should help for fiber cards and we might not 37116c8d8eccSSepherosa Ziehau * need to do this here if BNX_FLAG_TBI is set but as 37126c8d8eccSSepherosa Ziehau * we poll for fiber anyway it should not harm. 37136c8d8eccSSepherosa Ziehau */ 37146c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_HCC_MODE, BGE_HCCMODE_COAL_NOW); 37156c8d8eccSSepherosa Ziehau } 37166c8d8eccSSepherosa Ziehau return(0); 37176c8d8eccSSepherosa Ziehau } 37186c8d8eccSSepherosa Ziehau 37196c8d8eccSSepherosa Ziehau /* 37206c8d8eccSSepherosa Ziehau * Report current media status. 37216c8d8eccSSepherosa Ziehau */ 37226c8d8eccSSepherosa Ziehau static void 37236c8d8eccSSepherosa Ziehau bnx_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 37246c8d8eccSSepherosa Ziehau { 37256c8d8eccSSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 37266c8d8eccSSepherosa Ziehau 37276c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 37286c8d8eccSSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 37296c8d8eccSSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 37306c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_MAC_STS) & 37316c8d8eccSSepherosa Ziehau BGE_MACSTAT_TBI_PCS_SYNCHED) { 37326c8d8eccSSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 37336c8d8eccSSepherosa Ziehau } else { 37346c8d8eccSSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 37356c8d8eccSSepherosa Ziehau return; 37366c8d8eccSSepherosa Ziehau } 37376c8d8eccSSepherosa Ziehau 37386c8d8eccSSepherosa Ziehau ifmr->ifm_active |= IFM_1000_SX; 37396c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_MAC_MODE) & BGE_MACMODE_HALF_DUPLEX) 37406c8d8eccSSepherosa Ziehau ifmr->ifm_active |= IFM_HDX; 37416c8d8eccSSepherosa Ziehau else 37426c8d8eccSSepherosa Ziehau ifmr->ifm_active |= IFM_FDX; 37436c8d8eccSSepherosa Ziehau } else { 37446c8d8eccSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->bnx_miibus); 37456c8d8eccSSepherosa Ziehau 37466c8d8eccSSepherosa Ziehau mii_pollstat(mii); 37476c8d8eccSSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 37486c8d8eccSSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 37496c8d8eccSSepherosa Ziehau } 37506c8d8eccSSepherosa Ziehau } 37516c8d8eccSSepherosa Ziehau 37526c8d8eccSSepherosa Ziehau static int 37536c8d8eccSSepherosa Ziehau bnx_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) 37546c8d8eccSSepherosa Ziehau { 37556c8d8eccSSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 37566c8d8eccSSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 37576c8d8eccSSepherosa Ziehau int mask, error = 0; 37586c8d8eccSSepherosa Ziehau 3759329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 37606c8d8eccSSepherosa Ziehau 37616c8d8eccSSepherosa Ziehau switch (command) { 37626c8d8eccSSepherosa Ziehau case SIOCSIFMTU: 37636c8d8eccSSepherosa Ziehau if ((!BNX_IS_JUMBO_CAPABLE(sc) && ifr->ifr_mtu > ETHERMTU) || 37646c8d8eccSSepherosa Ziehau (BNX_IS_JUMBO_CAPABLE(sc) && 37656c8d8eccSSepherosa Ziehau ifr->ifr_mtu > BNX_JUMBO_MTU)) { 37666c8d8eccSSepherosa Ziehau error = EINVAL; 37676c8d8eccSSepherosa Ziehau } else if (ifp->if_mtu != ifr->ifr_mtu) { 37686c8d8eccSSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 37696c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 37706c8d8eccSSepherosa Ziehau bnx_init(sc); 37716c8d8eccSSepherosa Ziehau } 37726c8d8eccSSepherosa Ziehau break; 37736c8d8eccSSepherosa Ziehau case SIOCSIFFLAGS: 37746c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 37756c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 37766c8d8eccSSepherosa Ziehau mask = ifp->if_flags ^ sc->bnx_if_flags; 37776c8d8eccSSepherosa Ziehau 37786c8d8eccSSepherosa Ziehau /* 37796c8d8eccSSepherosa Ziehau * If only the state of the PROMISC flag 37806c8d8eccSSepherosa Ziehau * changed, then just use the 'set promisc 37816c8d8eccSSepherosa Ziehau * mode' command instead of reinitializing 37826c8d8eccSSepherosa Ziehau * the entire NIC. Doing a full re-init 37836c8d8eccSSepherosa Ziehau * means reloading the firmware and waiting 37846c8d8eccSSepherosa Ziehau * for it to start up, which may take a 37856c8d8eccSSepherosa Ziehau * second or two. Similarly for ALLMULTI. 37866c8d8eccSSepherosa Ziehau */ 37876c8d8eccSSepherosa Ziehau if (mask & IFF_PROMISC) 37886c8d8eccSSepherosa Ziehau bnx_setpromisc(sc); 37896c8d8eccSSepherosa Ziehau if (mask & IFF_ALLMULTI) 37906c8d8eccSSepherosa Ziehau bnx_setmulti(sc); 37916c8d8eccSSepherosa Ziehau } else { 37926c8d8eccSSepherosa Ziehau bnx_init(sc); 37936c8d8eccSSepherosa Ziehau } 37946c8d8eccSSepherosa Ziehau } else if (ifp->if_flags & IFF_RUNNING) { 37956c8d8eccSSepherosa Ziehau bnx_stop(sc); 37966c8d8eccSSepherosa Ziehau } 37976c8d8eccSSepherosa Ziehau sc->bnx_if_flags = ifp->if_flags; 37986c8d8eccSSepherosa Ziehau break; 37996c8d8eccSSepherosa Ziehau case SIOCADDMULTI: 38006c8d8eccSSepherosa Ziehau case SIOCDELMULTI: 38016c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 38026c8d8eccSSepherosa Ziehau bnx_setmulti(sc); 38036c8d8eccSSepherosa Ziehau break; 38046c8d8eccSSepherosa Ziehau case SIOCSIFMEDIA: 38056c8d8eccSSepherosa Ziehau case SIOCGIFMEDIA: 38066c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 38076c8d8eccSSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, 38086c8d8eccSSepherosa Ziehau &sc->bnx_ifmedia, command); 38096c8d8eccSSepherosa Ziehau } else { 38106c8d8eccSSepherosa Ziehau struct mii_data *mii; 38116c8d8eccSSepherosa Ziehau 38126c8d8eccSSepherosa Ziehau mii = device_get_softc(sc->bnx_miibus); 38136c8d8eccSSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, 38146c8d8eccSSepherosa Ziehau &mii->mii_media, command); 38156c8d8eccSSepherosa Ziehau } 38166c8d8eccSSepherosa Ziehau break; 38176c8d8eccSSepherosa Ziehau case SIOCSIFCAP: 38186c8d8eccSSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 38196c8d8eccSSepherosa Ziehau if (mask & IFCAP_HWCSUM) { 38206c8d8eccSSepherosa Ziehau ifp->if_capenable ^= (mask & IFCAP_HWCSUM); 382166deb1c1SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 382266deb1c1SSepherosa Ziehau ifp->if_hwassist |= BNX_CSUM_FEATURES; 38236c8d8eccSSepherosa Ziehau else 382466deb1c1SSepherosa Ziehau ifp->if_hwassist &= ~BNX_CSUM_FEATURES; 382566deb1c1SSepherosa Ziehau } 382666deb1c1SSepherosa Ziehau if (mask & IFCAP_TSO) { 382766deb1c1SSepherosa Ziehau ifp->if_capenable ^= (mask & IFCAP_TSO); 382866deb1c1SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO) 382966deb1c1SSepherosa Ziehau ifp->if_hwassist |= CSUM_TSO; 383066deb1c1SSepherosa Ziehau else 383166deb1c1SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 38326c8d8eccSSepherosa Ziehau } 3833b19ddf7eSSepherosa Ziehau if (mask & IFCAP_RSS) 3834b19ddf7eSSepherosa Ziehau ifp->if_capenable ^= IFCAP_RSS; 38356c8d8eccSSepherosa Ziehau break; 38366c8d8eccSSepherosa Ziehau default: 38376c8d8eccSSepherosa Ziehau error = ether_ioctl(ifp, command, data); 38386c8d8eccSSepherosa Ziehau break; 38396c8d8eccSSepherosa Ziehau } 38406c8d8eccSSepherosa Ziehau return error; 38416c8d8eccSSepherosa Ziehau } 38426c8d8eccSSepherosa Ziehau 38436c8d8eccSSepherosa Ziehau static void 38443397dea6SSepherosa Ziehau bnx_watchdog(struct ifaltq_subque *ifsq) 38456c8d8eccSSepherosa Ziehau { 38463397dea6SSepherosa Ziehau struct ifnet *ifp = ifsq_get_ifp(ifsq); 38476c8d8eccSSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 38483397dea6SSepherosa Ziehau int i; 38493397dea6SSepherosa Ziehau 38503397dea6SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 38516c8d8eccSSepherosa Ziehau 38526c8d8eccSSepherosa Ziehau if_printf(ifp, "watchdog timeout -- resetting\n"); 38536c8d8eccSSepherosa Ziehau 38546c8d8eccSSepherosa Ziehau bnx_init(sc); 38556c8d8eccSSepherosa Ziehau 3856d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 38576c8d8eccSSepherosa Ziehau 38583397dea6SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 38593397dea6SSepherosa Ziehau ifsq_devstart_sched(sc->bnx_tx_ring[i].bnx_ifsq); 38606c8d8eccSSepherosa Ziehau } 38616c8d8eccSSepherosa Ziehau 38626c8d8eccSSepherosa Ziehau /* 38636c8d8eccSSepherosa Ziehau * Stop the adapter and free any mbufs allocated to the 38646c8d8eccSSepherosa Ziehau * RX and TX lists. 38656c8d8eccSSepherosa Ziehau */ 38666c8d8eccSSepherosa Ziehau static void 38676c8d8eccSSepherosa Ziehau bnx_stop(struct bnx_softc *sc) 38686c8d8eccSSepherosa Ziehau { 38696c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 387033a04907SSepherosa Ziehau int i; 38716c8d8eccSSepherosa Ziehau 3872329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 38736c8d8eccSSepherosa Ziehau 38747dbaa833SSepherosa Ziehau callout_stop(&sc->bnx_tick_timer); 38756c8d8eccSSepherosa Ziehau 38766c8d8eccSSepherosa Ziehau /* 38776c8d8eccSSepherosa Ziehau * Disable all of the receiver blocks 38786c8d8eccSSepherosa Ziehau */ 38796c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE); 38806c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RBDI_MODE, BGE_RBDIMODE_ENABLE); 38816c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RXLP_MODE, BGE_RXLPMODE_ENABLE); 38826c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RDBDI_MODE, BGE_RBDIMODE_ENABLE); 38836c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RDC_MODE, BGE_RDCMODE_ENABLE); 38846c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RBDC_MODE, BGE_RBDCMODE_ENABLE); 38856c8d8eccSSepherosa Ziehau 38866c8d8eccSSepherosa Ziehau /* 38876c8d8eccSSepherosa Ziehau * Disable all of the transmit blocks 38886c8d8eccSSepherosa Ziehau */ 38896c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SRS_MODE, BGE_SRSMODE_ENABLE); 38906c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SBDI_MODE, BGE_SBDIMODE_ENABLE); 38916c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE); 38926c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RDMA_MODE, BGE_RDMAMODE_ENABLE); 38936c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SDC_MODE, BGE_SDCMODE_ENABLE); 38946c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SBDC_MODE, BGE_SBDCMODE_ENABLE); 38956c8d8eccSSepherosa Ziehau 38966c8d8eccSSepherosa Ziehau /* 38976c8d8eccSSepherosa Ziehau * Shut down all of the memory managers and related 38986c8d8eccSSepherosa Ziehau * state machines. 38996c8d8eccSSepherosa Ziehau */ 39006c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_HCC_MODE, BGE_HCCMODE_ENABLE); 39016c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_WDMA_MODE, BGE_WDMAMODE_ENABLE); 39026c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_FTQ_RESET, 0xFFFFFFFF); 39036c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_FTQ_RESET, 0); 39046c8d8eccSSepherosa Ziehau 39056c8d8eccSSepherosa Ziehau /* Disable host interrupts. */ 39066c8d8eccSSepherosa Ziehau bnx_disable_intr(sc); 39076c8d8eccSSepherosa Ziehau 39086c8d8eccSSepherosa Ziehau /* 39096c8d8eccSSepherosa Ziehau * Tell firmware we're shutting down. 39106c8d8eccSSepherosa Ziehau */ 39116c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP); 39126c8d8eccSSepherosa Ziehau 39136c8d8eccSSepherosa Ziehau /* Free the RX lists. */ 3914beedf5beSSepherosa Ziehau bnx_free_rx_ring_std(&sc->bnx_rx_std_ring); 39156c8d8eccSSepherosa Ziehau 39166c8d8eccSSepherosa Ziehau /* Free jumbo RX list. */ 39176c8d8eccSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) 39186c8d8eccSSepherosa Ziehau bnx_free_rx_ring_jumbo(sc); 39196c8d8eccSSepherosa Ziehau 39206c8d8eccSSepherosa Ziehau /* Free TX buffers. */ 39214fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 39224fa38985SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 39236c8d8eccSSepherosa Ziehau 39244fa38985SSepherosa Ziehau txr->bnx_saved_status_tag = 0; 39254fa38985SSepherosa Ziehau bnx_free_tx_ring(txr); 39264fa38985SSepherosa Ziehau } 39274fa38985SSepherosa Ziehau 39284fa38985SSepherosa Ziehau /* Clear saved status tag */ 39294fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) 39304fa38985SSepherosa Ziehau sc->bnx_rx_ret_ring[i].bnx_saved_status_tag = 0; 39314fa38985SSepherosa Ziehau 39326c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 39336c8d8eccSSepherosa Ziehau sc->bnx_coal_chg = 0; 39346c8d8eccSSepherosa Ziehau 39359ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 39363397dea6SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 39373397dea6SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 39383397dea6SSepherosa Ziehau 39393397dea6SSepherosa Ziehau ifsq_clr_oactive(txr->bnx_ifsq); 39403397dea6SSepherosa Ziehau ifsq_watchdog_stop(&txr->bnx_tx_watchdog); 39413397dea6SSepherosa Ziehau } 39426c8d8eccSSepherosa Ziehau } 39436c8d8eccSSepherosa Ziehau 39446c8d8eccSSepherosa Ziehau /* 39456c8d8eccSSepherosa Ziehau * Stop all chip I/O so that the kernel's probe routines don't 39466c8d8eccSSepherosa Ziehau * get confused by errant DMAs when rebooting. 39476c8d8eccSSepherosa Ziehau */ 39486c8d8eccSSepherosa Ziehau static void 39496c8d8eccSSepherosa Ziehau bnx_shutdown(device_t dev) 39506c8d8eccSSepherosa Ziehau { 39516c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 39526c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 39536c8d8eccSSepherosa Ziehau 3954329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 39556c8d8eccSSepherosa Ziehau bnx_stop(sc); 39566c8d8eccSSepherosa Ziehau bnx_reset(sc); 3957329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 39586c8d8eccSSepherosa Ziehau } 39596c8d8eccSSepherosa Ziehau 39606c8d8eccSSepherosa Ziehau static int 39616c8d8eccSSepherosa Ziehau bnx_suspend(device_t dev) 39626c8d8eccSSepherosa Ziehau { 39636c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 39646c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 39656c8d8eccSSepherosa Ziehau 3966329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 39676c8d8eccSSepherosa Ziehau bnx_stop(sc); 3968329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 39696c8d8eccSSepherosa Ziehau 39706c8d8eccSSepherosa Ziehau return 0; 39716c8d8eccSSepherosa Ziehau } 39726c8d8eccSSepherosa Ziehau 39736c8d8eccSSepherosa Ziehau static int 39746c8d8eccSSepherosa Ziehau bnx_resume(device_t dev) 39756c8d8eccSSepherosa Ziehau { 39766c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 39776c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 39786c8d8eccSSepherosa Ziehau 3979329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 39806c8d8eccSSepherosa Ziehau 39816c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 39823397dea6SSepherosa Ziehau int i; 39836c8d8eccSSepherosa Ziehau 39843397dea6SSepherosa Ziehau bnx_init(sc); 39853397dea6SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 39863397dea6SSepherosa Ziehau ifsq_devstart_sched(sc->bnx_tx_ring[i].bnx_ifsq); 39876c8d8eccSSepherosa Ziehau } 39886c8d8eccSSepherosa Ziehau 3989329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 39906c8d8eccSSepherosa Ziehau 39916c8d8eccSSepherosa Ziehau return 0; 39926c8d8eccSSepherosa Ziehau } 39936c8d8eccSSepherosa Ziehau 39946c8d8eccSSepherosa Ziehau static void 39956c8d8eccSSepherosa Ziehau bnx_setpromisc(struct bnx_softc *sc) 39966c8d8eccSSepherosa Ziehau { 39976c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 39986c8d8eccSSepherosa Ziehau 39996c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_PROMISC) 40006c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC); 40016c8d8eccSSepherosa Ziehau else 40026c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC); 40036c8d8eccSSepherosa Ziehau } 40046c8d8eccSSepherosa Ziehau 40056c8d8eccSSepherosa Ziehau static void 40066c8d8eccSSepherosa Ziehau bnx_dma_free(struct bnx_softc *sc) 40076c8d8eccSSepherosa Ziehau { 4008beedf5beSSepherosa Ziehau struct bnx_rx_std_ring *std = &sc->bnx_rx_std_ring; 40096c8d8eccSSepherosa Ziehau int i; 40106c8d8eccSSepherosa Ziehau 4011beedf5beSSepherosa Ziehau /* Destroy RX return rings */ 4012beedf5beSSepherosa Ziehau if (sc->bnx_rx_ret_ring != NULL) { 4013beedf5beSSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) 4014beedf5beSSepherosa Ziehau bnx_destroy_rx_ret_ring(&sc->bnx_rx_ret_ring[i]); 4015beedf5beSSepherosa Ziehau kfree(sc->bnx_rx_ret_ring, M_DEVBUF); 4016beedf5beSSepherosa Ziehau } 4017beedf5beSSepherosa Ziehau 40186c8d8eccSSepherosa Ziehau /* Destroy RX mbuf DMA stuffs. */ 4019beedf5beSSepherosa Ziehau if (std->bnx_rx_mtag != NULL) { 40206c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_STD_RX_RING_CNT; i++) { 4021beedf5beSSepherosa Ziehau KKASSERT(std->bnx_rx_std_buf[i].bnx_rx_mbuf == NULL); 4022beedf5beSSepherosa Ziehau bus_dmamap_destroy(std->bnx_rx_mtag, 4023beedf5beSSepherosa Ziehau std->bnx_rx_std_buf[i].bnx_rx_dmamap); 40246c8d8eccSSepherosa Ziehau } 4025beedf5beSSepherosa Ziehau bus_dma_tag_destroy(std->bnx_rx_mtag); 40266c8d8eccSSepherosa Ziehau } 40276c8d8eccSSepherosa Ziehau 4028beedf5beSSepherosa Ziehau /* Destroy standard RX ring */ 4029beedf5beSSepherosa Ziehau bnx_dma_block_free(std->bnx_rx_std_ring_tag, 4030beedf5beSSepherosa Ziehau std->bnx_rx_std_ring_map, std->bnx_rx_std_ring); 4031beedf5beSSepherosa Ziehau 403233a04907SSepherosa Ziehau /* Destroy TX rings */ 403333a04907SSepherosa Ziehau if (sc->bnx_tx_ring != NULL) { 403433a04907SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 403533a04907SSepherosa Ziehau bnx_destroy_tx_ring(&sc->bnx_tx_ring[i]); 403633a04907SSepherosa Ziehau kfree(sc->bnx_tx_ring, M_DEVBUF); 40376c8d8eccSSepherosa Ziehau } 40386c8d8eccSSepherosa Ziehau 40396c8d8eccSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) 40406c8d8eccSSepherosa Ziehau bnx_free_jumbo_mem(sc); 40416c8d8eccSSepherosa Ziehau 40420a806e3aSSepherosa Ziehau /* Destroy status blocks */ 40430a806e3aSSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 40440a806e3aSSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 40450a806e3aSSepherosa Ziehau 40460a806e3aSSepherosa Ziehau bnx_dma_block_free(intr->bnx_status_tag, 40470a806e3aSSepherosa Ziehau intr->bnx_status_map, intr->bnx_status_block); 40480a806e3aSSepherosa Ziehau } 40496c8d8eccSSepherosa Ziehau 40506c8d8eccSSepherosa Ziehau /* Destroy the parent tag */ 40516c8d8eccSSepherosa Ziehau if (sc->bnx_cdata.bnx_parent_tag != NULL) 40526c8d8eccSSepherosa Ziehau bus_dma_tag_destroy(sc->bnx_cdata.bnx_parent_tag); 40536c8d8eccSSepherosa Ziehau } 40546c8d8eccSSepherosa Ziehau 40556c8d8eccSSepherosa Ziehau static int 4056beedf5beSSepherosa Ziehau bnx_dma_alloc(device_t dev) 40576c8d8eccSSepherosa Ziehau { 4058beedf5beSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 4059beedf5beSSepherosa Ziehau struct bnx_rx_std_ring *std = &sc->bnx_rx_std_ring; 4060ac2936fdSSepherosa Ziehau int i, error, mbx; 40616c8d8eccSSepherosa Ziehau 40626c8d8eccSSepherosa Ziehau /* 40636c8d8eccSSepherosa Ziehau * Allocate the parent bus DMA tag appropriate for PCI. 40646c8d8eccSSepherosa Ziehau * 40656c8d8eccSSepherosa Ziehau * All of the NetExtreme/NetLink controllers have 4GB boundary 40666c8d8eccSSepherosa Ziehau * DMA bug. 40676c8d8eccSSepherosa Ziehau * Whenever an address crosses a multiple of the 4GB boundary 40686c8d8eccSSepherosa Ziehau * (including 4GB, 8Gb, 12Gb, etc.) and makes the transition 40696c8d8eccSSepherosa Ziehau * from 0xX_FFFF_FFFF to 0x(X+1)_0000_0000 an internal DMA 40706c8d8eccSSepherosa Ziehau * state machine will lockup and cause the device to hang. 40716c8d8eccSSepherosa Ziehau */ 40726c8d8eccSSepherosa Ziehau error = bus_dma_tag_create(NULL, 1, BGE_DMA_BOUNDARY_4G, 4073beedf5beSSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 4074beedf5beSSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 40756c8d8eccSSepherosa Ziehau 0, &sc->bnx_cdata.bnx_parent_tag); 40766c8d8eccSSepherosa Ziehau if (error) { 4077beedf5beSSepherosa Ziehau device_printf(dev, "could not create parent DMA tag\n"); 40786c8d8eccSSepherosa Ziehau return error; 40796c8d8eccSSepherosa Ziehau } 40806c8d8eccSSepherosa Ziehau 40816c8d8eccSSepherosa Ziehau /* 40820a806e3aSSepherosa Ziehau * Create DMA stuffs for status blocks. 40836c8d8eccSSepherosa Ziehau */ 40840a806e3aSSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 40850a806e3aSSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 40860a806e3aSSepherosa Ziehau 4087695a8586SSepherosa Ziehau error = bnx_dma_block_alloc(sc, 4088695a8586SSepherosa Ziehau __VM_CACHELINE_ALIGN(BGE_STATUS_BLK_SZ), 40890a806e3aSSepherosa Ziehau &intr->bnx_status_tag, &intr->bnx_status_map, 40900a806e3aSSepherosa Ziehau (void *)&intr->bnx_status_block, 40910a806e3aSSepherosa Ziehau &intr->bnx_status_block_paddr); 40926c8d8eccSSepherosa Ziehau if (error) { 40930a806e3aSSepherosa Ziehau device_printf(dev, 40940a806e3aSSepherosa Ziehau "could not create %dth status block\n", i); 40956c8d8eccSSepherosa Ziehau return error; 40966c8d8eccSSepherosa Ziehau } 40970a806e3aSSepherosa Ziehau } 4098695a8586SSepherosa Ziehau sc->bnx_hw_status = &sc->bnx_intr_data[0].bnx_status_block->bge_status; 4099695a8586SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_STATUS_HASTAG) { 4100695a8586SSepherosa Ziehau sc->bnx_hw_status_tag = 4101695a8586SSepherosa Ziehau &sc->bnx_intr_data[0].bnx_status_block->bge_status_tag; 4102695a8586SSepherosa Ziehau } 41036c8d8eccSSepherosa Ziehau 4104beedf5beSSepherosa Ziehau /* 4105beedf5beSSepherosa Ziehau * Create DMA tag and maps for RX mbufs. 4106beedf5beSSepherosa Ziehau */ 4107beedf5beSSepherosa Ziehau std->bnx_sc = sc; 4108329f9016SSepherosa Ziehau lwkt_serialize_init(&std->bnx_rx_std_serialize); 4109beedf5beSSepherosa Ziehau error = bus_dma_tag_create(sc->bnx_cdata.bnx_parent_tag, 1, 0, 4110beedf5beSSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 4111beedf5beSSepherosa Ziehau NULL, NULL, MCLBYTES, 1, MCLBYTES, 4112beedf5beSSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK, &std->bnx_rx_mtag); 4113beedf5beSSepherosa Ziehau if (error) { 4114beedf5beSSepherosa Ziehau device_printf(dev, "could not create RX mbuf DMA tag\n"); 4115beedf5beSSepherosa Ziehau return error; 4116beedf5beSSepherosa Ziehau } 4117beedf5beSSepherosa Ziehau 4118beedf5beSSepherosa Ziehau for (i = 0; i < BGE_STD_RX_RING_CNT; ++i) { 4119beedf5beSSepherosa Ziehau error = bus_dmamap_create(std->bnx_rx_mtag, BUS_DMA_WAITOK, 4120beedf5beSSepherosa Ziehau &std->bnx_rx_std_buf[i].bnx_rx_dmamap); 4121beedf5beSSepherosa Ziehau if (error) { 4122beedf5beSSepherosa Ziehau int j; 4123beedf5beSSepherosa Ziehau 4124beedf5beSSepherosa Ziehau for (j = 0; j < i; ++j) { 4125beedf5beSSepherosa Ziehau bus_dmamap_destroy(std->bnx_rx_mtag, 4126beedf5beSSepherosa Ziehau std->bnx_rx_std_buf[j].bnx_rx_dmamap); 4127beedf5beSSepherosa Ziehau } 4128beedf5beSSepherosa Ziehau bus_dma_tag_destroy(std->bnx_rx_mtag); 4129beedf5beSSepherosa Ziehau std->bnx_rx_mtag = NULL; 4130beedf5beSSepherosa Ziehau 4131beedf5beSSepherosa Ziehau device_printf(dev, 4132beedf5beSSepherosa Ziehau "could not create %dth RX mbuf DMA map\n", i); 4133beedf5beSSepherosa Ziehau return error; 4134beedf5beSSepherosa Ziehau } 4135beedf5beSSepherosa Ziehau } 4136beedf5beSSepherosa Ziehau 4137beedf5beSSepherosa Ziehau /* 4138beedf5beSSepherosa Ziehau * Create DMA stuffs for standard RX ring. 4139beedf5beSSepherosa Ziehau */ 4140beedf5beSSepherosa Ziehau error = bnx_dma_block_alloc(sc, BGE_STD_RX_RING_SZ, 4141beedf5beSSepherosa Ziehau &std->bnx_rx_std_ring_tag, 4142beedf5beSSepherosa Ziehau &std->bnx_rx_std_ring_map, 4143beedf5beSSepherosa Ziehau (void *)&std->bnx_rx_std_ring, 4144beedf5beSSepherosa Ziehau &std->bnx_rx_std_ring_paddr); 4145beedf5beSSepherosa Ziehau if (error) { 4146beedf5beSSepherosa Ziehau device_printf(dev, "could not create std RX ring\n"); 4147beedf5beSSepherosa Ziehau return error; 4148beedf5beSSepherosa Ziehau } 4149beedf5beSSepherosa Ziehau 4150beedf5beSSepherosa Ziehau /* 4151beedf5beSSepherosa Ziehau * Create RX return rings 4152beedf5beSSepherosa Ziehau */ 4153ac2936fdSSepherosa Ziehau mbx = BGE_MBX_RX_CONS0_LO; 4154beedf5beSSepherosa Ziehau sc->bnx_rx_ret_ring = kmalloc_cachealign( 4155beedf5beSSepherosa Ziehau sizeof(struct bnx_rx_ret_ring) * sc->bnx_rx_retcnt, M_DEVBUF, 4156beedf5beSSepherosa Ziehau M_WAITOK | M_ZERO); 4157beedf5beSSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 4158beedf5beSSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[i]; 41590a806e3aSSepherosa Ziehau struct bnx_intr_data *intr; 4160beedf5beSSepherosa Ziehau 4161beedf5beSSepherosa Ziehau ret->bnx_sc = sc; 4162beedf5beSSepherosa Ziehau ret->bnx_std = std; 4163ac2936fdSSepherosa Ziehau ret->bnx_rx_mbx = mbx; 4164841cdf08SSepherosa Ziehau ret->bnx_rx_cntmax = (BGE_STD_RX_RING_CNT / 4) / 4165841cdf08SSepherosa Ziehau sc->bnx_rx_retcnt; 4166841cdf08SSepherosa Ziehau ret->bnx_rx_mask = 1 << i; 41673a16b7b8SSepherosa Ziehau 4168695a8586SSepherosa Ziehau if (!BNX_RSS_ENABLED(sc)) { 41690a806e3aSSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 41700a806e3aSSepherosa Ziehau } else { 41710a806e3aSSepherosa Ziehau KKASSERT(i + 1 < sc->bnx_intr_cnt); 41720a806e3aSSepherosa Ziehau intr = &sc->bnx_intr_data[i + 1]; 41730a806e3aSSepherosa Ziehau } 41740a806e3aSSepherosa Ziehau 4175695a8586SSepherosa Ziehau if (i == 0) { 41763a16b7b8SSepherosa Ziehau ret->bnx_rx_considx = 41770a806e3aSSepherosa Ziehau &intr->bnx_status_block->bge_idx[0].bge_rx_prod_idx; 4178695a8586SSepherosa Ziehau } else if (i == 1) { 4179695a8586SSepherosa Ziehau ret->bnx_rx_considx = 4180695a8586SSepherosa Ziehau &intr->bnx_status_block->bge_rx_jumbo_cons_idx; 4181695a8586SSepherosa Ziehau } else if (i == 2) { 4182695a8586SSepherosa Ziehau ret->bnx_rx_considx = 4183695a8586SSepherosa Ziehau &intr->bnx_status_block->bge_rsvd1; 4184695a8586SSepherosa Ziehau } else if (i == 3) { 4185695a8586SSepherosa Ziehau ret->bnx_rx_considx = 4186695a8586SSepherosa Ziehau &intr->bnx_status_block->bge_rx_mini_cons_idx; 4187695a8586SSepherosa Ziehau } else { 4188695a8586SSepherosa Ziehau panic("unknown RX return ring %d\n", i); 4189695a8586SSepherosa Ziehau } 41904fa38985SSepherosa Ziehau ret->bnx_hw_status_tag = 41910a806e3aSSepherosa Ziehau &intr->bnx_status_block->bge_status_tag; 41923a16b7b8SSepherosa Ziehau 4193beedf5beSSepherosa Ziehau error = bnx_create_rx_ret_ring(ret); 4194beedf5beSSepherosa Ziehau if (error) { 4195beedf5beSSepherosa Ziehau device_printf(dev, 4196beedf5beSSepherosa Ziehau "could not create %dth RX ret ring\n", i); 4197beedf5beSSepherosa Ziehau return error; 4198beedf5beSSepherosa Ziehau } 4199ac2936fdSSepherosa Ziehau mbx += 8; 4200beedf5beSSepherosa Ziehau } 4201beedf5beSSepherosa Ziehau 4202beedf5beSSepherosa Ziehau /* 4203beedf5beSSepherosa Ziehau * Create TX rings 4204beedf5beSSepherosa Ziehau */ 420533a04907SSepherosa Ziehau sc->bnx_tx_ring = kmalloc_cachealign( 420633a04907SSepherosa Ziehau sizeof(struct bnx_tx_ring) * sc->bnx_tx_ringcnt, M_DEVBUF, 420733a04907SSepherosa Ziehau M_WAITOK | M_ZERO); 420833a04907SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 420933a04907SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 42100a806e3aSSepherosa Ziehau struct bnx_intr_data *intr; 421133a04907SSepherosa Ziehau 421233a04907SSepherosa Ziehau txr->bnx_sc = sc; 42131c9d03f6SSepherosa Ziehau txr->bnx_tx_mbx = bnx_tx_mailbox[i]; 42148bd43d5dSSepherosa Ziehau 42150a806e3aSSepherosa Ziehau if (sc->bnx_tx_ringcnt == 1) { 42160a806e3aSSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 42170a806e3aSSepherosa Ziehau } else { 42180a806e3aSSepherosa Ziehau KKASSERT(i + 1 < sc->bnx_intr_cnt); 42190a806e3aSSepherosa Ziehau intr = &sc->bnx_intr_data[i + 1]; 42200a806e3aSSepherosa Ziehau } 42210a806e3aSSepherosa Ziehau 4222695a8586SSepherosa Ziehau if ((sc->bnx_flags & BNX_FLAG_RXTX_BUNDLE) == 0) { 4223695a8586SSepherosa Ziehau txr->bnx_hw_status_tag = 4224695a8586SSepherosa Ziehau &intr->bnx_status_block->bge_status_tag; 4225695a8586SSepherosa Ziehau } 42263a16b7b8SSepherosa Ziehau txr->bnx_tx_considx = 42270a806e3aSSepherosa Ziehau &intr->bnx_status_block->bge_idx[0].bge_tx_cons_idx; 42283a16b7b8SSepherosa Ziehau 422933a04907SSepherosa Ziehau error = bnx_create_tx_ring(txr); 423033a04907SSepherosa Ziehau if (error) { 4231beedf5beSSepherosa Ziehau device_printf(dev, 4232beedf5beSSepherosa Ziehau "could not create %dth TX ring\n", i); 4233beedf5beSSepherosa Ziehau return error; 4234beedf5beSSepherosa Ziehau } 4235beedf5beSSepherosa Ziehau } 4236beedf5beSSepherosa Ziehau 4237beedf5beSSepherosa Ziehau /* 4238beedf5beSSepherosa Ziehau * Create jumbo buffer pool. 4239beedf5beSSepherosa Ziehau */ 4240beedf5beSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) { 4241beedf5beSSepherosa Ziehau error = bnx_alloc_jumbo_mem(sc); 4242beedf5beSSepherosa Ziehau if (error) { 4243beedf5beSSepherosa Ziehau device_printf(dev, 4244beedf5beSSepherosa Ziehau "could not create jumbo buffer pool\n"); 424533a04907SSepherosa Ziehau return error; 424633a04907SSepherosa Ziehau } 424733a04907SSepherosa Ziehau } 424833a04907SSepherosa Ziehau 42496c8d8eccSSepherosa Ziehau return 0; 42506c8d8eccSSepherosa Ziehau } 42516c8d8eccSSepherosa Ziehau 42526c8d8eccSSepherosa Ziehau static int 42536c8d8eccSSepherosa Ziehau bnx_dma_block_alloc(struct bnx_softc *sc, bus_size_t size, bus_dma_tag_t *tag, 42546c8d8eccSSepherosa Ziehau bus_dmamap_t *map, void **addr, bus_addr_t *paddr) 42556c8d8eccSSepherosa Ziehau { 42566c8d8eccSSepherosa Ziehau bus_dmamem_t dmem; 42576c8d8eccSSepherosa Ziehau int error; 42586c8d8eccSSepherosa Ziehau 42596c8d8eccSSepherosa Ziehau error = bus_dmamem_coherent(sc->bnx_cdata.bnx_parent_tag, PAGE_SIZE, 0, 42606c8d8eccSSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 42616c8d8eccSSepherosa Ziehau size, BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmem); 42626c8d8eccSSepherosa Ziehau if (error) 42636c8d8eccSSepherosa Ziehau return error; 42646c8d8eccSSepherosa Ziehau 42656c8d8eccSSepherosa Ziehau *tag = dmem.dmem_tag; 42666c8d8eccSSepherosa Ziehau *map = dmem.dmem_map; 42676c8d8eccSSepherosa Ziehau *addr = dmem.dmem_addr; 42686c8d8eccSSepherosa Ziehau *paddr = dmem.dmem_busaddr; 42696c8d8eccSSepherosa Ziehau 42706c8d8eccSSepherosa Ziehau return 0; 42716c8d8eccSSepherosa Ziehau } 42726c8d8eccSSepherosa Ziehau 42736c8d8eccSSepherosa Ziehau static void 42746c8d8eccSSepherosa Ziehau bnx_dma_block_free(bus_dma_tag_t tag, bus_dmamap_t map, void *addr) 42756c8d8eccSSepherosa Ziehau { 42766c8d8eccSSepherosa Ziehau if (tag != NULL) { 42776c8d8eccSSepherosa Ziehau bus_dmamap_unload(tag, map); 42786c8d8eccSSepherosa Ziehau bus_dmamem_free(tag, addr, map); 42796c8d8eccSSepherosa Ziehau bus_dma_tag_destroy(tag); 42806c8d8eccSSepherosa Ziehau } 42816c8d8eccSSepherosa Ziehau } 42826c8d8eccSSepherosa Ziehau 42836c8d8eccSSepherosa Ziehau static void 42846c8d8eccSSepherosa Ziehau bnx_tbi_link_upd(struct bnx_softc *sc, uint32_t status) 42856c8d8eccSSepherosa Ziehau { 42866c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 42876c8d8eccSSepherosa Ziehau 42886c8d8eccSSepherosa Ziehau #define PCS_ENCODE_ERR (BGE_MACSTAT_PORT_DECODE_ERROR|BGE_MACSTAT_MI_COMPLETE) 42896c8d8eccSSepherosa Ziehau 42906c8d8eccSSepherosa Ziehau /* 42916c8d8eccSSepherosa Ziehau * Sometimes PCS encoding errors are detected in 42926c8d8eccSSepherosa Ziehau * TBI mode (on fiber NICs), and for some reason 42936c8d8eccSSepherosa Ziehau * the chip will signal them as link changes. 42946c8d8eccSSepherosa Ziehau * If we get a link change event, but the 'PCS 42956c8d8eccSSepherosa Ziehau * encoding error' bit in the MAC status register 42966c8d8eccSSepherosa Ziehau * is set, don't bother doing a link check. 42976c8d8eccSSepherosa Ziehau * This avoids spurious "gigabit link up" messages 42986c8d8eccSSepherosa Ziehau * that sometimes appear on fiber NICs during 42996c8d8eccSSepherosa Ziehau * periods of heavy traffic. 43006c8d8eccSSepherosa Ziehau */ 43016c8d8eccSSepherosa Ziehau if (status & BGE_MACSTAT_TBI_PCS_SYNCHED) { 43026c8d8eccSSepherosa Ziehau if (!sc->bnx_link) { 43036c8d8eccSSepherosa Ziehau sc->bnx_link++; 43046c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5704) { 43056c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_MAC_MODE, 43066c8d8eccSSepherosa Ziehau BGE_MACMODE_TBI_SEND_CFGS); 43076c8d8eccSSepherosa Ziehau } 43086c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, 0xFFFFFFFF); 43096c8d8eccSSepherosa Ziehau 43106c8d8eccSSepherosa Ziehau if (bootverbose) 43116c8d8eccSSepherosa Ziehau if_printf(ifp, "link UP\n"); 43126c8d8eccSSepherosa Ziehau 43136c8d8eccSSepherosa Ziehau ifp->if_link_state = LINK_STATE_UP; 43146c8d8eccSSepherosa Ziehau if_link_state_change(ifp); 43156c8d8eccSSepherosa Ziehau } 43166c8d8eccSSepherosa Ziehau } else if ((status & PCS_ENCODE_ERR) != PCS_ENCODE_ERR) { 43176c8d8eccSSepherosa Ziehau if (sc->bnx_link) { 43186c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 43196c8d8eccSSepherosa Ziehau 43206c8d8eccSSepherosa Ziehau if (bootverbose) 43216c8d8eccSSepherosa Ziehau if_printf(ifp, "link DOWN\n"); 43226c8d8eccSSepherosa Ziehau 43236c8d8eccSSepherosa Ziehau ifp->if_link_state = LINK_STATE_DOWN; 43246c8d8eccSSepherosa Ziehau if_link_state_change(ifp); 43256c8d8eccSSepherosa Ziehau } 43266c8d8eccSSepherosa Ziehau } 43276c8d8eccSSepherosa Ziehau 43286c8d8eccSSepherosa Ziehau #undef PCS_ENCODE_ERR 43296c8d8eccSSepherosa Ziehau 43306c8d8eccSSepherosa Ziehau /* Clear the attention. */ 43316c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED | 43326c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED | BGE_MACSTAT_MI_COMPLETE | 43336c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 43346c8d8eccSSepherosa Ziehau } 43356c8d8eccSSepherosa Ziehau 43366c8d8eccSSepherosa Ziehau static void 43376c8d8eccSSepherosa Ziehau bnx_copper_link_upd(struct bnx_softc *sc, uint32_t status __unused) 43386c8d8eccSSepherosa Ziehau { 43396c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 43406c8d8eccSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->bnx_miibus); 43416c8d8eccSSepherosa Ziehau 43426c8d8eccSSepherosa Ziehau mii_pollstat(mii); 43436c8d8eccSSepherosa Ziehau bnx_miibus_statchg(sc->bnx_dev); 43446c8d8eccSSepherosa Ziehau 43456c8d8eccSSepherosa Ziehau if (bootverbose) { 43466c8d8eccSSepherosa Ziehau if (sc->bnx_link) 43476c8d8eccSSepherosa Ziehau if_printf(ifp, "link UP\n"); 43486c8d8eccSSepherosa Ziehau else 43496c8d8eccSSepherosa Ziehau if_printf(ifp, "link DOWN\n"); 43506c8d8eccSSepherosa Ziehau } 43516c8d8eccSSepherosa Ziehau 43526c8d8eccSSepherosa Ziehau /* Clear the attention. */ 43536c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED | 43546c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED | BGE_MACSTAT_MI_COMPLETE | 43556c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 43566c8d8eccSSepherosa Ziehau } 43576c8d8eccSSepherosa Ziehau 43586c8d8eccSSepherosa Ziehau static void 43596c8d8eccSSepherosa Ziehau bnx_autopoll_link_upd(struct bnx_softc *sc, uint32_t status __unused) 43606c8d8eccSSepherosa Ziehau { 43616c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 43626c8d8eccSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->bnx_miibus); 43636c8d8eccSSepherosa Ziehau 43646c8d8eccSSepherosa Ziehau mii_pollstat(mii); 43656c8d8eccSSepherosa Ziehau 43666c8d8eccSSepherosa Ziehau if (!sc->bnx_link && 43676c8d8eccSSepherosa Ziehau (mii->mii_media_status & IFM_ACTIVE) && 43686c8d8eccSSepherosa Ziehau IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 43696c8d8eccSSepherosa Ziehau sc->bnx_link++; 43706c8d8eccSSepherosa Ziehau if (bootverbose) 43716c8d8eccSSepherosa Ziehau if_printf(ifp, "link UP\n"); 43726c8d8eccSSepherosa Ziehau } else if (sc->bnx_link && 43736c8d8eccSSepherosa Ziehau (!(mii->mii_media_status & IFM_ACTIVE) || 43746c8d8eccSSepherosa Ziehau IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE)) { 43756c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 43766c8d8eccSSepherosa Ziehau if (bootverbose) 43776c8d8eccSSepherosa Ziehau if_printf(ifp, "link DOWN\n"); 43786c8d8eccSSepherosa Ziehau } 43796c8d8eccSSepherosa Ziehau 43806c8d8eccSSepherosa Ziehau /* Clear the attention. */ 43816c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED | 43826c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED | BGE_MACSTAT_MI_COMPLETE | 43836c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 43846c8d8eccSSepherosa Ziehau } 43856c8d8eccSSepherosa Ziehau 43866c8d8eccSSepherosa Ziehau static int 43876c8d8eccSSepherosa Ziehau bnx_sysctl_rx_coal_ticks(SYSCTL_HANDLER_ARGS) 43886c8d8eccSSepherosa Ziehau { 43896c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 43906c8d8eccSSepherosa Ziehau 43916c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 43926c8d8eccSSepherosa Ziehau &sc->bnx_rx_coal_ticks, 43936c8d8eccSSepherosa Ziehau BNX_RX_COAL_TICKS_MIN, BNX_RX_COAL_TICKS_MAX, 43946c8d8eccSSepherosa Ziehau BNX_RX_COAL_TICKS_CHG); 43956c8d8eccSSepherosa Ziehau } 43966c8d8eccSSepherosa Ziehau 43976c8d8eccSSepherosa Ziehau static int 43986c8d8eccSSepherosa Ziehau bnx_sysctl_tx_coal_ticks(SYSCTL_HANDLER_ARGS) 43996c8d8eccSSepherosa Ziehau { 44006c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44016c8d8eccSSepherosa Ziehau 44026c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44036c8d8eccSSepherosa Ziehau &sc->bnx_tx_coal_ticks, 44046c8d8eccSSepherosa Ziehau BNX_TX_COAL_TICKS_MIN, BNX_TX_COAL_TICKS_MAX, 44056c8d8eccSSepherosa Ziehau BNX_TX_COAL_TICKS_CHG); 44066c8d8eccSSepherosa Ziehau } 44076c8d8eccSSepherosa Ziehau 44086c8d8eccSSepherosa Ziehau static int 44096c8d8eccSSepherosa Ziehau bnx_sysctl_rx_coal_bds(SYSCTL_HANDLER_ARGS) 44106c8d8eccSSepherosa Ziehau { 44116c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44126c8d8eccSSepherosa Ziehau 44136c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44146c8d8eccSSepherosa Ziehau &sc->bnx_rx_coal_bds, 44156c8d8eccSSepherosa Ziehau BNX_RX_COAL_BDS_MIN, BNX_RX_COAL_BDS_MAX, 44166c8d8eccSSepherosa Ziehau BNX_RX_COAL_BDS_CHG); 44176c8d8eccSSepherosa Ziehau } 44186c8d8eccSSepherosa Ziehau 44196c8d8eccSSepherosa Ziehau static int 4420a86cc105SSepherosa Ziehau bnx_sysctl_rx_coal_bds_poll(SYSCTL_HANDLER_ARGS) 4421a86cc105SSepherosa Ziehau { 4422a86cc105SSepherosa Ziehau struct bnx_softc *sc = arg1; 4423a86cc105SSepherosa Ziehau 4424a86cc105SSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 4425a86cc105SSepherosa Ziehau &sc->bnx_rx_coal_bds_poll, 4426a86cc105SSepherosa Ziehau BNX_RX_COAL_BDS_MIN, BNX_RX_COAL_BDS_MAX, 4427a86cc105SSepherosa Ziehau BNX_RX_COAL_BDS_CHG); 4428a86cc105SSepherosa Ziehau } 4429a86cc105SSepherosa Ziehau 4430a86cc105SSepherosa Ziehau static int 44316c8d8eccSSepherosa Ziehau bnx_sysctl_tx_coal_bds(SYSCTL_HANDLER_ARGS) 44326c8d8eccSSepherosa Ziehau { 44336c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44346c8d8eccSSepherosa Ziehau 44356c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44366c8d8eccSSepherosa Ziehau &sc->bnx_tx_coal_bds, 44376c8d8eccSSepherosa Ziehau BNX_TX_COAL_BDS_MIN, BNX_TX_COAL_BDS_MAX, 44386c8d8eccSSepherosa Ziehau BNX_TX_COAL_BDS_CHG); 44396c8d8eccSSepherosa Ziehau } 44406c8d8eccSSepherosa Ziehau 44416c8d8eccSSepherosa Ziehau static int 444227357d84SSepherosa Ziehau bnx_sysctl_tx_coal_bds_poll(SYSCTL_HANDLER_ARGS) 444327357d84SSepherosa Ziehau { 444427357d84SSepherosa Ziehau struct bnx_softc *sc = arg1; 444527357d84SSepherosa Ziehau 444627357d84SSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 444727357d84SSepherosa Ziehau &sc->bnx_tx_coal_bds_poll, 444827357d84SSepherosa Ziehau BNX_TX_COAL_BDS_MIN, BNX_TX_COAL_BDS_MAX, 444927357d84SSepherosa Ziehau BNX_TX_COAL_BDS_CHG); 445027357d84SSepherosa Ziehau } 445127357d84SSepherosa Ziehau 445227357d84SSepherosa Ziehau static int 44536c8d8eccSSepherosa Ziehau bnx_sysctl_rx_coal_bds_int(SYSCTL_HANDLER_ARGS) 44546c8d8eccSSepherosa Ziehau { 44556c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44566c8d8eccSSepherosa Ziehau 44576c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44586c8d8eccSSepherosa Ziehau &sc->bnx_rx_coal_bds_int, 44596c8d8eccSSepherosa Ziehau BNX_RX_COAL_BDS_MIN, BNX_RX_COAL_BDS_MAX, 44606c8d8eccSSepherosa Ziehau BNX_RX_COAL_BDS_INT_CHG); 44616c8d8eccSSepherosa Ziehau } 44626c8d8eccSSepherosa Ziehau 44636c8d8eccSSepherosa Ziehau static int 44646c8d8eccSSepherosa Ziehau bnx_sysctl_tx_coal_bds_int(SYSCTL_HANDLER_ARGS) 44656c8d8eccSSepherosa Ziehau { 44666c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44676c8d8eccSSepherosa Ziehau 44686c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44696c8d8eccSSepherosa Ziehau &sc->bnx_tx_coal_bds_int, 44706c8d8eccSSepherosa Ziehau BNX_TX_COAL_BDS_MIN, BNX_TX_COAL_BDS_MAX, 44716c8d8eccSSepherosa Ziehau BNX_TX_COAL_BDS_INT_CHG); 44726c8d8eccSSepherosa Ziehau } 44736c8d8eccSSepherosa Ziehau 44746c8d8eccSSepherosa Ziehau static int 44756c8d8eccSSepherosa Ziehau bnx_sysctl_coal_chg(SYSCTL_HANDLER_ARGS, uint32_t *coal, 44766c8d8eccSSepherosa Ziehau int coal_min, int coal_max, uint32_t coal_chg_mask) 44776c8d8eccSSepherosa Ziehau { 44786c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44796c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 44806c8d8eccSSepherosa Ziehau int error = 0, v; 44816c8d8eccSSepherosa Ziehau 4482329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 44836c8d8eccSSepherosa Ziehau 44846c8d8eccSSepherosa Ziehau v = *coal; 44856c8d8eccSSepherosa Ziehau error = sysctl_handle_int(oidp, &v, 0, req); 44866c8d8eccSSepherosa Ziehau if (!error && req->newptr != NULL) { 44876c8d8eccSSepherosa Ziehau if (v < coal_min || v > coal_max) { 44886c8d8eccSSepherosa Ziehau error = EINVAL; 44896c8d8eccSSepherosa Ziehau } else { 44906c8d8eccSSepherosa Ziehau *coal = v; 44916c8d8eccSSepherosa Ziehau sc->bnx_coal_chg |= coal_chg_mask; 4492f5014362SSepherosa Ziehau 4493f5014362SSepherosa Ziehau /* Commit changes */ 4494f5014362SSepherosa Ziehau bnx_coal_change(sc); 44956c8d8eccSSepherosa Ziehau } 44966c8d8eccSSepherosa Ziehau } 44976c8d8eccSSepherosa Ziehau 4498329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 44996c8d8eccSSepherosa Ziehau return error; 45006c8d8eccSSepherosa Ziehau } 45016c8d8eccSSepherosa Ziehau 45026c8d8eccSSepherosa Ziehau static void 45036c8d8eccSSepherosa Ziehau bnx_coal_change(struct bnx_softc *sc) 45046c8d8eccSSepherosa Ziehau { 45056c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 4506695a8586SSepherosa Ziehau int i; 45076c8d8eccSSepherosa Ziehau 4508329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 45096c8d8eccSSepherosa Ziehau 45106c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_RX_COAL_TICKS_CHG) { 4511695a8586SSepherosa Ziehau if (sc->bnx_rx_retcnt == 1) { 45126c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, 45136c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_ticks); 4514695a8586SSepherosa Ziehau i = 0; 4515695a8586SSepherosa Ziehau } else { 4516695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, 0); 4517695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 4518695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_COAL_TICKS + 4519695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 4520695a8586SSepherosa Ziehau sc->bnx_rx_coal_ticks); 4521695a8586SSepherosa Ziehau } 4522695a8586SSepherosa Ziehau } 4523695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4524695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_COAL_TICKS + 4525695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4526695a8586SSepherosa Ziehau } 45276c8d8eccSSepherosa Ziehau if (bootverbose) { 45286c8d8eccSSepherosa Ziehau if_printf(ifp, "rx_coal_ticks -> %u\n", 45296c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_ticks); 45306c8d8eccSSepherosa Ziehau } 45316c8d8eccSSepherosa Ziehau } 45326c8d8eccSSepherosa Ziehau 45336c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_TX_COAL_TICKS_CHG) { 4534695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt == 1) { 45356c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS, 45366c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_ticks); 4537695a8586SSepherosa Ziehau i = 0; 4538695a8586SSepherosa Ziehau } else { 4539695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS, 0); 4540695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 4541695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_COAL_TICKS + 4542695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 4543695a8586SSepherosa Ziehau sc->bnx_tx_coal_ticks); 4544695a8586SSepherosa Ziehau } 4545695a8586SSepherosa Ziehau } 4546695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4547695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_COAL_TICKS + 4548695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4549695a8586SSepherosa Ziehau } 45506c8d8eccSSepherosa Ziehau if (bootverbose) { 45516c8d8eccSSepherosa Ziehau if_printf(ifp, "tx_coal_ticks -> %u\n", 45526c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_ticks); 45536c8d8eccSSepherosa Ziehau } 45546c8d8eccSSepherosa Ziehau } 45556c8d8eccSSepherosa Ziehau 45566c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_RX_COAL_BDS_CHG) { 4557a86cc105SSepherosa Ziehau uint32_t rx_coal_bds; 4558a86cc105SSepherosa Ziehau 4559a86cc105SSepherosa Ziehau if (ifp->if_flags & IFF_NPOLLING) 4560a86cc105SSepherosa Ziehau rx_coal_bds = sc->bnx_rx_coal_bds_poll; 4561a86cc105SSepherosa Ziehau else 4562a86cc105SSepherosa Ziehau rx_coal_bds = sc->bnx_rx_coal_bds; 4563a86cc105SSepherosa Ziehau 4564695a8586SSepherosa Ziehau if (sc->bnx_rx_retcnt == 1) { 4565a86cc105SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, rx_coal_bds); 4566695a8586SSepherosa Ziehau i = 0; 4567695a8586SSepherosa Ziehau } else { 4568695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, 0); 4569695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 4570695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_MAX_COAL_BDS + 4571a86cc105SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), rx_coal_bds); 4572695a8586SSepherosa Ziehau } 4573695a8586SSepherosa Ziehau } 4574695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4575695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_MAX_COAL_BDS + 4576695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4577695a8586SSepherosa Ziehau } 45786c8d8eccSSepherosa Ziehau if (bootverbose) { 4579a86cc105SSepherosa Ziehau if_printf(ifp, "%srx_coal_bds -> %u\n", 4580a86cc105SSepherosa Ziehau (ifp->if_flags & IFF_NPOLLING) ? "polling " : "", 4581a86cc105SSepherosa Ziehau rx_coal_bds); 45826c8d8eccSSepherosa Ziehau } 45836c8d8eccSSepherosa Ziehau } 45846c8d8eccSSepherosa Ziehau 45856c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_TX_COAL_BDS_CHG) { 458627357d84SSepherosa Ziehau uint32_t tx_coal_bds; 458727357d84SSepherosa Ziehau 458827357d84SSepherosa Ziehau if (ifp->if_flags & IFF_NPOLLING) 458927357d84SSepherosa Ziehau tx_coal_bds = sc->bnx_tx_coal_bds_poll; 459027357d84SSepherosa Ziehau else 459127357d84SSepherosa Ziehau tx_coal_bds = sc->bnx_tx_coal_bds; 459227357d84SSepherosa Ziehau 4593695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt == 1) { 459427357d84SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS, tx_coal_bds); 4595695a8586SSepherosa Ziehau i = 0; 4596695a8586SSepherosa Ziehau } else { 4597695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS, 0); 4598695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 4599695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_MAX_COAL_BDS + 460027357d84SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), tx_coal_bds); 4601695a8586SSepherosa Ziehau } 4602695a8586SSepherosa Ziehau } 4603695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4604695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_MAX_COAL_BDS + 4605695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4606695a8586SSepherosa Ziehau } 46076c8d8eccSSepherosa Ziehau if (bootverbose) { 460827357d84SSepherosa Ziehau if_printf(ifp, "%stx_coal_bds -> %u\n", 460927357d84SSepherosa Ziehau (ifp->if_flags & IFF_NPOLLING) ? "polling " : "", 461027357d84SSepherosa Ziehau tx_coal_bds); 46116c8d8eccSSepherosa Ziehau } 46126c8d8eccSSepherosa Ziehau } 46136c8d8eccSSepherosa Ziehau 46146c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_RX_COAL_BDS_INT_CHG) { 4615695a8586SSepherosa Ziehau if (sc->bnx_rx_retcnt == 1) { 46166c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 46176c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_bds_int); 4618695a8586SSepherosa Ziehau i = 0; 4619695a8586SSepherosa Ziehau } else { 4620695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 0); 4621695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 4622695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_MAX_COAL_BDS_INT + 4623695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 4624695a8586SSepherosa Ziehau sc->bnx_rx_coal_bds_int); 4625695a8586SSepherosa Ziehau } 4626695a8586SSepherosa Ziehau } 4627695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4628695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_MAX_COAL_BDS_INT + 4629695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4630695a8586SSepherosa Ziehau } 46316c8d8eccSSepherosa Ziehau if (bootverbose) { 46326c8d8eccSSepherosa Ziehau if_printf(ifp, "rx_coal_bds_int -> %u\n", 46336c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_bds_int); 46346c8d8eccSSepherosa Ziehau } 46356c8d8eccSSepherosa Ziehau } 46366c8d8eccSSepherosa Ziehau 46376c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_TX_COAL_BDS_INT_CHG) { 4638695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt == 1) { 46396c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 46406c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_bds_int); 4641695a8586SSepherosa Ziehau i = 0; 4642695a8586SSepherosa Ziehau } else { 4643695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 0); 4644695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 4645695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_MAX_COAL_BDS_INT + 4646695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 4647695a8586SSepherosa Ziehau sc->bnx_tx_coal_bds_int); 4648695a8586SSepherosa Ziehau } 4649695a8586SSepherosa Ziehau } 4650695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4651695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_MAX_COAL_BDS_INT + 4652695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4653695a8586SSepherosa Ziehau } 46546c8d8eccSSepherosa Ziehau if (bootverbose) { 46556c8d8eccSSepherosa Ziehau if_printf(ifp, "tx_coal_bds_int -> %u\n", 46566c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_bds_int); 46576c8d8eccSSepherosa Ziehau } 46586c8d8eccSSepherosa Ziehau } 46596c8d8eccSSepherosa Ziehau 46606c8d8eccSSepherosa Ziehau sc->bnx_coal_chg = 0; 46616c8d8eccSSepherosa Ziehau } 46626c8d8eccSSepherosa Ziehau 46636c8d8eccSSepherosa Ziehau static void 4664695a8586SSepherosa Ziehau bnx_check_intr_rxtx(void *xintr) 4665df9ccc98SSepherosa Ziehau { 4666f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr = xintr; 4667f33ac8a4SSepherosa Ziehau struct bnx_rx_ret_ring *ret; 4668f33ac8a4SSepherosa Ziehau struct bnx_tx_ring *txr; 4669f33ac8a4SSepherosa Ziehau struct ifnet *ifp; 4670df9ccc98SSepherosa Ziehau 4671f33ac8a4SSepherosa Ziehau lwkt_serialize_enter(intr->bnx_intr_serialize); 4672df9ccc98SSepherosa Ziehau 4673f33ac8a4SSepherosa Ziehau KKASSERT(mycpuid == intr->bnx_intr_cpuid); 4674df9ccc98SSepherosa Ziehau 4675f33ac8a4SSepherosa Ziehau ifp = &intr->bnx_sc->arpcom.ac_if; 467639a8d43aSSepherosa Ziehau if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) != IFF_RUNNING) { 4677f33ac8a4SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4678df9ccc98SSepherosa Ziehau return; 4679df9ccc98SSepherosa Ziehau } 4680df9ccc98SSepherosa Ziehau 4681f33ac8a4SSepherosa Ziehau txr = intr->bnx_txr; 4682f33ac8a4SSepherosa Ziehau ret = intr->bnx_ret; 4683f33ac8a4SSepherosa Ziehau 46843a16b7b8SSepherosa Ziehau if (*ret->bnx_rx_considx != ret->bnx_rx_saved_considx || 46853a16b7b8SSepherosa Ziehau *txr->bnx_tx_considx != txr->bnx_tx_saved_considx) { 4686f33ac8a4SSepherosa Ziehau if (intr->bnx_rx_check_considx == ret->bnx_rx_saved_considx && 4687f33ac8a4SSepherosa Ziehau intr->bnx_tx_check_considx == txr->bnx_tx_saved_considx) { 4688f33ac8a4SSepherosa Ziehau if (!intr->bnx_intr_maylose) { 4689f33ac8a4SSepherosa Ziehau intr->bnx_intr_maylose = TRUE; 4690df9ccc98SSepherosa Ziehau goto done; 4691df9ccc98SSepherosa Ziehau } 4692df9ccc98SSepherosa Ziehau if (bootverbose) 4693df9ccc98SSepherosa Ziehau if_printf(ifp, "lost interrupt\n"); 4694f33ac8a4SSepherosa Ziehau intr->bnx_intr_func(intr->bnx_intr_arg); 4695df9ccc98SSepherosa Ziehau } 4696df9ccc98SSepherosa Ziehau } 4697f33ac8a4SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4698f33ac8a4SSepherosa Ziehau intr->bnx_rx_check_considx = ret->bnx_rx_saved_considx; 4699f33ac8a4SSepherosa Ziehau intr->bnx_tx_check_considx = txr->bnx_tx_saved_considx; 4700df9ccc98SSepherosa Ziehau 4701df9ccc98SSepherosa Ziehau done: 4702f33ac8a4SSepherosa Ziehau callout_reset(&intr->bnx_intr_timer, BNX_INTR_CKINTVL, 4703f33ac8a4SSepherosa Ziehau intr->bnx_intr_check, intr); 4704f33ac8a4SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4705df9ccc98SSepherosa Ziehau } 4706df9ccc98SSepherosa Ziehau 4707df9ccc98SSepherosa Ziehau static void 4708695a8586SSepherosa Ziehau bnx_check_intr_tx(void *xintr) 4709695a8586SSepherosa Ziehau { 4710695a8586SSepherosa Ziehau struct bnx_intr_data *intr = xintr; 4711695a8586SSepherosa Ziehau struct bnx_tx_ring *txr; 4712695a8586SSepherosa Ziehau struct ifnet *ifp; 4713695a8586SSepherosa Ziehau 4714695a8586SSepherosa Ziehau lwkt_serialize_enter(intr->bnx_intr_serialize); 4715695a8586SSepherosa Ziehau 4716695a8586SSepherosa Ziehau KKASSERT(mycpuid == intr->bnx_intr_cpuid); 4717695a8586SSepherosa Ziehau 4718695a8586SSepherosa Ziehau ifp = &intr->bnx_sc->arpcom.ac_if; 4719695a8586SSepherosa Ziehau if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) != IFF_RUNNING) { 4720695a8586SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4721695a8586SSepherosa Ziehau return; 4722695a8586SSepherosa Ziehau } 4723695a8586SSepherosa Ziehau 4724695a8586SSepherosa Ziehau txr = intr->bnx_txr; 4725695a8586SSepherosa Ziehau 4726695a8586SSepherosa Ziehau if (*txr->bnx_tx_considx != txr->bnx_tx_saved_considx) { 4727695a8586SSepherosa Ziehau if (intr->bnx_tx_check_considx == txr->bnx_tx_saved_considx) { 4728695a8586SSepherosa Ziehau if (!intr->bnx_intr_maylose) { 4729695a8586SSepherosa Ziehau intr->bnx_intr_maylose = TRUE; 4730695a8586SSepherosa Ziehau goto done; 4731695a8586SSepherosa Ziehau } 4732695a8586SSepherosa Ziehau if (bootverbose) 4733695a8586SSepherosa Ziehau if_printf(ifp, "lost interrupt\n"); 4734695a8586SSepherosa Ziehau intr->bnx_intr_func(intr->bnx_intr_arg); 4735695a8586SSepherosa Ziehau } 4736695a8586SSepherosa Ziehau } 4737695a8586SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4738695a8586SSepherosa Ziehau intr->bnx_tx_check_considx = txr->bnx_tx_saved_considx; 4739695a8586SSepherosa Ziehau 4740695a8586SSepherosa Ziehau done: 4741695a8586SSepherosa Ziehau callout_reset(&intr->bnx_intr_timer, BNX_INTR_CKINTVL, 4742695a8586SSepherosa Ziehau intr->bnx_intr_check, intr); 4743695a8586SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4744695a8586SSepherosa Ziehau } 4745695a8586SSepherosa Ziehau 4746695a8586SSepherosa Ziehau static void 4747695a8586SSepherosa Ziehau bnx_check_intr_rx(void *xintr) 4748695a8586SSepherosa Ziehau { 4749695a8586SSepherosa Ziehau struct bnx_intr_data *intr = xintr; 4750695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret; 4751695a8586SSepherosa Ziehau struct ifnet *ifp; 4752695a8586SSepherosa Ziehau 4753695a8586SSepherosa Ziehau lwkt_serialize_enter(intr->bnx_intr_serialize); 4754695a8586SSepherosa Ziehau 4755695a8586SSepherosa Ziehau KKASSERT(mycpuid == intr->bnx_intr_cpuid); 4756695a8586SSepherosa Ziehau 4757695a8586SSepherosa Ziehau ifp = &intr->bnx_sc->arpcom.ac_if; 4758695a8586SSepherosa Ziehau if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) != IFF_RUNNING) { 4759695a8586SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4760695a8586SSepherosa Ziehau return; 4761695a8586SSepherosa Ziehau } 4762695a8586SSepherosa Ziehau 4763695a8586SSepherosa Ziehau ret = intr->bnx_ret; 4764695a8586SSepherosa Ziehau 4765695a8586SSepherosa Ziehau if (*ret->bnx_rx_considx != ret->bnx_rx_saved_considx) { 4766695a8586SSepherosa Ziehau if (intr->bnx_rx_check_considx == ret->bnx_rx_saved_considx) { 4767695a8586SSepherosa Ziehau if (!intr->bnx_intr_maylose) { 4768695a8586SSepherosa Ziehau intr->bnx_intr_maylose = TRUE; 4769695a8586SSepherosa Ziehau goto done; 4770695a8586SSepherosa Ziehau } 4771695a8586SSepherosa Ziehau if (bootverbose) 4772695a8586SSepherosa Ziehau if_printf(ifp, "lost interrupt\n"); 4773695a8586SSepherosa Ziehau intr->bnx_intr_func(intr->bnx_intr_arg); 4774695a8586SSepherosa Ziehau } 4775695a8586SSepherosa Ziehau } 4776695a8586SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4777695a8586SSepherosa Ziehau intr->bnx_rx_check_considx = ret->bnx_rx_saved_considx; 4778695a8586SSepherosa Ziehau 4779695a8586SSepherosa Ziehau done: 4780695a8586SSepherosa Ziehau callout_reset(&intr->bnx_intr_timer, BNX_INTR_CKINTVL, 4781695a8586SSepherosa Ziehau intr->bnx_intr_check, intr); 4782695a8586SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4783695a8586SSepherosa Ziehau } 4784695a8586SSepherosa Ziehau 4785695a8586SSepherosa Ziehau static void 47866c8d8eccSSepherosa Ziehau bnx_enable_intr(struct bnx_softc *sc) 47876c8d8eccSSepherosa Ziehau { 47886c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 4789f33ac8a4SSepherosa Ziehau int i; 47906c8d8eccSSepherosa Ziehau 4791f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 4792f33ac8a4SSepherosa Ziehau lwkt_serialize_handler_enable( 4793f33ac8a4SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_serialize); 4794f33ac8a4SSepherosa Ziehau } 47956c8d8eccSSepherosa Ziehau 47966c8d8eccSSepherosa Ziehau /* 47976c8d8eccSSepherosa Ziehau * Enable interrupt. 47986c8d8eccSSepherosa Ziehau */ 479997ba8fc5SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 480097ba8fc5SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 480197ba8fc5SSepherosa Ziehau 480297ba8fc5SSepherosa Ziehau bnx_writembx(sc, intr->bnx_intr_mbx, 480397ba8fc5SSepherosa Ziehau (*intr->bnx_saved_status_tag) << 24); 48046c8d8eccSSepherosa Ziehau /* XXX Linux driver */ 480597ba8fc5SSepherosa Ziehau bnx_writembx(sc, intr->bnx_intr_mbx, 480697ba8fc5SSepherosa Ziehau (*intr->bnx_saved_status_tag) << 24); 480797ba8fc5SSepherosa Ziehau } 48086c8d8eccSSepherosa Ziehau 48096c8d8eccSSepherosa Ziehau /* 48106c8d8eccSSepherosa Ziehau * Unmask the interrupt when we stop polling. 48116c8d8eccSSepherosa Ziehau */ 48126c8d8eccSSepherosa Ziehau PCI_CLRBIT(sc->bnx_dev, BGE_PCI_MISC_CTL, 48136c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_MASK_PCI_INTR, 4); 48146c8d8eccSSepherosa Ziehau 48156c8d8eccSSepherosa Ziehau /* 48166c8d8eccSSepherosa Ziehau * Trigger another interrupt, since above writing 48176c8d8eccSSepherosa Ziehau * to interrupt mailbox0 may acknowledge pending 48186c8d8eccSSepherosa Ziehau * interrupt. 48196c8d8eccSSepherosa Ziehau */ 48206c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_SET); 4821df9ccc98SSepherosa Ziehau 4822df9ccc98SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_STATUSTAG_BUG) { 4823df9ccc98SSepherosa Ziehau if (bootverbose) 4824df9ccc98SSepherosa Ziehau if_printf(ifp, "status tag bug workaround\n"); 4825df9ccc98SSepherosa Ziehau 4826f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 482797ba8fc5SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 482897ba8fc5SSepherosa Ziehau 4829695a8586SSepherosa Ziehau if (intr->bnx_intr_check == NULL) 4830695a8586SSepherosa Ziehau continue; 4831f33ac8a4SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4832f33ac8a4SSepherosa Ziehau intr->bnx_rx_check_considx = 0; 4833f33ac8a4SSepherosa Ziehau intr->bnx_tx_check_considx = 0; 4834f33ac8a4SSepherosa Ziehau callout_reset_bycpu(&intr->bnx_intr_timer, 4835f33ac8a4SSepherosa Ziehau BNX_INTR_CKINTVL, intr->bnx_intr_check, intr, 4836f33ac8a4SSepherosa Ziehau intr->bnx_intr_cpuid); 4837f33ac8a4SSepherosa Ziehau } 4838df9ccc98SSepherosa Ziehau } 48396c8d8eccSSepherosa Ziehau } 48406c8d8eccSSepherosa Ziehau 48416c8d8eccSSepherosa Ziehau static void 48426c8d8eccSSepherosa Ziehau bnx_disable_intr(struct bnx_softc *sc) 48436c8d8eccSSepherosa Ziehau { 4844f33ac8a4SSepherosa Ziehau int i; 4845f33ac8a4SSepherosa Ziehau 4846f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 4847f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 4848f33ac8a4SSepherosa Ziehau 4849f33ac8a4SSepherosa Ziehau callout_stop(&intr->bnx_intr_timer); 4850f33ac8a4SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4851f33ac8a4SSepherosa Ziehau intr->bnx_rx_check_considx = 0; 4852f33ac8a4SSepherosa Ziehau intr->bnx_tx_check_considx = 0; 4853f33ac8a4SSepherosa Ziehau } 48546c8d8eccSSepherosa Ziehau 48556c8d8eccSSepherosa Ziehau /* 48566c8d8eccSSepherosa Ziehau * Mask the interrupt when we start polling. 48576c8d8eccSSepherosa Ziehau */ 48586c8d8eccSSepherosa Ziehau PCI_SETBIT(sc->bnx_dev, BGE_PCI_MISC_CTL, 48596c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_MASK_PCI_INTR, 4); 48606c8d8eccSSepherosa Ziehau 48616c8d8eccSSepherosa Ziehau /* 48626c8d8eccSSepherosa Ziehau * Acknowledge possible asserted interrupt. 48636c8d8eccSSepherosa Ziehau */ 4864695a8586SSepherosa Ziehau for (i = 0; i < BNX_INTR_MAX; ++i) 486597ba8fc5SSepherosa Ziehau bnx_writembx(sc, sc->bnx_intr_data[i].bnx_intr_mbx, 1); 48666c8d8eccSSepherosa Ziehau 4867f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 4868f33ac8a4SSepherosa Ziehau lwkt_serialize_handler_disable( 4869f33ac8a4SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_serialize); 4870f33ac8a4SSepherosa Ziehau } 48716c8d8eccSSepherosa Ziehau } 48726c8d8eccSSepherosa Ziehau 48736c8d8eccSSepherosa Ziehau static int 48746c8d8eccSSepherosa Ziehau bnx_get_eaddr_mem(struct bnx_softc *sc, uint8_t ether_addr[]) 48756c8d8eccSSepherosa Ziehau { 48766c8d8eccSSepherosa Ziehau uint32_t mac_addr; 48776c8d8eccSSepherosa Ziehau int ret = 1; 48786c8d8eccSSepherosa Ziehau 48796c8d8eccSSepherosa Ziehau mac_addr = bnx_readmem_ind(sc, 0x0c14); 48806c8d8eccSSepherosa Ziehau if ((mac_addr >> 16) == 0x484b) { 48816c8d8eccSSepherosa Ziehau ether_addr[0] = (uint8_t)(mac_addr >> 8); 48826c8d8eccSSepherosa Ziehau ether_addr[1] = (uint8_t)mac_addr; 48836c8d8eccSSepherosa Ziehau mac_addr = bnx_readmem_ind(sc, 0x0c18); 48846c8d8eccSSepherosa Ziehau ether_addr[2] = (uint8_t)(mac_addr >> 24); 48856c8d8eccSSepherosa Ziehau ether_addr[3] = (uint8_t)(mac_addr >> 16); 48866c8d8eccSSepherosa Ziehau ether_addr[4] = (uint8_t)(mac_addr >> 8); 48876c8d8eccSSepherosa Ziehau ether_addr[5] = (uint8_t)mac_addr; 48886c8d8eccSSepherosa Ziehau ret = 0; 48896c8d8eccSSepherosa Ziehau } 48906c8d8eccSSepherosa Ziehau return ret; 48916c8d8eccSSepherosa Ziehau } 48926c8d8eccSSepherosa Ziehau 48936c8d8eccSSepherosa Ziehau static int 48946c8d8eccSSepherosa Ziehau bnx_get_eaddr_nvram(struct bnx_softc *sc, uint8_t ether_addr[]) 48956c8d8eccSSepherosa Ziehau { 48966c8d8eccSSepherosa Ziehau int mac_offset = BGE_EE_MAC_OFFSET; 48976c8d8eccSSepherosa Ziehau 489880969639SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) { 489980969639SSepherosa Ziehau int f; 490080969639SSepherosa Ziehau 490180969639SSepherosa Ziehau f = pci_get_function(sc->bnx_dev); 490280969639SSepherosa Ziehau if (f & 1) 490380969639SSepherosa Ziehau mac_offset = BGE_EE_MAC_OFFSET_5717; 490480969639SSepherosa Ziehau if (f > 1) 490580969639SSepherosa Ziehau mac_offset += BGE_EE_MAC_OFFSET_5717_OFF; 490680969639SSepherosa Ziehau } 49076c8d8eccSSepherosa Ziehau 49086c8d8eccSSepherosa Ziehau return bnx_read_nvram(sc, ether_addr, mac_offset + 2, ETHER_ADDR_LEN); 49096c8d8eccSSepherosa Ziehau } 49106c8d8eccSSepherosa Ziehau 49116c8d8eccSSepherosa Ziehau static int 49126c8d8eccSSepherosa Ziehau bnx_get_eaddr_eeprom(struct bnx_softc *sc, uint8_t ether_addr[]) 49136c8d8eccSSepherosa Ziehau { 49146c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_NO_EEPROM) 49156c8d8eccSSepherosa Ziehau return 1; 49166c8d8eccSSepherosa Ziehau 49176c8d8eccSSepherosa Ziehau return bnx_read_eeprom(sc, ether_addr, BGE_EE_MAC_OFFSET + 2, 49186c8d8eccSSepherosa Ziehau ETHER_ADDR_LEN); 49196c8d8eccSSepherosa Ziehau } 49206c8d8eccSSepherosa Ziehau 49216c8d8eccSSepherosa Ziehau static int 49226c8d8eccSSepherosa Ziehau bnx_get_eaddr(struct bnx_softc *sc, uint8_t eaddr[]) 49236c8d8eccSSepherosa Ziehau { 49246c8d8eccSSepherosa Ziehau static const bnx_eaddr_fcn_t bnx_eaddr_funcs[] = { 49256c8d8eccSSepherosa Ziehau /* NOTE: Order is critical */ 49266c8d8eccSSepherosa Ziehau bnx_get_eaddr_mem, 49276c8d8eccSSepherosa Ziehau bnx_get_eaddr_nvram, 49286c8d8eccSSepherosa Ziehau bnx_get_eaddr_eeprom, 49296c8d8eccSSepherosa Ziehau NULL 49306c8d8eccSSepherosa Ziehau }; 49316c8d8eccSSepherosa Ziehau const bnx_eaddr_fcn_t *func; 49326c8d8eccSSepherosa Ziehau 49336c8d8eccSSepherosa Ziehau for (func = bnx_eaddr_funcs; *func != NULL; ++func) { 49346c8d8eccSSepherosa Ziehau if ((*func)(sc, eaddr) == 0) 49356c8d8eccSSepherosa Ziehau break; 49366c8d8eccSSepherosa Ziehau } 49376c8d8eccSSepherosa Ziehau return (*func == NULL ? ENXIO : 0); 49386c8d8eccSSepherosa Ziehau } 49396c8d8eccSSepherosa Ziehau 49406c8d8eccSSepherosa Ziehau /* 49416c8d8eccSSepherosa Ziehau * NOTE: 'm' is not freed upon failure 49426c8d8eccSSepherosa Ziehau */ 49436c8d8eccSSepherosa Ziehau struct mbuf * 49446c8d8eccSSepherosa Ziehau bnx_defrag_shortdma(struct mbuf *m) 49456c8d8eccSSepherosa Ziehau { 49466c8d8eccSSepherosa Ziehau struct mbuf *n; 49476c8d8eccSSepherosa Ziehau int found; 49486c8d8eccSSepherosa Ziehau 49496c8d8eccSSepherosa Ziehau /* 49506c8d8eccSSepherosa Ziehau * If device receive two back-to-back send BDs with less than 49516c8d8eccSSepherosa Ziehau * or equal to 8 total bytes then the device may hang. The two 49526c8d8eccSSepherosa Ziehau * back-to-back send BDs must in the same frame for this failure 49536c8d8eccSSepherosa Ziehau * to occur. Scan mbuf chains and see whether two back-to-back 49546c8d8eccSSepherosa Ziehau * send BDs are there. If this is the case, allocate new mbuf 49556c8d8eccSSepherosa Ziehau * and copy the frame to workaround the silicon bug. 49566c8d8eccSSepherosa Ziehau */ 49576c8d8eccSSepherosa Ziehau for (n = m, found = 0; n != NULL; n = n->m_next) { 49586c8d8eccSSepherosa Ziehau if (n->m_len < 8) { 49596c8d8eccSSepherosa Ziehau found++; 49606c8d8eccSSepherosa Ziehau if (found > 1) 49616c8d8eccSSepherosa Ziehau break; 49626c8d8eccSSepherosa Ziehau continue; 49636c8d8eccSSepherosa Ziehau } 49646c8d8eccSSepherosa Ziehau found = 0; 49656c8d8eccSSepherosa Ziehau } 49666c8d8eccSSepherosa Ziehau 49676c8d8eccSSepherosa Ziehau if (found > 1) 49686c8d8eccSSepherosa Ziehau n = m_defrag(m, MB_DONTWAIT); 49696c8d8eccSSepherosa Ziehau else 49706c8d8eccSSepherosa Ziehau n = m; 49716c8d8eccSSepherosa Ziehau return n; 49726c8d8eccSSepherosa Ziehau } 49736c8d8eccSSepherosa Ziehau 49746c8d8eccSSepherosa Ziehau static void 49756c8d8eccSSepherosa Ziehau bnx_stop_block(struct bnx_softc *sc, bus_size_t reg, uint32_t bit) 49766c8d8eccSSepherosa Ziehau { 49776c8d8eccSSepherosa Ziehau int i; 49786c8d8eccSSepherosa Ziehau 49796c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, reg, bit); 49806c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 49816c8d8eccSSepherosa Ziehau if ((CSR_READ_4(sc, reg) & bit) == 0) 49826c8d8eccSSepherosa Ziehau return; 49836c8d8eccSSepherosa Ziehau DELAY(100); 49846c8d8eccSSepherosa Ziehau } 49856c8d8eccSSepherosa Ziehau } 49866c8d8eccSSepherosa Ziehau 49876c8d8eccSSepherosa Ziehau static void 49886c8d8eccSSepherosa Ziehau bnx_link_poll(struct bnx_softc *sc) 49896c8d8eccSSepherosa Ziehau { 49906c8d8eccSSepherosa Ziehau uint32_t status; 49916c8d8eccSSepherosa Ziehau 49926c8d8eccSSepherosa Ziehau status = CSR_READ_4(sc, BGE_MAC_STS); 49936c8d8eccSSepherosa Ziehau if ((status & sc->bnx_link_chg) || sc->bnx_link_evt) { 49946c8d8eccSSepherosa Ziehau sc->bnx_link_evt = 0; 49956c8d8eccSSepherosa Ziehau sc->bnx_link_upd(sc, status); 49966c8d8eccSSepherosa Ziehau } 49976c8d8eccSSepherosa Ziehau } 49986c8d8eccSSepherosa Ziehau 49996c8d8eccSSepherosa Ziehau static void 5000695a8586SSepherosa Ziehau bnx_enable_msi(struct bnx_softc *sc, boolean_t is_msix) 50016c8d8eccSSepherosa Ziehau { 50026c8d8eccSSepherosa Ziehau uint32_t msi_mode; 50036c8d8eccSSepherosa Ziehau 50046c8d8eccSSepherosa Ziehau msi_mode = CSR_READ_4(sc, BGE_MSI_MODE); 50056c8d8eccSSepherosa Ziehau msi_mode |= BGE_MSIMODE_ENABLE; 50066c8d8eccSSepherosa Ziehau /* 50076c8d8eccSSepherosa Ziehau * NOTE: 50080b4feeacSSepherosa Ziehau * 5718-PG105-R says that "one shot" mode does not work 50090b4feeacSSepherosa Ziehau * if MSI is used, however, it obviously works. 50106c8d8eccSSepherosa Ziehau */ 50116c8d8eccSSepherosa Ziehau msi_mode &= ~BGE_MSIMODE_ONESHOT_DISABLE; 5012695a8586SSepherosa Ziehau if (is_msix) 5013695a8586SSepherosa Ziehau msi_mode |= BGE_MSIMODE_MSIX_MULTIMODE; 5014695a8586SSepherosa Ziehau else 5015695a8586SSepherosa Ziehau msi_mode &= ~BGE_MSIMODE_MSIX_MULTIMODE; 50166c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MSI_MODE, msi_mode); 50176c8d8eccSSepherosa Ziehau } 50186c8d8eccSSepherosa Ziehau 50196c8d8eccSSepherosa Ziehau static uint32_t 50206c8d8eccSSepherosa Ziehau bnx_dma_swap_options(struct bnx_softc *sc) 50216c8d8eccSSepherosa Ziehau { 50226c8d8eccSSepherosa Ziehau uint32_t dma_options; 50236c8d8eccSSepherosa Ziehau 50246c8d8eccSSepherosa Ziehau dma_options = BGE_MODECTL_WORDSWAP_NONFRAME | 50256c8d8eccSSepherosa Ziehau BGE_MODECTL_BYTESWAP_DATA | BGE_MODECTL_WORDSWAP_DATA; 50266c8d8eccSSepherosa Ziehau #if BYTE_ORDER == BIG_ENDIAN 50276c8d8eccSSepherosa Ziehau dma_options |= BGE_MODECTL_BYTESWAP_NONFRAME; 50286c8d8eccSSepherosa Ziehau #endif 5029b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 5030b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 50316c8d8eccSSepherosa Ziehau dma_options |= BGE_MODECTL_BYTESWAP_B2HRX_DATA | 50326c8d8eccSSepherosa Ziehau BGE_MODECTL_WORDSWAP_B2HRX_DATA | BGE_MODECTL_B2HRX_ENABLE | 50336c8d8eccSSepherosa Ziehau BGE_MODECTL_HTX2B_ENABLE; 50346c8d8eccSSepherosa Ziehau } 50356c8d8eccSSepherosa Ziehau return dma_options; 50366c8d8eccSSepherosa Ziehau } 503766deb1c1SSepherosa Ziehau 503866deb1c1SSepherosa Ziehau static int 503933a04907SSepherosa Ziehau bnx_setup_tso(struct bnx_tx_ring *txr, struct mbuf **mp, 504066deb1c1SSepherosa Ziehau uint16_t *mss0, uint16_t *flags0) 504166deb1c1SSepherosa Ziehau { 504266deb1c1SSepherosa Ziehau struct mbuf *m; 504366deb1c1SSepherosa Ziehau struct ip *ip; 504466deb1c1SSepherosa Ziehau struct tcphdr *th; 504566deb1c1SSepherosa Ziehau int thoff, iphlen, hoff, hlen; 504666deb1c1SSepherosa Ziehau uint16_t flags, mss; 504766deb1c1SSepherosa Ziehau 5048f7a2269aSSepherosa Ziehau m = *mp; 5049f7a2269aSSepherosa Ziehau KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); 5050f7a2269aSSepherosa Ziehau 5051f7a2269aSSepherosa Ziehau hoff = m->m_pkthdr.csum_lhlen; 5052f7a2269aSSepherosa Ziehau iphlen = m->m_pkthdr.csum_iphlen; 5053f7a2269aSSepherosa Ziehau thoff = m->m_pkthdr.csum_thlen; 5054f7a2269aSSepherosa Ziehau 5055f7a2269aSSepherosa Ziehau KASSERT(hoff > 0, ("invalid ether header len")); 5056f7a2269aSSepherosa Ziehau KASSERT(iphlen > 0, ("invalid ip header len")); 5057f7a2269aSSepherosa Ziehau KASSERT(thoff > 0, ("invalid tcp header len")); 5058f7a2269aSSepherosa Ziehau 5059f7a2269aSSepherosa Ziehau if (__predict_false(m->m_len < hoff + iphlen + thoff)) { 5060f7a2269aSSepherosa Ziehau m = m_pullup(m, hoff + iphlen + thoff); 5061f7a2269aSSepherosa Ziehau if (m == NULL) { 5062f7a2269aSSepherosa Ziehau *mp = NULL; 5063f7a2269aSSepherosa Ziehau return ENOBUFS; 5064f7a2269aSSepherosa Ziehau } 5065f7a2269aSSepherosa Ziehau *mp = m; 5066f7a2269aSSepherosa Ziehau } 5067f7a2269aSSepherosa Ziehau ip = mtodoff(m, struct ip *, hoff); 5068f7a2269aSSepherosa Ziehau th = mtodoff(m, struct tcphdr *, hoff + iphlen); 5069f7a2269aSSepherosa Ziehau 5070f0336d39SSepherosa Ziehau mss = m->m_pkthdr.tso_segsz; 507166deb1c1SSepherosa Ziehau flags = BGE_TXBDFLAG_CPU_PRE_DMA | BGE_TXBDFLAG_CPU_POST_DMA; 507266deb1c1SSepherosa Ziehau 507366deb1c1SSepherosa Ziehau ip->ip_len = htons(mss + iphlen + thoff); 507466deb1c1SSepherosa Ziehau th->th_sum = 0; 507566deb1c1SSepherosa Ziehau 507666deb1c1SSepherosa Ziehau hlen = (iphlen + thoff) >> 2; 507766deb1c1SSepherosa Ziehau mss |= ((hlen & 0x3) << 14); 507866deb1c1SSepherosa Ziehau flags |= ((hlen & 0xf8) << 7) | ((hlen & 0x4) << 2); 507966deb1c1SSepherosa Ziehau 508066deb1c1SSepherosa Ziehau *mss0 = mss; 508166deb1c1SSepherosa Ziehau *flags0 = flags; 508266deb1c1SSepherosa Ziehau 508366deb1c1SSepherosa Ziehau return 0; 508466deb1c1SSepherosa Ziehau } 508533a04907SSepherosa Ziehau 508633a04907SSepherosa Ziehau static int 508733a04907SSepherosa Ziehau bnx_create_tx_ring(struct bnx_tx_ring *txr) 508833a04907SSepherosa Ziehau { 508933a04907SSepherosa Ziehau bus_size_t txmaxsz, txmaxsegsz; 509033a04907SSepherosa Ziehau int i, error; 509133a04907SSepherosa Ziehau 5092329f9016SSepherosa Ziehau lwkt_serialize_init(&txr->bnx_tx_serialize); 5093329f9016SSepherosa Ziehau 509433a04907SSepherosa Ziehau /* 509533a04907SSepherosa Ziehau * Create DMA tag and maps for TX mbufs. 509633a04907SSepherosa Ziehau */ 509733a04907SSepherosa Ziehau if (txr->bnx_sc->bnx_flags & BNX_FLAG_TSO) 509833a04907SSepherosa Ziehau txmaxsz = IP_MAXPACKET + sizeof(struct ether_vlan_header); 509933a04907SSepherosa Ziehau else 510033a04907SSepherosa Ziehau txmaxsz = BNX_JUMBO_FRAMELEN; 510133a04907SSepherosa Ziehau if (txr->bnx_sc->bnx_asicrev == BGE_ASICREV_BCM57766) 510233a04907SSepherosa Ziehau txmaxsegsz = MCLBYTES; 510333a04907SSepherosa Ziehau else 510433a04907SSepherosa Ziehau txmaxsegsz = PAGE_SIZE; 510533a04907SSepherosa Ziehau error = bus_dma_tag_create(txr->bnx_sc->bnx_cdata.bnx_parent_tag, 510633a04907SSepherosa Ziehau 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 510733a04907SSepherosa Ziehau txmaxsz, BNX_NSEG_NEW, txmaxsegsz, 510833a04907SSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 510933a04907SSepherosa Ziehau &txr->bnx_tx_mtag); 511033a04907SSepherosa Ziehau if (error) { 511133a04907SSepherosa Ziehau device_printf(txr->bnx_sc->bnx_dev, 5112beedf5beSSepherosa Ziehau "could not create TX mbuf DMA tag\n"); 511333a04907SSepherosa Ziehau return error; 511433a04907SSepherosa Ziehau } 511533a04907SSepherosa Ziehau 511633a04907SSepherosa Ziehau for (i = 0; i < BGE_TX_RING_CNT; i++) { 511733a04907SSepherosa Ziehau error = bus_dmamap_create(txr->bnx_tx_mtag, 511833a04907SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 5119fa4b1067SSepherosa Ziehau &txr->bnx_tx_buf[i].bnx_tx_dmamap); 512033a04907SSepherosa Ziehau if (error) { 512133a04907SSepherosa Ziehau int j; 512233a04907SSepherosa Ziehau 512333a04907SSepherosa Ziehau for (j = 0; j < i; ++j) { 512433a04907SSepherosa Ziehau bus_dmamap_destroy(txr->bnx_tx_mtag, 5125fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[j].bnx_tx_dmamap); 512633a04907SSepherosa Ziehau } 512733a04907SSepherosa Ziehau bus_dma_tag_destroy(txr->bnx_tx_mtag); 512833a04907SSepherosa Ziehau txr->bnx_tx_mtag = NULL; 512933a04907SSepherosa Ziehau 513033a04907SSepherosa Ziehau device_printf(txr->bnx_sc->bnx_dev, 5131beedf5beSSepherosa Ziehau "could not create TX mbuf DMA map\n"); 513233a04907SSepherosa Ziehau return error; 513333a04907SSepherosa Ziehau } 513433a04907SSepherosa Ziehau } 513533a04907SSepherosa Ziehau 513633a04907SSepherosa Ziehau /* 513733a04907SSepherosa Ziehau * Create DMA stuffs for TX ring. 513833a04907SSepherosa Ziehau */ 513933a04907SSepherosa Ziehau error = bnx_dma_block_alloc(txr->bnx_sc, BGE_TX_RING_SZ, 5140beedf5beSSepherosa Ziehau &txr->bnx_tx_ring_tag, 5141beedf5beSSepherosa Ziehau &txr->bnx_tx_ring_map, 5142beedf5beSSepherosa Ziehau (void *)&txr->bnx_tx_ring, 5143beedf5beSSepherosa Ziehau &txr->bnx_tx_ring_paddr); 514433a04907SSepherosa Ziehau if (error) { 514533a04907SSepherosa Ziehau device_printf(txr->bnx_sc->bnx_dev, 514633a04907SSepherosa Ziehau "could not create TX ring\n"); 514733a04907SSepherosa Ziehau return error; 514833a04907SSepherosa Ziehau } 514933a04907SSepherosa Ziehau 515079a64343SSepherosa Ziehau txr->bnx_tx_flags |= BNX_TX_FLAG_SHORTDMA; 515133a04907SSepherosa Ziehau txr->bnx_tx_wreg = BNX_TX_WREG_NSEGS; 515233a04907SSepherosa Ziehau 515333a04907SSepherosa Ziehau return 0; 515433a04907SSepherosa Ziehau } 515533a04907SSepherosa Ziehau 515633a04907SSepherosa Ziehau static void 515733a04907SSepherosa Ziehau bnx_destroy_tx_ring(struct bnx_tx_ring *txr) 515833a04907SSepherosa Ziehau { 515933a04907SSepherosa Ziehau /* Destroy TX mbuf DMA stuffs. */ 516033a04907SSepherosa Ziehau if (txr->bnx_tx_mtag != NULL) { 516133a04907SSepherosa Ziehau int i; 516233a04907SSepherosa Ziehau 516333a04907SSepherosa Ziehau for (i = 0; i < BGE_TX_RING_CNT; i++) { 5164fa4b1067SSepherosa Ziehau KKASSERT(txr->bnx_tx_buf[i].bnx_tx_mbuf == NULL); 516533a04907SSepherosa Ziehau bus_dmamap_destroy(txr->bnx_tx_mtag, 5166fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[i].bnx_tx_dmamap); 516733a04907SSepherosa Ziehau } 516833a04907SSepherosa Ziehau bus_dma_tag_destroy(txr->bnx_tx_mtag); 516933a04907SSepherosa Ziehau } 517033a04907SSepherosa Ziehau 517133a04907SSepherosa Ziehau /* Destroy TX ring */ 517233a04907SSepherosa Ziehau bnx_dma_block_free(txr->bnx_tx_ring_tag, 517333a04907SSepherosa Ziehau txr->bnx_tx_ring_map, txr->bnx_tx_ring); 517433a04907SSepherosa Ziehau } 5175aad4de2bSSepherosa Ziehau 5176aad4de2bSSepherosa Ziehau static int 5177aad4de2bSSepherosa Ziehau bnx_sysctl_force_defrag(SYSCTL_HANDLER_ARGS) 5178aad4de2bSSepherosa Ziehau { 5179aad4de2bSSepherosa Ziehau struct bnx_softc *sc = (void *)arg1; 5180aad4de2bSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 5181aad4de2bSSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[0]; 5182aad4de2bSSepherosa Ziehau int error, defrag, i; 5183aad4de2bSSepherosa Ziehau 5184aad4de2bSSepherosa Ziehau if (txr->bnx_tx_flags & BNX_TX_FLAG_FORCE_DEFRAG) 5185aad4de2bSSepherosa Ziehau defrag = 1; 5186aad4de2bSSepherosa Ziehau else 5187aad4de2bSSepherosa Ziehau defrag = 0; 5188aad4de2bSSepherosa Ziehau 5189aad4de2bSSepherosa Ziehau error = sysctl_handle_int(oidp, &defrag, 0, req); 5190aad4de2bSSepherosa Ziehau if (error || req->newptr == NULL) 5191aad4de2bSSepherosa Ziehau return error; 5192aad4de2bSSepherosa Ziehau 5193329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 5194aad4de2bSSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 5195aad4de2bSSepherosa Ziehau txr = &sc->bnx_tx_ring[i]; 5196aad4de2bSSepherosa Ziehau if (defrag) 5197aad4de2bSSepherosa Ziehau txr->bnx_tx_flags |= BNX_TX_FLAG_FORCE_DEFRAG; 5198aad4de2bSSepherosa Ziehau else 5199aad4de2bSSepherosa Ziehau txr->bnx_tx_flags &= ~BNX_TX_FLAG_FORCE_DEFRAG; 5200aad4de2bSSepherosa Ziehau } 5201329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 5202aad4de2bSSepherosa Ziehau 5203aad4de2bSSepherosa Ziehau return 0; 5204aad4de2bSSepherosa Ziehau } 5205472c99c8SSepherosa Ziehau 5206472c99c8SSepherosa Ziehau static int 5207472c99c8SSepherosa Ziehau bnx_sysctl_tx_wreg(SYSCTL_HANDLER_ARGS) 5208472c99c8SSepherosa Ziehau { 5209472c99c8SSepherosa Ziehau struct bnx_softc *sc = (void *)arg1; 5210472c99c8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 5211472c99c8SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[0]; 5212472c99c8SSepherosa Ziehau int error, tx_wreg, i; 5213472c99c8SSepherosa Ziehau 5214472c99c8SSepherosa Ziehau tx_wreg = txr->bnx_tx_wreg; 5215472c99c8SSepherosa Ziehau error = sysctl_handle_int(oidp, &tx_wreg, 0, req); 5216472c99c8SSepherosa Ziehau if (error || req->newptr == NULL) 5217472c99c8SSepherosa Ziehau return error; 5218472c99c8SSepherosa Ziehau 5219329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 5220472c99c8SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 5221472c99c8SSepherosa Ziehau sc->bnx_tx_ring[i].bnx_tx_wreg = tx_wreg; 5222329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 5223472c99c8SSepherosa Ziehau 5224472c99c8SSepherosa Ziehau return 0; 5225472c99c8SSepherosa Ziehau } 5226beedf5beSSepherosa Ziehau 5227beedf5beSSepherosa Ziehau static int 5228beedf5beSSepherosa Ziehau bnx_create_rx_ret_ring(struct bnx_rx_ret_ring *ret) 5229beedf5beSSepherosa Ziehau { 5230beedf5beSSepherosa Ziehau int error; 5231beedf5beSSepherosa Ziehau 5232329f9016SSepherosa Ziehau lwkt_serialize_init(&ret->bnx_rx_ret_serialize); 5233329f9016SSepherosa Ziehau 5234beedf5beSSepherosa Ziehau /* 5235beedf5beSSepherosa Ziehau * Create DMA stuffs for RX return ring. 5236beedf5beSSepherosa Ziehau */ 5237beedf5beSSepherosa Ziehau error = bnx_dma_block_alloc(ret->bnx_sc, 5238beedf5beSSepherosa Ziehau BGE_RX_RTN_RING_SZ(BNX_RETURN_RING_CNT), 5239beedf5beSSepherosa Ziehau &ret->bnx_rx_ret_ring_tag, 5240beedf5beSSepherosa Ziehau &ret->bnx_rx_ret_ring_map, 5241beedf5beSSepherosa Ziehau (void *)&ret->bnx_rx_ret_ring, 5242beedf5beSSepherosa Ziehau &ret->bnx_rx_ret_ring_paddr); 5243beedf5beSSepherosa Ziehau if (error) { 5244beedf5beSSepherosa Ziehau device_printf(ret->bnx_sc->bnx_dev, 5245beedf5beSSepherosa Ziehau "could not create RX ret ring\n"); 5246beedf5beSSepherosa Ziehau return error; 5247beedf5beSSepherosa Ziehau } 5248beedf5beSSepherosa Ziehau 5249beedf5beSSepherosa Ziehau /* Shadow standard ring's RX mbuf DMA tag */ 5250beedf5beSSepherosa Ziehau ret->bnx_rx_mtag = ret->bnx_std->bnx_rx_mtag; 5251beedf5beSSepherosa Ziehau 5252beedf5beSSepherosa Ziehau /* 5253beedf5beSSepherosa Ziehau * Create tmp DMA map for RX mbufs. 5254beedf5beSSepherosa Ziehau */ 5255beedf5beSSepherosa Ziehau error = bus_dmamap_create(ret->bnx_rx_mtag, BUS_DMA_WAITOK, 5256beedf5beSSepherosa Ziehau &ret->bnx_rx_tmpmap); 5257beedf5beSSepherosa Ziehau if (error) { 5258beedf5beSSepherosa Ziehau device_printf(ret->bnx_sc->bnx_dev, 5259beedf5beSSepherosa Ziehau "could not create tmp RX mbuf DMA map\n"); 5260beedf5beSSepherosa Ziehau ret->bnx_rx_mtag = NULL; 5261beedf5beSSepherosa Ziehau return error; 5262beedf5beSSepherosa Ziehau } 5263beedf5beSSepherosa Ziehau return 0; 5264beedf5beSSepherosa Ziehau } 5265beedf5beSSepherosa Ziehau 5266beedf5beSSepherosa Ziehau static void 5267beedf5beSSepherosa Ziehau bnx_destroy_rx_ret_ring(struct bnx_rx_ret_ring *ret) 5268beedf5beSSepherosa Ziehau { 5269beedf5beSSepherosa Ziehau /* Destroy tmp RX mbuf DMA map */ 5270beedf5beSSepherosa Ziehau if (ret->bnx_rx_mtag != NULL) 5271beedf5beSSepherosa Ziehau bus_dmamap_destroy(ret->bnx_rx_mtag, ret->bnx_rx_tmpmap); 5272beedf5beSSepherosa Ziehau 5273beedf5beSSepherosa Ziehau /* Destroy RX return ring */ 5274beedf5beSSepherosa Ziehau bnx_dma_block_free(ret->bnx_rx_ret_ring_tag, 5275beedf5beSSepherosa Ziehau ret->bnx_rx_ret_ring_map, ret->bnx_rx_ret_ring); 5276beedf5beSSepherosa Ziehau } 52770c7da01dSSepherosa Ziehau 52780c7da01dSSepherosa Ziehau static int 52790c7da01dSSepherosa Ziehau bnx_alloc_intr(struct bnx_softc *sc) 52800c7da01dSSepherosa Ziehau { 5281f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr; 52820c7da01dSSepherosa Ziehau u_int intr_flags; 5283695a8586SSepherosa Ziehau int error; 5284695a8586SSepherosa Ziehau 5285695a8586SSepherosa Ziehau if (sc->bnx_intr_cnt > 1) { 5286695a8586SSepherosa Ziehau error = bnx_alloc_msix(sc); 5287695a8586SSepherosa Ziehau if (error) 5288695a8586SSepherosa Ziehau return error; 5289695a8586SSepherosa Ziehau KKASSERT(sc->bnx_intr_type == PCI_INTR_TYPE_MSIX); 5290695a8586SSepherosa Ziehau return 0; 5291695a8586SSepherosa Ziehau } 52920c7da01dSSepherosa Ziehau 52930a806e3aSSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt == 1); 52940c7da01dSSepherosa Ziehau 5295f33ac8a4SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 5296f33ac8a4SSepherosa Ziehau intr->bnx_ret = &sc->bnx_rx_ret_ring[0]; 5297f33ac8a4SSepherosa Ziehau intr->bnx_txr = &sc->bnx_tx_ring[0]; 5298f33ac8a4SSepherosa Ziehau intr->bnx_intr_serialize = &sc->bnx_main_serialize; 5299695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_rxtx; 53004fa38985SSepherosa Ziehau intr->bnx_saved_status_tag = &intr->bnx_ret->bnx_saved_status_tag; 5301f33ac8a4SSepherosa Ziehau 5302f33ac8a4SSepherosa Ziehau sc->bnx_intr_type = pci_alloc_1intr(sc->bnx_dev, bnx_msi_enable, 5303f33ac8a4SSepherosa Ziehau &intr->bnx_intr_rid, &intr_flags); 5304f33ac8a4SSepherosa Ziehau 5305f33ac8a4SSepherosa Ziehau intr->bnx_intr_res = bus_alloc_resource_any(sc->bnx_dev, SYS_RES_IRQ, 5306f33ac8a4SSepherosa Ziehau &intr->bnx_intr_rid, intr_flags); 5307f33ac8a4SSepherosa Ziehau if (intr->bnx_intr_res == NULL) { 53080c7da01dSSepherosa Ziehau device_printf(sc->bnx_dev, "could not alloc interrupt\n"); 53090c7da01dSSepherosa Ziehau return ENXIO; 53100c7da01dSSepherosa Ziehau } 53110c7da01dSSepherosa Ziehau 5312f33ac8a4SSepherosa Ziehau if (sc->bnx_intr_type == PCI_INTR_TYPE_MSI) { 5313695a8586SSepherosa Ziehau bnx_enable_msi(sc, FALSE); 531403cc99fdSSepherosa Ziehau intr->bnx_intr_func = bnx_msi; 5315f33ac8a4SSepherosa Ziehau if (bootverbose) 5316f33ac8a4SSepherosa Ziehau device_printf(sc->bnx_dev, "oneshot MSI\n"); 5317f33ac8a4SSepherosa Ziehau } else { 5318f33ac8a4SSepherosa Ziehau intr->bnx_intr_func = bnx_intr_legacy; 5319f33ac8a4SSepherosa Ziehau } 5320f33ac8a4SSepherosa Ziehau intr->bnx_intr_arg = sc; 5321f33ac8a4SSepherosa Ziehau intr->bnx_intr_cpuid = rman_get_cpuid(intr->bnx_intr_res); 5322f33ac8a4SSepherosa Ziehau 5323f33ac8a4SSepherosa Ziehau intr->bnx_txr->bnx_tx_cpuid = intr->bnx_intr_cpuid; 5324f33ac8a4SSepherosa Ziehau 53250c7da01dSSepherosa Ziehau return 0; 53260c7da01dSSepherosa Ziehau } 53270c7da01dSSepherosa Ziehau 53280c7da01dSSepherosa Ziehau static int 53290c7da01dSSepherosa Ziehau bnx_setup_intr(struct bnx_softc *sc) 53300c7da01dSSepherosa Ziehau { 5331f33ac8a4SSepherosa Ziehau int error, i; 53320c7da01dSSepherosa Ziehau 5333f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 5334f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 5335f33ac8a4SSepherosa Ziehau 5336f33ac8a4SSepherosa Ziehau error = bus_setup_intr_descr(sc->bnx_dev, intr->bnx_intr_res, 5337f33ac8a4SSepherosa Ziehau INTR_MPSAFE, intr->bnx_intr_func, intr->bnx_intr_arg, 5338f33ac8a4SSepherosa Ziehau &intr->bnx_intr_hand, intr->bnx_intr_serialize, 5339f33ac8a4SSepherosa Ziehau intr->bnx_intr_desc); 53400c7da01dSSepherosa Ziehau if (error) { 5341f33ac8a4SSepherosa Ziehau device_printf(sc->bnx_dev, 5342f33ac8a4SSepherosa Ziehau "could not set up %dth intr\n", i); 5343f33ac8a4SSepherosa Ziehau bnx_teardown_intr(sc, i); 53440c7da01dSSepherosa Ziehau return error; 53450c7da01dSSepherosa Ziehau } 5346f33ac8a4SSepherosa Ziehau } 53470c7da01dSSepherosa Ziehau return 0; 53480c7da01dSSepherosa Ziehau } 53490c7da01dSSepherosa Ziehau 53500c7da01dSSepherosa Ziehau static void 5351f33ac8a4SSepherosa Ziehau bnx_teardown_intr(struct bnx_softc *sc, int cnt) 5352f33ac8a4SSepherosa Ziehau { 5353f33ac8a4SSepherosa Ziehau int i; 5354f33ac8a4SSepherosa Ziehau 5355f33ac8a4SSepherosa Ziehau for (i = 0; i < cnt; ++i) { 5356f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 5357f33ac8a4SSepherosa Ziehau 5358f33ac8a4SSepherosa Ziehau bus_teardown_intr(sc->bnx_dev, intr->bnx_intr_res, 5359f33ac8a4SSepherosa Ziehau intr->bnx_intr_hand); 5360f33ac8a4SSepherosa Ziehau } 5361f33ac8a4SSepherosa Ziehau } 5362f33ac8a4SSepherosa Ziehau 5363f33ac8a4SSepherosa Ziehau static void 53640c7da01dSSepherosa Ziehau bnx_free_intr(struct bnx_softc *sc) 53650c7da01dSSepherosa Ziehau { 5366695a8586SSepherosa Ziehau if (sc->bnx_intr_type != PCI_INTR_TYPE_MSIX) { 5367f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr; 5368f33ac8a4SSepherosa Ziehau 5369f33ac8a4SSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt <= 1); 5370f33ac8a4SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 5371f33ac8a4SSepherosa Ziehau 5372f33ac8a4SSepherosa Ziehau if (intr->bnx_intr_res != NULL) { 53730c7da01dSSepherosa Ziehau bus_release_resource(sc->bnx_dev, SYS_RES_IRQ, 5374f33ac8a4SSepherosa Ziehau intr->bnx_intr_rid, intr->bnx_intr_res); 53750c7da01dSSepherosa Ziehau } 5376f33ac8a4SSepherosa Ziehau if (sc->bnx_intr_type == PCI_INTR_TYPE_MSI) 53770c7da01dSSepherosa Ziehau pci_release_msi(sc->bnx_dev); 5378695a8586SSepherosa Ziehau } else { 5379695a8586SSepherosa Ziehau bnx_free_msix(sc, TRUE); 5380695a8586SSepherosa Ziehau } 53810c7da01dSSepherosa Ziehau } 5382329f9016SSepherosa Ziehau 5383329f9016SSepherosa Ziehau static void 5384329f9016SSepherosa Ziehau bnx_setup_serialize(struct bnx_softc *sc) 5385329f9016SSepherosa Ziehau { 5386329f9016SSepherosa Ziehau int i, j; 5387329f9016SSepherosa Ziehau 5388329f9016SSepherosa Ziehau /* 5389329f9016SSepherosa Ziehau * Allocate serializer array 5390329f9016SSepherosa Ziehau */ 5391329f9016SSepherosa Ziehau 5392329f9016SSepherosa Ziehau /* Main + RX STD + TX + RX RET */ 5393329f9016SSepherosa Ziehau sc->bnx_serialize_cnt = 1 + 1 + sc->bnx_tx_ringcnt + sc->bnx_rx_retcnt; 5394329f9016SSepherosa Ziehau 5395329f9016SSepherosa Ziehau sc->bnx_serialize = 5396329f9016SSepherosa Ziehau kmalloc(sc->bnx_serialize_cnt * sizeof(struct lwkt_serialize *), 5397329f9016SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 5398329f9016SSepherosa Ziehau 5399329f9016SSepherosa Ziehau /* 5400329f9016SSepherosa Ziehau * Setup serializers 5401329f9016SSepherosa Ziehau * 5402329f9016SSepherosa Ziehau * NOTE: Order is critical 5403329f9016SSepherosa Ziehau */ 5404329f9016SSepherosa Ziehau 5405329f9016SSepherosa Ziehau i = 0; 5406329f9016SSepherosa Ziehau 5407329f9016SSepherosa Ziehau KKASSERT(i < sc->bnx_serialize_cnt); 5408329f9016SSepherosa Ziehau sc->bnx_serialize[i++] = &sc->bnx_main_serialize; 5409329f9016SSepherosa Ziehau 5410329f9016SSepherosa Ziehau KKASSERT(i < sc->bnx_serialize_cnt); 5411329f9016SSepherosa Ziehau sc->bnx_serialize[i++] = &sc->bnx_rx_std_ring.bnx_rx_std_serialize; 5412329f9016SSepherosa Ziehau 5413329f9016SSepherosa Ziehau for (j = 0; j < sc->bnx_rx_retcnt; ++j) { 5414329f9016SSepherosa Ziehau KKASSERT(i < sc->bnx_serialize_cnt); 5415329f9016SSepherosa Ziehau sc->bnx_serialize[i++] = 5416329f9016SSepherosa Ziehau &sc->bnx_rx_ret_ring[j].bnx_rx_ret_serialize; 5417329f9016SSepherosa Ziehau } 5418329f9016SSepherosa Ziehau 5419329f9016SSepherosa Ziehau for (j = 0; j < sc->bnx_tx_ringcnt; ++j) { 5420329f9016SSepherosa Ziehau KKASSERT(i < sc->bnx_serialize_cnt); 5421329f9016SSepherosa Ziehau sc->bnx_serialize[i++] = 5422329f9016SSepherosa Ziehau &sc->bnx_tx_ring[j].bnx_tx_serialize; 5423329f9016SSepherosa Ziehau } 5424329f9016SSepherosa Ziehau 5425329f9016SSepherosa Ziehau KKASSERT(i == sc->bnx_serialize_cnt); 5426329f9016SSepherosa Ziehau } 5427329f9016SSepherosa Ziehau 5428329f9016SSepherosa Ziehau static void 5429329f9016SSepherosa Ziehau bnx_serialize(struct ifnet *ifp, enum ifnet_serialize slz) 5430329f9016SSepherosa Ziehau { 5431329f9016SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 5432329f9016SSepherosa Ziehau 5433329f9016SSepherosa Ziehau ifnet_serialize_array_enter(sc->bnx_serialize, 5434329f9016SSepherosa Ziehau sc->bnx_serialize_cnt, slz); 5435329f9016SSepherosa Ziehau } 5436329f9016SSepherosa Ziehau 5437329f9016SSepherosa Ziehau static void 5438329f9016SSepherosa Ziehau bnx_deserialize(struct ifnet *ifp, enum ifnet_serialize slz) 5439329f9016SSepherosa Ziehau { 5440329f9016SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 5441329f9016SSepherosa Ziehau 5442329f9016SSepherosa Ziehau ifnet_serialize_array_exit(sc->bnx_serialize, 5443329f9016SSepherosa Ziehau sc->bnx_serialize_cnt, slz); 5444329f9016SSepherosa Ziehau } 5445329f9016SSepherosa Ziehau 5446329f9016SSepherosa Ziehau static int 5447329f9016SSepherosa Ziehau bnx_tryserialize(struct ifnet *ifp, enum ifnet_serialize slz) 5448329f9016SSepherosa Ziehau { 5449329f9016SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 5450329f9016SSepherosa Ziehau 5451329f9016SSepherosa Ziehau return ifnet_serialize_array_try(sc->bnx_serialize, 5452329f9016SSepherosa Ziehau sc->bnx_serialize_cnt, slz); 5453329f9016SSepherosa Ziehau } 5454329f9016SSepherosa Ziehau 5455329f9016SSepherosa Ziehau #ifdef INVARIANTS 5456329f9016SSepherosa Ziehau 5457329f9016SSepherosa Ziehau static void 5458329f9016SSepherosa Ziehau bnx_serialize_assert(struct ifnet *ifp, enum ifnet_serialize slz, 5459329f9016SSepherosa Ziehau boolean_t serialized) 5460329f9016SSepherosa Ziehau { 5461329f9016SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 5462329f9016SSepherosa Ziehau 5463329f9016SSepherosa Ziehau ifnet_serialize_array_assert(sc->bnx_serialize, sc->bnx_serialize_cnt, 5464329f9016SSepherosa Ziehau slz, serialized); 5465329f9016SSepherosa Ziehau } 5466329f9016SSepherosa Ziehau 5467329f9016SSepherosa Ziehau #endif /* INVARIANTS */ 54684fa38985SSepherosa Ziehau 54694fa38985SSepherosa Ziehau #ifdef IFPOLL_ENABLE 54704fa38985SSepherosa Ziehau 54714fa38985SSepherosa Ziehau static int 54724fa38985SSepherosa Ziehau bnx_sysctl_npoll_offset(SYSCTL_HANDLER_ARGS) 54734fa38985SSepherosa Ziehau { 54744fa38985SSepherosa Ziehau struct bnx_softc *sc = (void *)arg1; 54754fa38985SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 54764fa38985SSepherosa Ziehau int error, off; 54774fa38985SSepherosa Ziehau 54784fa38985SSepherosa Ziehau off = sc->bnx_npoll_rxoff; 54794fa38985SSepherosa Ziehau error = sysctl_handle_int(oidp, &off, 0, req); 54804fa38985SSepherosa Ziehau if (error || req->newptr == NULL) 54814fa38985SSepherosa Ziehau return error; 54824fa38985SSepherosa Ziehau if (off < 0) 54834fa38985SSepherosa Ziehau return EINVAL; 54844fa38985SSepherosa Ziehau 54854fa38985SSepherosa Ziehau ifnet_serialize_all(ifp); 54864fa38985SSepherosa Ziehau if (off >= ncpus2 || off % sc->bnx_rx_retcnt != 0) { 54874fa38985SSepherosa Ziehau error = EINVAL; 54884fa38985SSepherosa Ziehau } else { 54894fa38985SSepherosa Ziehau error = 0; 54904fa38985SSepherosa Ziehau sc->bnx_npoll_txoff = off; 54914fa38985SSepherosa Ziehau sc->bnx_npoll_rxoff = off; 54924fa38985SSepherosa Ziehau } 54934fa38985SSepherosa Ziehau ifnet_deserialize_all(ifp); 54944fa38985SSepherosa Ziehau 54954fa38985SSepherosa Ziehau return error; 54964fa38985SSepherosa Ziehau } 54974fa38985SSepherosa Ziehau 54984fa38985SSepherosa Ziehau static int 54994fa38985SSepherosa Ziehau bnx_sysctl_npoll_rxoff(SYSCTL_HANDLER_ARGS) 55004fa38985SSepherosa Ziehau { 55014fa38985SSepherosa Ziehau struct bnx_softc *sc = (void *)arg1; 55024fa38985SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 55034fa38985SSepherosa Ziehau int error, off; 55044fa38985SSepherosa Ziehau 55054fa38985SSepherosa Ziehau off = sc->bnx_npoll_rxoff; 55064fa38985SSepherosa Ziehau error = sysctl_handle_int(oidp, &off, 0, req); 55074fa38985SSepherosa Ziehau if (error || req->newptr == NULL) 55084fa38985SSepherosa Ziehau return error; 55094fa38985SSepherosa Ziehau if (off < 0) 55104fa38985SSepherosa Ziehau return EINVAL; 55114fa38985SSepherosa Ziehau 55124fa38985SSepherosa Ziehau ifnet_serialize_all(ifp); 55134fa38985SSepherosa Ziehau if (off >= ncpus2 || off % sc->bnx_rx_retcnt != 0) { 55144fa38985SSepherosa Ziehau error = EINVAL; 55154fa38985SSepherosa Ziehau } else { 55164fa38985SSepherosa Ziehau error = 0; 55174fa38985SSepherosa Ziehau sc->bnx_npoll_rxoff = off; 55184fa38985SSepherosa Ziehau } 55194fa38985SSepherosa Ziehau ifnet_deserialize_all(ifp); 55204fa38985SSepherosa Ziehau 55214fa38985SSepherosa Ziehau return error; 55224fa38985SSepherosa Ziehau } 55234fa38985SSepherosa Ziehau 55244fa38985SSepherosa Ziehau static int 55254fa38985SSepherosa Ziehau bnx_sysctl_npoll_txoff(SYSCTL_HANDLER_ARGS) 55264fa38985SSepherosa Ziehau { 55274fa38985SSepherosa Ziehau struct bnx_softc *sc = (void *)arg1; 55284fa38985SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 55294fa38985SSepherosa Ziehau int error, off; 55304fa38985SSepherosa Ziehau 55314fa38985SSepherosa Ziehau off = sc->bnx_npoll_txoff; 55324fa38985SSepherosa Ziehau error = sysctl_handle_int(oidp, &off, 0, req); 55334fa38985SSepherosa Ziehau if (error || req->newptr == NULL) 55344fa38985SSepherosa Ziehau return error; 55354fa38985SSepherosa Ziehau if (off < 0) 55364fa38985SSepherosa Ziehau return EINVAL; 55374fa38985SSepherosa Ziehau 55384fa38985SSepherosa Ziehau ifnet_serialize_all(ifp); 55394fa38985SSepherosa Ziehau if (off >= ncpus2) { 55404fa38985SSepherosa Ziehau error = EINVAL; 55414fa38985SSepherosa Ziehau } else { 55424fa38985SSepherosa Ziehau error = 0; 55434fa38985SSepherosa Ziehau sc->bnx_npoll_txoff = off; 55444fa38985SSepherosa Ziehau } 55454fa38985SSepherosa Ziehau ifnet_deserialize_all(ifp); 55464fa38985SSepherosa Ziehau 55474fa38985SSepherosa Ziehau return error; 55484fa38985SSepherosa Ziehau } 55494fa38985SSepherosa Ziehau 55504fa38985SSepherosa Ziehau #endif /* IFPOLL_ENABLE */ 55517dbaa833SSepherosa Ziehau 55527dbaa833SSepherosa Ziehau static void 55537dbaa833SSepherosa Ziehau bnx_set_tick_cpuid(struct bnx_softc *sc, boolean_t polling) 55547dbaa833SSepherosa Ziehau { 55557dbaa833SSepherosa Ziehau if (polling) 55567dbaa833SSepherosa Ziehau sc->bnx_tick_cpuid = 0; /* XXX */ 55577dbaa833SSepherosa Ziehau else 55587dbaa833SSepherosa Ziehau sc->bnx_tick_cpuid = sc->bnx_intr_data[0].bnx_intr_cpuid; 55597dbaa833SSepherosa Ziehau } 5560841cdf08SSepherosa Ziehau 5561841cdf08SSepherosa Ziehau static void 5562841cdf08SSepherosa Ziehau bnx_rx_std_refill_ithread(void *xstd) 5563841cdf08SSepherosa Ziehau { 5564841cdf08SSepherosa Ziehau struct bnx_rx_std_ring *std = xstd; 5565841cdf08SSepherosa Ziehau struct globaldata *gd = mycpu; 5566841cdf08SSepherosa Ziehau 5567841cdf08SSepherosa Ziehau crit_enter_gd(gd); 5568841cdf08SSepherosa Ziehau 5569841cdf08SSepherosa Ziehau while (!std->bnx_rx_std_stop) { 5570841cdf08SSepherosa Ziehau if (std->bnx_rx_std_refill) { 5571841cdf08SSepherosa Ziehau lwkt_serialize_handler_call( 5572841cdf08SSepherosa Ziehau &std->bnx_rx_std_serialize, 5573841cdf08SSepherosa Ziehau bnx_rx_std_refill, std, NULL); 5574841cdf08SSepherosa Ziehau } 5575841cdf08SSepherosa Ziehau 5576841cdf08SSepherosa Ziehau crit_exit_gd(gd); 5577841cdf08SSepherosa Ziehau crit_enter_gd(gd); 5578841cdf08SSepherosa Ziehau 5579695a8586SSepherosa Ziehau atomic_poll_release_int(&std->bnx_rx_std_running); 5580695a8586SSepherosa Ziehau cpu_mfence(); 5581695a8586SSepherosa Ziehau 5582841cdf08SSepherosa Ziehau if (!std->bnx_rx_std_refill && !std->bnx_rx_std_stop) { 5583841cdf08SSepherosa Ziehau lwkt_deschedule_self(gd->gd_curthread); 5584841cdf08SSepherosa Ziehau lwkt_switch(); 5585841cdf08SSepherosa Ziehau } 5586841cdf08SSepherosa Ziehau } 5587841cdf08SSepherosa Ziehau 5588841cdf08SSepherosa Ziehau crit_exit_gd(gd); 5589841cdf08SSepherosa Ziehau 5590841cdf08SSepherosa Ziehau wakeup(std); 5591841cdf08SSepherosa Ziehau 5592841cdf08SSepherosa Ziehau lwkt_exit(); 5593841cdf08SSepherosa Ziehau } 5594841cdf08SSepherosa Ziehau 5595841cdf08SSepherosa Ziehau static void 5596841cdf08SSepherosa Ziehau bnx_rx_std_refill(void *xstd, void *frame __unused) 5597841cdf08SSepherosa Ziehau { 5598841cdf08SSepherosa Ziehau struct bnx_rx_std_ring *std = xstd; 5599695a8586SSepherosa Ziehau int cnt, refill_mask; 5600841cdf08SSepherosa Ziehau 5601841cdf08SSepherosa Ziehau again: 5602841cdf08SSepherosa Ziehau cnt = 0; 5603841cdf08SSepherosa Ziehau 5604841cdf08SSepherosa Ziehau cpu_lfence(); 5605695a8586SSepherosa Ziehau refill_mask = std->bnx_rx_std_refill; 5606695a8586SSepherosa Ziehau atomic_clear_int(&std->bnx_rx_std_refill, refill_mask); 5607841cdf08SSepherosa Ziehau 5608695a8586SSepherosa Ziehau while (refill_mask) { 5609695a8586SSepherosa Ziehau uint16_t check_idx = std->bnx_rx_std; 5610695a8586SSepherosa Ziehau int ret_idx; 5611695a8586SSepherosa Ziehau 5612695a8586SSepherosa Ziehau ret_idx = bsfl(refill_mask); 5613841cdf08SSepherosa Ziehau for (;;) { 5614841cdf08SSepherosa Ziehau struct bnx_rx_buf *rb; 5615695a8586SSepherosa Ziehau int refilled; 5616841cdf08SSepherosa Ziehau 5617841cdf08SSepherosa Ziehau BNX_INC(check_idx, BGE_STD_RX_RING_CNT); 5618841cdf08SSepherosa Ziehau rb = &std->bnx_rx_std_buf[check_idx]; 5619695a8586SSepherosa Ziehau refilled = rb->bnx_rx_refilled; 5620841cdf08SSepherosa Ziehau cpu_lfence(); 5621695a8586SSepherosa Ziehau if (refilled) { 5622841cdf08SSepherosa Ziehau bnx_setup_rxdesc_std(std, check_idx); 5623841cdf08SSepherosa Ziehau std->bnx_rx_std = check_idx; 5624841cdf08SSepherosa Ziehau ++cnt; 5625695a8586SSepherosa Ziehau if (cnt >= 8) { 5626625c3ba3SSepherosa Ziehau atomic_subtract_int( 5627625c3ba3SSepherosa Ziehau &std->bnx_rx_std_used, cnt); 5628695a8586SSepherosa Ziehau bnx_writembx(std->bnx_sc, 5629695a8586SSepherosa Ziehau BGE_MBX_RX_STD_PROD_LO, 5630695a8586SSepherosa Ziehau std->bnx_rx_std); 5631695a8586SSepherosa Ziehau cnt = 0; 5632695a8586SSepherosa Ziehau } 5633841cdf08SSepherosa Ziehau } else { 5634841cdf08SSepherosa Ziehau break; 5635841cdf08SSepherosa Ziehau } 5636841cdf08SSepherosa Ziehau } 5637695a8586SSepherosa Ziehau refill_mask &= ~(1 << ret_idx); 5638695a8586SSepherosa Ziehau } 5639841cdf08SSepherosa Ziehau 5640841cdf08SSepherosa Ziehau if (cnt) { 5641625c3ba3SSepherosa Ziehau atomic_subtract_int(&std->bnx_rx_std_used, cnt); 5642841cdf08SSepherosa Ziehau bnx_writembx(std->bnx_sc, BGE_MBX_RX_STD_PROD_LO, 5643841cdf08SSepherosa Ziehau std->bnx_rx_std); 5644841cdf08SSepherosa Ziehau } 5645841cdf08SSepherosa Ziehau 5646841cdf08SSepherosa Ziehau if (std->bnx_rx_std_refill) 5647841cdf08SSepherosa Ziehau goto again; 5648841cdf08SSepherosa Ziehau 5649841cdf08SSepherosa Ziehau atomic_poll_release_int(&std->bnx_rx_std_running); 5650841cdf08SSepherosa Ziehau cpu_mfence(); 5651841cdf08SSepherosa Ziehau 5652841cdf08SSepherosa Ziehau if (std->bnx_rx_std_refill) 5653841cdf08SSepherosa Ziehau goto again; 5654841cdf08SSepherosa Ziehau } 5655841cdf08SSepherosa Ziehau 5656841cdf08SSepherosa Ziehau static int 5657841cdf08SSepherosa Ziehau bnx_sysctl_std_refill(SYSCTL_HANDLER_ARGS) 5658841cdf08SSepherosa Ziehau { 5659841cdf08SSepherosa Ziehau struct bnx_softc *sc = (void *)arg1; 5660841cdf08SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 5661841cdf08SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[0]; 5662841cdf08SSepherosa Ziehau int error, cntmax, i; 5663841cdf08SSepherosa Ziehau 5664841cdf08SSepherosa Ziehau cntmax = ret->bnx_rx_cntmax; 5665841cdf08SSepherosa Ziehau error = sysctl_handle_int(oidp, &cntmax, 0, req); 5666841cdf08SSepherosa Ziehau if (error || req->newptr == NULL) 5667841cdf08SSepherosa Ziehau return error; 5668841cdf08SSepherosa Ziehau 5669841cdf08SSepherosa Ziehau ifnet_serialize_all(ifp); 5670841cdf08SSepherosa Ziehau 5671625c3ba3SSepherosa Ziehau if ((cntmax * sc->bnx_rx_retcnt) >= BGE_STD_RX_RING_CNT / 2) { 5672841cdf08SSepherosa Ziehau error = EINVAL; 5673841cdf08SSepherosa Ziehau goto back; 5674841cdf08SSepherosa Ziehau } 5675841cdf08SSepherosa Ziehau 5676841cdf08SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 5677841cdf08SSepherosa Ziehau sc->bnx_rx_ret_ring[i].bnx_rx_cntmax = cntmax; 5678841cdf08SSepherosa Ziehau error = 0; 5679841cdf08SSepherosa Ziehau 5680841cdf08SSepherosa Ziehau back: 5681841cdf08SSepherosa Ziehau ifnet_deserialize_all(ifp); 5682841cdf08SSepherosa Ziehau 5683841cdf08SSepherosa Ziehau return error; 5684841cdf08SSepherosa Ziehau } 5685695a8586SSepherosa Ziehau 5686695a8586SSepherosa Ziehau static void 5687695a8586SSepherosa Ziehau bnx_init_rss(struct bnx_softc *sc) 5688695a8586SSepherosa Ziehau { 5689695a8586SSepherosa Ziehau uint8_t key[BGE_RSS_KEYREG_CNT * BGE_RSS_KEYREG_SIZE]; 5690695a8586SSepherosa Ziehau int i, j, r; 5691695a8586SSepherosa Ziehau 5692695a8586SSepherosa Ziehau KKASSERT(BNX_RSS_ENABLED(sc)); 5693695a8586SSepherosa Ziehau 5694*0f02bb87SSepherosa Ziehau /* 5695*0f02bb87SSepherosa Ziehau * Configure RSS redirect table in following fashion: 5696*0f02bb87SSepherosa Ziehau * (hash & ring_cnt_mask) == rdr_table[(hash & rdr_table_mask)] 5697*0f02bb87SSepherosa Ziehau */ 5698695a8586SSepherosa Ziehau r = 0; 5699695a8586SSepherosa Ziehau for (j = 0; j < BGE_RSS_INDIR_TBL_CNT; ++j) { 5700695a8586SSepherosa Ziehau uint32_t tbl = 0; 5701695a8586SSepherosa Ziehau 5702695a8586SSepherosa Ziehau for (i = 0; i < BGE_RSS_INDIR_TBLENT_CNT; ++i) { 5703695a8586SSepherosa Ziehau uint32_t q; 5704695a8586SSepherosa Ziehau 5705695a8586SSepherosa Ziehau q = r % sc->bnx_rx_retcnt; 5706695a8586SSepherosa Ziehau tbl |= q << (BGE_RSS_INDIR_TBLENT_SHIFT * 5707695a8586SSepherosa Ziehau (BGE_RSS_INDIR_TBLENT_CNT - i - 1)); 5708695a8586SSepherosa Ziehau ++r; 5709695a8586SSepherosa Ziehau } 5710695a8586SSepherosa Ziehau 5711695a8586SSepherosa Ziehau BNX_RSS_DPRINTF(sc, 1, "tbl%d %08x\n", j, tbl); 5712695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_RSS_INDIR_TBL(j), tbl); 5713695a8586SSepherosa Ziehau } 5714695a8586SSepherosa Ziehau 5715695a8586SSepherosa Ziehau toeplitz_get_key(key, sizeof(key)); 5716695a8586SSepherosa Ziehau for (i = 0; i < BGE_RSS_KEYREG_CNT; ++i) { 5717695a8586SSepherosa Ziehau uint32_t keyreg; 5718695a8586SSepherosa Ziehau 5719695a8586SSepherosa Ziehau keyreg = BGE_RSS_KEYREG_VAL(key, i); 5720695a8586SSepherosa Ziehau 5721695a8586SSepherosa Ziehau BNX_RSS_DPRINTF(sc, 1, "key%d %08x\n", i, keyreg); 5722695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_RSS_KEYREG(i), keyreg); 5723695a8586SSepherosa Ziehau } 5724695a8586SSepherosa Ziehau } 5725695a8586SSepherosa Ziehau 5726695a8586SSepherosa Ziehau static void 5727695a8586SSepherosa Ziehau bnx_setup_ring_cnt(struct bnx_softc *sc) 5728695a8586SSepherosa Ziehau { 5729695a8586SSepherosa Ziehau int msix_enable, i, msix_cnt, msix_cnt2, ring_max; 5730695a8586SSepherosa Ziehau 5731695a8586SSepherosa Ziehau sc->bnx_tx_ringcnt = 1; 5732695a8586SSepherosa Ziehau sc->bnx_rx_retcnt = 1; 5733695a8586SSepherosa Ziehau sc->bnx_intr_cnt = 1; 5734695a8586SSepherosa Ziehau 5735695a8586SSepherosa Ziehau msix_enable = device_getenv_int(sc->bnx_dev, "msix.enable", 5736695a8586SSepherosa Ziehau bnx_msix_enable); 5737695a8586SSepherosa Ziehau if (!msix_enable) 5738695a8586SSepherosa Ziehau return; 5739695a8586SSepherosa Ziehau 5740695a8586SSepherosa Ziehau if (ncpus2 == 1) 5741695a8586SSepherosa Ziehau return; 5742695a8586SSepherosa Ziehau 5743695a8586SSepherosa Ziehau msix_cnt = pci_msix_count(sc->bnx_dev); 5744695a8586SSepherosa Ziehau if (msix_cnt <= 1) 5745695a8586SSepherosa Ziehau return; 5746695a8586SSepherosa Ziehau 5747695a8586SSepherosa Ziehau i = 0; 5748695a8586SSepherosa Ziehau while ((1 << (i + 1)) <= msix_cnt) 5749695a8586SSepherosa Ziehau ++i; 5750695a8586SSepherosa Ziehau msix_cnt2 = 1 << i; 5751695a8586SSepherosa Ziehau 5752695a8586SSepherosa Ziehau /* 5753695a8586SSepherosa Ziehau * One MSI-X vector is dedicated to status or single TX queue, 5754695a8586SSepherosa Ziehau * so make sure that there are enough MSI-X vectors. 5755695a8586SSepherosa Ziehau */ 5756695a8586SSepherosa Ziehau if (msix_cnt == msix_cnt2) { 5757695a8586SSepherosa Ziehau /* 5758695a8586SSepherosa Ziehau * XXX 5759695a8586SSepherosa Ziehau * This probably will not happen; 57785/5718 families 5760695a8586SSepherosa Ziehau * come with at least 5 MSI-X vectors. 5761695a8586SSepherosa Ziehau */ 5762695a8586SSepherosa Ziehau msix_cnt2 >>= 1; 5763695a8586SSepherosa Ziehau if (msix_cnt2 <= 1) { 5764695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, 5765695a8586SSepherosa Ziehau "MSI-X count %d could not be used\n", msix_cnt); 5766695a8586SSepherosa Ziehau return; 5767695a8586SSepherosa Ziehau } 5768695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, "MSI-X count %d is power of 2\n", 5769695a8586SSepherosa Ziehau msix_cnt); 5770695a8586SSepherosa Ziehau } 5771695a8586SSepherosa Ziehau 5772695a8586SSepherosa Ziehau /* 5773695a8586SSepherosa Ziehau * Setup RX ring count 5774695a8586SSepherosa Ziehau */ 5775695a8586SSepherosa Ziehau ring_max = BNX_RX_RING_MAX; 5776695a8586SSepherosa Ziehau if (ring_max > msix_cnt2) 5777695a8586SSepherosa Ziehau ring_max = msix_cnt2; 5778695a8586SSepherosa Ziehau sc->bnx_rx_retcnt = device_getenv_int(sc->bnx_dev, "rx_rings", 5779695a8586SSepherosa Ziehau bnx_rx_rings); 5780695a8586SSepherosa Ziehau sc->bnx_rx_retcnt = if_ring_count2(sc->bnx_rx_retcnt, ring_max); 5781695a8586SSepherosa Ziehau 5782695a8586SSepherosa Ziehau if (sc->bnx_rx_retcnt == 1) 5783695a8586SSepherosa Ziehau return; 5784695a8586SSepherosa Ziehau 5785695a8586SSepherosa Ziehau /* 5786695a8586SSepherosa Ziehau * We need one extra MSI-X vector for link status or 5787695a8586SSepherosa Ziehau * TX ring (if only one TX ring is enabled). 5788695a8586SSepherosa Ziehau */ 5789695a8586SSepherosa Ziehau sc->bnx_intr_cnt = sc->bnx_rx_retcnt + 1; 5790695a8586SSepherosa Ziehau 5791695a8586SSepherosa Ziehau /* 5792695a8586SSepherosa Ziehau * Setup TX ring count 5793695a8586SSepherosa Ziehau * 5794695a8586SSepherosa Ziehau * Currently only BCM5719 and BCM5720 support multiple TX rings 5795695a8586SSepherosa Ziehau * and the TX ring count must be less than the RX ring count. 5796695a8586SSepherosa Ziehau */ 5797695a8586SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719 || 5798695a8586SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5720) { 5799695a8586SSepherosa Ziehau ring_max = BNX_TX_RING_MAX; 5800695a8586SSepherosa Ziehau if (ring_max > msix_cnt2) 5801695a8586SSepherosa Ziehau ring_max = msix_cnt2; 5802695a8586SSepherosa Ziehau if (ring_max > sc->bnx_rx_retcnt) 5803695a8586SSepherosa Ziehau ring_max = sc->bnx_rx_retcnt; 5804695a8586SSepherosa Ziehau sc->bnx_tx_ringcnt = device_getenv_int(sc->bnx_dev, "tx_rings", 5805695a8586SSepherosa Ziehau bnx_tx_rings); 5806695a8586SSepherosa Ziehau sc->bnx_tx_ringcnt = if_ring_count2(sc->bnx_tx_ringcnt, 5807695a8586SSepherosa Ziehau ring_max); 5808695a8586SSepherosa Ziehau } 5809695a8586SSepherosa Ziehau } 5810695a8586SSepherosa Ziehau 5811695a8586SSepherosa Ziehau static int 5812695a8586SSepherosa Ziehau bnx_alloc_msix(struct bnx_softc *sc) 5813695a8586SSepherosa Ziehau { 5814695a8586SSepherosa Ziehau struct bnx_intr_data *intr; 5815695a8586SSepherosa Ziehau boolean_t setup = FALSE; 5816695a8586SSepherosa Ziehau int error, i, offset, offset_def; 5817695a8586SSepherosa Ziehau 5818695a8586SSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt > 1); 5819695a8586SSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt == sc->bnx_rx_retcnt + 1); 5820695a8586SSepherosa Ziehau 5821695a8586SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_RXTX_BUNDLE) { 5822695a8586SSepherosa Ziehau /* 5823695a8586SSepherosa Ziehau * Link status 5824695a8586SSepherosa Ziehau */ 5825695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 5826695a8586SSepherosa Ziehau 5827695a8586SSepherosa Ziehau intr->bnx_intr_serialize = &sc->bnx_main_serialize; 5828695a8586SSepherosa Ziehau intr->bnx_saved_status_tag = &sc->bnx_saved_status_tag; 5829695a8586SSepherosa Ziehau 5830695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_status; 5831695a8586SSepherosa Ziehau intr->bnx_intr_arg = sc; 5832695a8586SSepherosa Ziehau intr->bnx_intr_cpuid = 0; /* XXX */ 5833695a8586SSepherosa Ziehau 5834695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, sizeof(intr->bnx_intr_desc0), 5835695a8586SSepherosa Ziehau "%s sts", device_get_nameunit(sc->bnx_dev)); 5836695a8586SSepherosa Ziehau intr->bnx_intr_desc = intr->bnx_intr_desc0; 5837695a8586SSepherosa Ziehau 5838695a8586SSepherosa Ziehau /* 5839695a8586SSepherosa Ziehau * RX/TX rings 5840695a8586SSepherosa Ziehau */ 5841695a8586SSepherosa Ziehau if (sc->bnx_rx_retcnt == ncpus2) { 5842695a8586SSepherosa Ziehau offset = 0; 5843695a8586SSepherosa Ziehau } else { 5844695a8586SSepherosa Ziehau offset_def = (sc->bnx_rx_retcnt * 5845695a8586SSepherosa Ziehau device_get_unit(sc->bnx_dev)) % ncpus2; 5846695a8586SSepherosa Ziehau 5847695a8586SSepherosa Ziehau offset = device_getenv_int(sc->bnx_dev, 5848695a8586SSepherosa Ziehau "msix.offset", offset_def); 5849695a8586SSepherosa Ziehau if (offset >= ncpus2 || 5850695a8586SSepherosa Ziehau offset % sc->bnx_rx_retcnt != 0) { 5851695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, 5852695a8586SSepherosa Ziehau "invalid msix.offset %d, use %d\n", 5853695a8586SSepherosa Ziehau offset, offset_def); 5854695a8586SSepherosa Ziehau offset = offset_def; 5855695a8586SSepherosa Ziehau } 5856695a8586SSepherosa Ziehau } 5857695a8586SSepherosa Ziehau 5858695a8586SSepherosa Ziehau for (i = 1; i < sc->bnx_intr_cnt; ++i) { 5859695a8586SSepherosa Ziehau int idx = i - 1; 5860695a8586SSepherosa Ziehau 5861695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[i]; 5862695a8586SSepherosa Ziehau 5863695a8586SSepherosa Ziehau KKASSERT(idx < sc->bnx_rx_retcnt); 5864695a8586SSepherosa Ziehau intr->bnx_ret = &sc->bnx_rx_ret_ring[idx]; 5865695a8586SSepherosa Ziehau if (idx < sc->bnx_tx_ringcnt) { 5866695a8586SSepherosa Ziehau intr->bnx_txr = &sc->bnx_tx_ring[idx]; 5867695a8586SSepherosa Ziehau intr->bnx_ret->bnx_txr = intr->bnx_txr; 5868695a8586SSepherosa Ziehau } 5869695a8586SSepherosa Ziehau 5870695a8586SSepherosa Ziehau intr->bnx_intr_serialize = 5871695a8586SSepherosa Ziehau &intr->bnx_ret->bnx_rx_ret_serialize; 5872695a8586SSepherosa Ziehau intr->bnx_saved_status_tag = 5873695a8586SSepherosa Ziehau &intr->bnx_ret->bnx_saved_status_tag; 5874695a8586SSepherosa Ziehau 5875695a8586SSepherosa Ziehau intr->bnx_intr_arg = intr->bnx_ret; 5876695a8586SSepherosa Ziehau KKASSERT(idx + offset < ncpus2); 5877695a8586SSepherosa Ziehau intr->bnx_intr_cpuid = idx + offset; 5878695a8586SSepherosa Ziehau 5879695a8586SSepherosa Ziehau if (intr->bnx_txr == NULL) { 5880695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_rx; 5881695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_rx; 5882695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, 5883695a8586SSepherosa Ziehau sizeof(intr->bnx_intr_desc0), "%s rx%d", 5884695a8586SSepherosa Ziehau device_get_nameunit(sc->bnx_dev), idx); 5885695a8586SSepherosa Ziehau } else { 5886695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_rxtx; 5887695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_rxtx; 5888695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, 5889695a8586SSepherosa Ziehau sizeof(intr->bnx_intr_desc0), "%s rxtx%d", 5890695a8586SSepherosa Ziehau device_get_nameunit(sc->bnx_dev), idx); 5891695a8586SSepherosa Ziehau 5892695a8586SSepherosa Ziehau intr->bnx_txr->bnx_tx_cpuid = 5893695a8586SSepherosa Ziehau intr->bnx_intr_cpuid; 5894695a8586SSepherosa Ziehau } 5895695a8586SSepherosa Ziehau intr->bnx_intr_desc = intr->bnx_intr_desc0; 5896695a8586SSepherosa Ziehau 5897695a8586SSepherosa Ziehau intr->bnx_ret->bnx_msix_mbx = intr->bnx_intr_mbx; 5898695a8586SSepherosa Ziehau } 5899695a8586SSepherosa Ziehau } else { 5900695a8586SSepherosa Ziehau /* 5901695a8586SSepherosa Ziehau * TX ring and link status 5902695a8586SSepherosa Ziehau */ 5903695a8586SSepherosa Ziehau offset_def = device_get_unit(sc->bnx_dev) % ncpus2; 5904695a8586SSepherosa Ziehau offset = device_getenv_int(sc->bnx_dev, "msix.txoff", 5905695a8586SSepherosa Ziehau offset_def); 5906695a8586SSepherosa Ziehau if (offset >= ncpus2) { 5907695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, 5908695a8586SSepherosa Ziehau "invalid msix.txoff %d, use %d\n", 5909695a8586SSepherosa Ziehau offset, offset_def); 5910695a8586SSepherosa Ziehau offset = offset_def; 5911695a8586SSepherosa Ziehau } 5912695a8586SSepherosa Ziehau 5913695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 5914695a8586SSepherosa Ziehau 5915695a8586SSepherosa Ziehau intr->bnx_txr = &sc->bnx_tx_ring[0]; 5916695a8586SSepherosa Ziehau intr->bnx_intr_serialize = &sc->bnx_main_serialize; 5917695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_tx; 5918695a8586SSepherosa Ziehau intr->bnx_saved_status_tag = 5919695a8586SSepherosa Ziehau &intr->bnx_txr->bnx_saved_status_tag; 5920695a8586SSepherosa Ziehau 5921695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_tx_status; 5922695a8586SSepherosa Ziehau intr->bnx_intr_arg = intr->bnx_txr; 5923695a8586SSepherosa Ziehau intr->bnx_intr_cpuid = offset; 5924695a8586SSepherosa Ziehau 5925695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, sizeof(intr->bnx_intr_desc0), 5926695a8586SSepherosa Ziehau "%s ststx", device_get_nameunit(sc->bnx_dev)); 5927695a8586SSepherosa Ziehau intr->bnx_intr_desc = intr->bnx_intr_desc0; 5928695a8586SSepherosa Ziehau 5929695a8586SSepherosa Ziehau intr->bnx_txr->bnx_tx_cpuid = intr->bnx_intr_cpuid; 5930695a8586SSepherosa Ziehau 5931695a8586SSepherosa Ziehau /* 5932695a8586SSepherosa Ziehau * RX rings 5933695a8586SSepherosa Ziehau */ 5934695a8586SSepherosa Ziehau if (sc->bnx_rx_retcnt == ncpus2) { 5935695a8586SSepherosa Ziehau offset = 0; 5936695a8586SSepherosa Ziehau } else { 5937695a8586SSepherosa Ziehau offset_def = (sc->bnx_rx_retcnt * 5938695a8586SSepherosa Ziehau device_get_unit(sc->bnx_dev)) % ncpus2; 5939695a8586SSepherosa Ziehau 5940695a8586SSepherosa Ziehau offset = device_getenv_int(sc->bnx_dev, 5941695a8586SSepherosa Ziehau "msix.rxoff", offset_def); 5942695a8586SSepherosa Ziehau if (offset >= ncpus2 || 5943695a8586SSepherosa Ziehau offset % sc->bnx_rx_retcnt != 0) { 5944695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, 5945695a8586SSepherosa Ziehau "invalid msix.rxoff %d, use %d\n", 5946695a8586SSepherosa Ziehau offset, offset_def); 5947695a8586SSepherosa Ziehau offset = offset_def; 5948695a8586SSepherosa Ziehau } 5949695a8586SSepherosa Ziehau } 5950695a8586SSepherosa Ziehau 5951695a8586SSepherosa Ziehau for (i = 1; i < sc->bnx_intr_cnt; ++i) { 5952695a8586SSepherosa Ziehau int idx = i - 1; 5953695a8586SSepherosa Ziehau 5954695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[i]; 5955695a8586SSepherosa Ziehau 5956695a8586SSepherosa Ziehau KKASSERT(idx < sc->bnx_rx_retcnt); 5957695a8586SSepherosa Ziehau intr->bnx_ret = &sc->bnx_rx_ret_ring[idx]; 5958695a8586SSepherosa Ziehau intr->bnx_intr_serialize = 5959695a8586SSepherosa Ziehau &intr->bnx_ret->bnx_rx_ret_serialize; 5960695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_rx; 5961695a8586SSepherosa Ziehau intr->bnx_saved_status_tag = 5962695a8586SSepherosa Ziehau &intr->bnx_ret->bnx_saved_status_tag; 5963695a8586SSepherosa Ziehau 5964695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_rx; 5965695a8586SSepherosa Ziehau intr->bnx_intr_arg = intr->bnx_ret; 5966695a8586SSepherosa Ziehau KKASSERT(idx + offset < ncpus2); 5967695a8586SSepherosa Ziehau intr->bnx_intr_cpuid = idx + offset; 5968695a8586SSepherosa Ziehau 5969695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, 5970695a8586SSepherosa Ziehau sizeof(intr->bnx_intr_desc0), "%s rx%d", 5971695a8586SSepherosa Ziehau device_get_nameunit(sc->bnx_dev), idx); 5972695a8586SSepherosa Ziehau intr->bnx_intr_desc = intr->bnx_intr_desc0; 5973695a8586SSepherosa Ziehau 5974695a8586SSepherosa Ziehau intr->bnx_ret->bnx_msix_mbx = intr->bnx_intr_mbx; 5975695a8586SSepherosa Ziehau } 5976695a8586SSepherosa Ziehau } 5977695a8586SSepherosa Ziehau 5978695a8586SSepherosa Ziehau sc->bnx_msix_mem_rid = PCIR_BAR(4); 5979695a8586SSepherosa Ziehau sc->bnx_msix_mem_res = bus_alloc_resource_any(sc->bnx_dev, 5980695a8586SSepherosa Ziehau SYS_RES_MEMORY, &sc->bnx_msix_mem_rid, RF_ACTIVE); 5981695a8586SSepherosa Ziehau if (sc->bnx_msix_mem_res == NULL) { 5982695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, "could not alloc MSI-X table\n"); 5983695a8586SSepherosa Ziehau return ENXIO; 5984695a8586SSepherosa Ziehau } 5985695a8586SSepherosa Ziehau 5986695a8586SSepherosa Ziehau bnx_enable_msi(sc, TRUE); 5987695a8586SSepherosa Ziehau 5988695a8586SSepherosa Ziehau error = pci_setup_msix(sc->bnx_dev); 5989695a8586SSepherosa Ziehau if (error) { 5990695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, "could not setup MSI-X\n"); 5991695a8586SSepherosa Ziehau goto back; 5992695a8586SSepherosa Ziehau } 5993695a8586SSepherosa Ziehau setup = TRUE; 5994695a8586SSepherosa Ziehau 5995695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 5996695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[i]; 5997695a8586SSepherosa Ziehau 5998695a8586SSepherosa Ziehau error = pci_alloc_msix_vector(sc->bnx_dev, i, 5999695a8586SSepherosa Ziehau &intr->bnx_intr_rid, intr->bnx_intr_cpuid); 6000695a8586SSepherosa Ziehau if (error) { 6001695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, 6002695a8586SSepherosa Ziehau "could not alloc MSI-X %d on cpu%d\n", 6003695a8586SSepherosa Ziehau i, intr->bnx_intr_cpuid); 6004695a8586SSepherosa Ziehau goto back; 6005695a8586SSepherosa Ziehau } 6006695a8586SSepherosa Ziehau 6007695a8586SSepherosa Ziehau intr->bnx_intr_res = bus_alloc_resource_any(sc->bnx_dev, 6008695a8586SSepherosa Ziehau SYS_RES_IRQ, &intr->bnx_intr_rid, RF_ACTIVE); 6009695a8586SSepherosa Ziehau if (intr->bnx_intr_res == NULL) { 6010695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, 6011695a8586SSepherosa Ziehau "could not alloc MSI-X %d resource\n", i); 6012695a8586SSepherosa Ziehau error = ENXIO; 6013695a8586SSepherosa Ziehau goto back; 6014695a8586SSepherosa Ziehau } 6015695a8586SSepherosa Ziehau } 6016695a8586SSepherosa Ziehau 6017695a8586SSepherosa Ziehau pci_enable_msix(sc->bnx_dev); 6018695a8586SSepherosa Ziehau sc->bnx_intr_type = PCI_INTR_TYPE_MSIX; 6019695a8586SSepherosa Ziehau back: 6020695a8586SSepherosa Ziehau if (error) 6021695a8586SSepherosa Ziehau bnx_free_msix(sc, setup); 6022695a8586SSepherosa Ziehau return error; 6023695a8586SSepherosa Ziehau } 6024695a8586SSepherosa Ziehau 6025695a8586SSepherosa Ziehau static void 6026695a8586SSepherosa Ziehau bnx_free_msix(struct bnx_softc *sc, boolean_t setup) 6027695a8586SSepherosa Ziehau { 6028695a8586SSepherosa Ziehau int i; 6029695a8586SSepherosa Ziehau 6030695a8586SSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt > 1); 6031695a8586SSepherosa Ziehau 6032695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 6033695a8586SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 6034695a8586SSepherosa Ziehau 6035695a8586SSepherosa Ziehau if (intr->bnx_intr_res != NULL) { 6036695a8586SSepherosa Ziehau bus_release_resource(sc->bnx_dev, SYS_RES_IRQ, 6037695a8586SSepherosa Ziehau intr->bnx_intr_rid, intr->bnx_intr_res); 6038695a8586SSepherosa Ziehau } 6039695a8586SSepherosa Ziehau if (intr->bnx_intr_rid >= 0) { 6040695a8586SSepherosa Ziehau pci_release_msix_vector(sc->bnx_dev, 6041695a8586SSepherosa Ziehau intr->bnx_intr_rid); 6042695a8586SSepherosa Ziehau } 6043695a8586SSepherosa Ziehau } 6044695a8586SSepherosa Ziehau if (setup) 6045695a8586SSepherosa Ziehau pci_teardown_msix(sc->bnx_dev); 6046695a8586SSepherosa Ziehau } 6047695a8586SSepherosa Ziehau 6048695a8586SSepherosa Ziehau static void 6049695a8586SSepherosa Ziehau bnx_rx_std_refill_sched_ipi(void *xret) 6050695a8586SSepherosa Ziehau { 6051695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret = xret; 6052695a8586SSepherosa Ziehau struct bnx_rx_std_ring *std = ret->bnx_std; 6053695a8586SSepherosa Ziehau struct globaldata *gd = mycpu; 6054695a8586SSepherosa Ziehau 6055695a8586SSepherosa Ziehau crit_enter_gd(gd); 6056695a8586SSepherosa Ziehau 6057695a8586SSepherosa Ziehau atomic_set_int(&std->bnx_rx_std_refill, ret->bnx_rx_mask); 6058695a8586SSepherosa Ziehau cpu_sfence(); 6059695a8586SSepherosa Ziehau 6060695a8586SSepherosa Ziehau KKASSERT(std->bnx_rx_std_ithread.td_gd == gd); 6061695a8586SSepherosa Ziehau lwkt_schedule(&std->bnx_rx_std_ithread); 6062695a8586SSepherosa Ziehau 6063695a8586SSepherosa Ziehau crit_exit_gd(gd); 6064695a8586SSepherosa Ziehau } 6065695a8586SSepherosa Ziehau 6066695a8586SSepherosa Ziehau static void 6067695a8586SSepherosa Ziehau bnx_rx_std_refill_stop(void *xstd) 6068695a8586SSepherosa Ziehau { 6069695a8586SSepherosa Ziehau struct bnx_rx_std_ring *std = xstd; 6070695a8586SSepherosa Ziehau struct globaldata *gd = mycpu; 6071695a8586SSepherosa Ziehau 6072695a8586SSepherosa Ziehau crit_enter_gd(gd); 6073695a8586SSepherosa Ziehau 6074695a8586SSepherosa Ziehau std->bnx_rx_std_stop = 1; 6075695a8586SSepherosa Ziehau cpu_sfence(); 6076695a8586SSepherosa Ziehau 6077695a8586SSepherosa Ziehau KKASSERT(std->bnx_rx_std_ithread.td_gd == gd); 6078695a8586SSepherosa Ziehau lwkt_schedule(&std->bnx_rx_std_ithread); 6079695a8586SSepherosa Ziehau 6080695a8586SSepherosa Ziehau crit_exit_gd(gd); 6081695a8586SSepherosa Ziehau } 6082695a8586SSepherosa Ziehau 6083695a8586SSepherosa Ziehau static void 6084695a8586SSepherosa Ziehau bnx_serialize_skipmain(struct bnx_softc *sc) 6085695a8586SSepherosa Ziehau { 6086695a8586SSepherosa Ziehau lwkt_serialize_array_enter(sc->bnx_serialize, 6087695a8586SSepherosa Ziehau sc->bnx_serialize_cnt, 1); 6088695a8586SSepherosa Ziehau } 6089695a8586SSepherosa Ziehau 6090695a8586SSepherosa Ziehau static void 6091695a8586SSepherosa Ziehau bnx_deserialize_skipmain(struct bnx_softc *sc) 6092695a8586SSepherosa Ziehau { 6093695a8586SSepherosa Ziehau lwkt_serialize_array_exit(sc->bnx_serialize, 6094695a8586SSepherosa Ziehau sc->bnx_serialize_cnt, 1); 6095695a8586SSepherosa Ziehau } 6096695a8586SSepherosa Ziehau 6097695a8586SSepherosa Ziehau static void 6098695a8586SSepherosa Ziehau bnx_rx_std_refill_sched(struct bnx_rx_ret_ring *ret, 6099695a8586SSepherosa Ziehau struct bnx_rx_std_ring *std) 6100695a8586SSepherosa Ziehau { 6101695a8586SSepherosa Ziehau struct globaldata *gd = mycpu; 6102695a8586SSepherosa Ziehau 6103695a8586SSepherosa Ziehau ret->bnx_rx_cnt = 0; 6104695a8586SSepherosa Ziehau cpu_sfence(); 6105695a8586SSepherosa Ziehau 6106695a8586SSepherosa Ziehau crit_enter_gd(gd); 6107695a8586SSepherosa Ziehau 6108695a8586SSepherosa Ziehau atomic_set_int(&std->bnx_rx_std_refill, ret->bnx_rx_mask); 6109695a8586SSepherosa Ziehau cpu_sfence(); 6110695a8586SSepherosa Ziehau if (atomic_poll_acquire_int(&std->bnx_rx_std_running)) { 6111695a8586SSepherosa Ziehau if (std->bnx_rx_std_ithread.td_gd == gd) { 6112695a8586SSepherosa Ziehau lwkt_schedule(&std->bnx_rx_std_ithread); 6113695a8586SSepherosa Ziehau } else { 6114695a8586SSepherosa Ziehau lwkt_send_ipiq( 6115695a8586SSepherosa Ziehau std->bnx_rx_std_ithread.td_gd, 6116695a8586SSepherosa Ziehau bnx_rx_std_refill_sched_ipi, ret); 6117695a8586SSepherosa Ziehau } 6118695a8586SSepherosa Ziehau } 6119695a8586SSepherosa Ziehau 6120695a8586SSepherosa Ziehau crit_exit_gd(gd); 6121695a8586SSepherosa Ziehau } 6122b19ddf7eSSepherosa Ziehau 6123b19ddf7eSSepherosa Ziehau static struct pktinfo * 6124b19ddf7eSSepherosa Ziehau bnx_rss_info(struct pktinfo *pi, const struct bge_rx_bd *cur_rx) 6125b19ddf7eSSepherosa Ziehau { 6126b19ddf7eSSepherosa Ziehau /* Don't pick up IPv6 packet */ 6127b19ddf7eSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_IPV6) 6128b19ddf7eSSepherosa Ziehau return NULL; 6129b19ddf7eSSepherosa Ziehau 6130b19ddf7eSSepherosa Ziehau /* Don't pick up IP packet w/o IP checksum */ 6131b19ddf7eSSepherosa Ziehau if ((cur_rx->bge_flags & BGE_RXBDFLAG_IP_CSUM) == 0 || 6132b19ddf7eSSepherosa Ziehau (cur_rx->bge_error_flag & BGE_RXERRFLAG_IP_CSUM_NOK)) 6133b19ddf7eSSepherosa Ziehau return NULL; 6134b19ddf7eSSepherosa Ziehau 6135b19ddf7eSSepherosa Ziehau /* Don't pick up IP packet w/o TCP/UDP checksum */ 6136b19ddf7eSSepherosa Ziehau if ((cur_rx->bge_flags & BGE_RXBDFLAG_TCP_UDP_CSUM) == 0) 6137b19ddf7eSSepherosa Ziehau return NULL; 6138b19ddf7eSSepherosa Ziehau 6139b19ddf7eSSepherosa Ziehau /* May be IP fragment */ 6140b19ddf7eSSepherosa Ziehau if (cur_rx->bge_tcp_udp_csum != 0xffff) 6141b19ddf7eSSepherosa Ziehau return NULL; 6142b19ddf7eSSepherosa Ziehau 6143b19ddf7eSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_TCP_UDP_IS_TCP) 6144b19ddf7eSSepherosa Ziehau pi->pi_l3proto = IPPROTO_TCP; 6145b19ddf7eSSepherosa Ziehau else 6146b19ddf7eSSepherosa Ziehau pi->pi_l3proto = IPPROTO_UDP; 6147b19ddf7eSSepherosa Ziehau pi->pi_netisr = NETISR_IP; 6148b19ddf7eSSepherosa Ziehau pi->pi_flags = 0; 6149b19ddf7eSSepherosa Ziehau 6150b19ddf7eSSepherosa Ziehau return pi; 6151b19ddf7eSSepherosa Ziehau } 6152