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 74dcb4b80dSSascha Wildner #include "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 864aa71e73SSepherosa Ziehau #define BNX_RESET_SHUTDOWN 0 874aa71e73SSepherosa Ziehau #define BNX_RESET_START 1 884aa71e73SSepherosa Ziehau #define BNX_RESET_SUSPEND 2 894aa71e73SSepherosa Ziehau 90df9ccc98SSepherosa Ziehau #define BNX_INTR_CKINTVL ((10 * hz) / 1000) /* 10ms */ 91df9ccc98SSepherosa Ziehau 92695a8586SSepherosa Ziehau #ifdef BNX_RSS_DEBUG 93695a8586SSepherosa Ziehau #define BNX_RSS_DPRINTF(sc, lvl, fmt, ...) \ 94695a8586SSepherosa Ziehau do { \ 95695a8586SSepherosa Ziehau if (sc->bnx_rss_debug >= lvl) \ 96695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, fmt, __VA_ARGS__); \ 97695a8586SSepherosa Ziehau } while (0) 98695a8586SSepherosa Ziehau #else /* !BNX_RSS_DEBUG */ 99695a8586SSepherosa Ziehau #define BNX_RSS_DPRINTF(sc, lvl, fmt, ...) ((void)0) 100695a8586SSepherosa Ziehau #endif /* BNX_RSS_DEBUG */ 101695a8586SSepherosa Ziehau 1026c8d8eccSSepherosa Ziehau static const struct bnx_type { 1036c8d8eccSSepherosa Ziehau uint16_t bnx_vid; 1046c8d8eccSSepherosa Ziehau uint16_t bnx_did; 1056c8d8eccSSepherosa Ziehau char *bnx_name; 1066c8d8eccSSepherosa Ziehau } bnx_devs[] = { 1076c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5717, 1086c8d8eccSSepherosa Ziehau "Broadcom BCM5717 Gigabit Ethernet" }, 109d79f5d8fSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5717C, 110d79f5d8fSSepherosa Ziehau "Broadcom BCM5717C Gigabit Ethernet" }, 1116c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5718, 1126c8d8eccSSepherosa Ziehau "Broadcom BCM5718 Gigabit Ethernet" }, 1136c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5719, 1146c8d8eccSSepherosa Ziehau "Broadcom BCM5719 Gigabit Ethernet" }, 1156c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5720_ALT, 1166c8d8eccSSepherosa Ziehau "Broadcom BCM5720 Gigabit Ethernet" }, 1176c8d8eccSSepherosa Ziehau 118b96cbbb6SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5725, 119b96cbbb6SSepherosa Ziehau "Broadcom BCM5725 Gigabit Ethernet" }, 120b96cbbb6SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5727, 121b96cbbb6SSepherosa Ziehau "Broadcom BCM5727 Gigabit Ethernet" }, 122b96cbbb6SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5762, 123b96cbbb6SSepherosa Ziehau "Broadcom BCM5762 Gigabit Ethernet" }, 124b96cbbb6SSepherosa Ziehau 1256c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57761, 1266c8d8eccSSepherosa Ziehau "Broadcom BCM57761 Gigabit Ethernet" }, 12732ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57762, 12832ff3c80SSepherosa Ziehau "Broadcom BCM57762 Gigabit Ethernet" }, 1296c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57765, 1306c8d8eccSSepherosa Ziehau "Broadcom BCM57765 Gigabit Ethernet" }, 13132ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57766, 13232ff3c80SSepherosa Ziehau "Broadcom BCM57766 Gigabit Ethernet" }, 13332ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57781, 13432ff3c80SSepherosa Ziehau "Broadcom BCM57781 Gigabit Ethernet" }, 13532ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57782, 13632ff3c80SSepherosa Ziehau "Broadcom BCM57782 Gigabit Ethernet" }, 1376c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57785, 1386c8d8eccSSepherosa Ziehau "Broadcom BCM57785 Gigabit Ethernet" }, 13932ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57786, 14032ff3c80SSepherosa Ziehau "Broadcom BCM57786 Gigabit Ethernet" }, 14132ff3c80SSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57791, 14232ff3c80SSepherosa Ziehau "Broadcom BCM57791 Fast Ethernet" }, 1436c8d8eccSSepherosa Ziehau { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM57795, 1446c8d8eccSSepherosa Ziehau "Broadcom BCM57795 Fast Ethernet" }, 1456c8d8eccSSepherosa Ziehau 1466c8d8eccSSepherosa Ziehau { 0, 0, NULL } 1476c8d8eccSSepherosa Ziehau }; 1486c8d8eccSSepherosa Ziehau 1491c9d03f6SSepherosa Ziehau static const int bnx_tx_mailbox[BNX_TX_RING_MAX] = { 1501c9d03f6SSepherosa Ziehau BGE_MBX_TX_HOST_PROD0_LO, 1511c9d03f6SSepherosa Ziehau BGE_MBX_TX_HOST_PROD0_HI, 1521c9d03f6SSepherosa Ziehau BGE_MBX_TX_HOST_PROD1_LO, 1531c9d03f6SSepherosa Ziehau BGE_MBX_TX_HOST_PROD1_HI 1541c9d03f6SSepherosa Ziehau }; 1551c9d03f6SSepherosa Ziehau 1566c8d8eccSSepherosa Ziehau #define BNX_IS_JUMBO_CAPABLE(sc) ((sc)->bnx_flags & BNX_FLAG_JUMBO) 1576c8d8eccSSepherosa Ziehau #define BNX_IS_5717_PLUS(sc) ((sc)->bnx_flags & BNX_FLAG_5717_PLUS) 158f368d0d9SSepherosa Ziehau #define BNX_IS_57765_PLUS(sc) ((sc)->bnx_flags & BNX_FLAG_57765_PLUS) 159f368d0d9SSepherosa Ziehau #define BNX_IS_57765_FAMILY(sc) \ 160f368d0d9SSepherosa Ziehau ((sc)->bnx_flags & BNX_FLAG_57765_FAMILY) 1616c8d8eccSSepherosa Ziehau 1626c8d8eccSSepherosa Ziehau typedef int (*bnx_eaddr_fcn_t)(struct bnx_softc *, uint8_t[]); 1636c8d8eccSSepherosa Ziehau 1646c8d8eccSSepherosa Ziehau static int bnx_probe(device_t); 1656c8d8eccSSepherosa Ziehau static int bnx_attach(device_t); 1666c8d8eccSSepherosa Ziehau static int bnx_detach(device_t); 1676c8d8eccSSepherosa Ziehau static void bnx_shutdown(device_t); 1686c8d8eccSSepherosa Ziehau static int bnx_suspend(device_t); 1696c8d8eccSSepherosa Ziehau static int bnx_resume(device_t); 1706c8d8eccSSepherosa Ziehau static int bnx_miibus_readreg(device_t, int, int); 1716c8d8eccSSepherosa Ziehau static int bnx_miibus_writereg(device_t, int, int, int); 1726c8d8eccSSepherosa Ziehau static void bnx_miibus_statchg(device_t); 1736c8d8eccSSepherosa Ziehau 17424e16e4bSSepherosa Ziehau static int bnx_handle_status(struct bnx_softc *); 17539a8d43aSSepherosa Ziehau #ifdef IFPOLL_ENABLE 17639a8d43aSSepherosa Ziehau static void bnx_npoll(struct ifnet *, struct ifpoll_info *); 1774fa38985SSepherosa Ziehau static void bnx_npoll_rx(struct ifnet *, void *, int); 1784fa38985SSepherosa Ziehau static void bnx_npoll_tx(struct ifnet *, void *, int); 179695a8586SSepherosa Ziehau static void bnx_npoll_tx_notag(struct ifnet *, void *, int); 1804fa38985SSepherosa Ziehau static void bnx_npoll_status(struct ifnet *); 181695a8586SSepherosa Ziehau static void bnx_npoll_status_notag(struct ifnet *); 1826c8d8eccSSepherosa Ziehau #endif 1836c8d8eccSSepherosa Ziehau static void bnx_intr_legacy(void *); 18403cc99fdSSepherosa Ziehau static void bnx_msi(void *); 1856c8d8eccSSepherosa Ziehau static void bnx_intr(struct bnx_softc *); 186695a8586SSepherosa Ziehau static void bnx_msix_status(void *); 187695a8586SSepherosa Ziehau static void bnx_msix_tx_status(void *); 188695a8586SSepherosa Ziehau static void bnx_msix_rx(void *); 189695a8586SSepherosa Ziehau static void bnx_msix_rxtx(void *); 1906c8d8eccSSepherosa Ziehau static void bnx_enable_intr(struct bnx_softc *); 1916c8d8eccSSepherosa Ziehau static void bnx_disable_intr(struct bnx_softc *); 19233a04907SSepherosa Ziehau static void bnx_txeof(struct bnx_tx_ring *, uint16_t); 193beedf5beSSepherosa Ziehau static void bnx_rxeof(struct bnx_rx_ret_ring *, uint16_t, int); 1940c7da01dSSepherosa Ziehau static int bnx_alloc_intr(struct bnx_softc *); 1950c7da01dSSepherosa Ziehau static int bnx_setup_intr(struct bnx_softc *); 1960c7da01dSSepherosa Ziehau static void bnx_free_intr(struct bnx_softc *); 197f33ac8a4SSepherosa Ziehau static void bnx_teardown_intr(struct bnx_softc *, int); 198695a8586SSepherosa Ziehau static int bnx_alloc_msix(struct bnx_softc *); 199695a8586SSepherosa Ziehau static void bnx_free_msix(struct bnx_softc *, boolean_t); 200695a8586SSepherosa Ziehau static void bnx_check_intr_rxtx(void *); 201695a8586SSepherosa Ziehau static void bnx_check_intr_rx(void *); 202695a8586SSepherosa Ziehau static void bnx_check_intr_tx(void *); 203841cdf08SSepherosa Ziehau static void bnx_rx_std_refill_ithread(void *); 204841cdf08SSepherosa Ziehau static void bnx_rx_std_refill(void *, void *); 205695a8586SSepherosa Ziehau static void bnx_rx_std_refill_sched_ipi(void *); 206695a8586SSepherosa Ziehau static void bnx_rx_std_refill_stop(void *); 207695a8586SSepherosa Ziehau static void bnx_rx_std_refill_sched(struct bnx_rx_ret_ring *, 208695a8586SSepherosa Ziehau struct bnx_rx_std_ring *); 2096c8d8eccSSepherosa Ziehau 210f0a26983SSepherosa Ziehau static void bnx_start(struct ifnet *, struct ifaltq_subque *); 2116c8d8eccSSepherosa Ziehau static int bnx_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 2126c8d8eccSSepherosa Ziehau static void bnx_init(void *); 2136c8d8eccSSepherosa Ziehau static void bnx_stop(struct bnx_softc *); 2143397dea6SSepherosa Ziehau static void bnx_watchdog(struct ifaltq_subque *); 2156c8d8eccSSepherosa Ziehau static int bnx_ifmedia_upd(struct ifnet *); 2166c8d8eccSSepherosa Ziehau static void bnx_ifmedia_sts(struct ifnet *, struct ifmediareq *); 2176c8d8eccSSepherosa Ziehau static void bnx_tick(void *); 218329f9016SSepherosa Ziehau static void bnx_serialize(struct ifnet *, enum ifnet_serialize); 219329f9016SSepherosa Ziehau static void bnx_deserialize(struct ifnet *, enum ifnet_serialize); 220329f9016SSepherosa Ziehau static int bnx_tryserialize(struct ifnet *, enum ifnet_serialize); 221329f9016SSepherosa Ziehau #ifdef INVARIANTS 222329f9016SSepherosa Ziehau static void bnx_serialize_assert(struct ifnet *, enum ifnet_serialize, 223329f9016SSepherosa Ziehau boolean_t); 224329f9016SSepherosa Ziehau #endif 225695a8586SSepherosa Ziehau static void bnx_serialize_skipmain(struct bnx_softc *); 226695a8586SSepherosa Ziehau static void bnx_deserialize_skipmain(struct bnx_softc *sc); 2276c8d8eccSSepherosa Ziehau 2286c8d8eccSSepherosa Ziehau static int bnx_alloc_jumbo_mem(struct bnx_softc *); 2296c8d8eccSSepherosa Ziehau static void bnx_free_jumbo_mem(struct bnx_softc *); 2306c8d8eccSSepherosa Ziehau static struct bnx_jslot 2316c8d8eccSSepherosa Ziehau *bnx_jalloc(struct bnx_softc *); 2326c8d8eccSSepherosa Ziehau static void bnx_jfree(void *); 2336c8d8eccSSepherosa Ziehau static void bnx_jref(void *); 234beedf5beSSepherosa Ziehau static int bnx_newbuf_std(struct bnx_rx_ret_ring *, int, int); 2356c8d8eccSSepherosa Ziehau static int bnx_newbuf_jumbo(struct bnx_softc *, int, int); 236beedf5beSSepherosa Ziehau static void bnx_setup_rxdesc_std(struct bnx_rx_std_ring *, int); 2376c8d8eccSSepherosa Ziehau static void bnx_setup_rxdesc_jumbo(struct bnx_softc *, int); 238beedf5beSSepherosa Ziehau static int bnx_init_rx_ring_std(struct bnx_rx_std_ring *); 239beedf5beSSepherosa Ziehau static void bnx_free_rx_ring_std(struct bnx_rx_std_ring *); 2406c8d8eccSSepherosa Ziehau static int bnx_init_rx_ring_jumbo(struct bnx_softc *); 2416c8d8eccSSepherosa Ziehau static void bnx_free_rx_ring_jumbo(struct bnx_softc *); 24233a04907SSepherosa Ziehau static void bnx_free_tx_ring(struct bnx_tx_ring *); 24333a04907SSepherosa Ziehau static int bnx_init_tx_ring(struct bnx_tx_ring *); 24433a04907SSepherosa Ziehau static int bnx_create_tx_ring(struct bnx_tx_ring *); 24533a04907SSepherosa Ziehau static void bnx_destroy_tx_ring(struct bnx_tx_ring *); 246beedf5beSSepherosa Ziehau static int bnx_create_rx_ret_ring(struct bnx_rx_ret_ring *); 247beedf5beSSepherosa Ziehau static void bnx_destroy_rx_ret_ring(struct bnx_rx_ret_ring *); 248beedf5beSSepherosa Ziehau static int bnx_dma_alloc(device_t); 2496c8d8eccSSepherosa Ziehau static void bnx_dma_free(struct bnx_softc *); 2506c8d8eccSSepherosa Ziehau static int bnx_dma_block_alloc(struct bnx_softc *, bus_size_t, 2516c8d8eccSSepherosa Ziehau bus_dma_tag_t *, bus_dmamap_t *, void **, bus_addr_t *); 2526c8d8eccSSepherosa Ziehau static void bnx_dma_block_free(bus_dma_tag_t, bus_dmamap_t, void *); 2536c8d8eccSSepherosa Ziehau static struct mbuf * 2546c8d8eccSSepherosa Ziehau bnx_defrag_shortdma(struct mbuf *); 25533a04907SSepherosa Ziehau static int bnx_encap(struct bnx_tx_ring *, struct mbuf **, 256c9b7f592SSepherosa Ziehau uint32_t *, int *); 25733a04907SSepherosa Ziehau static int bnx_setup_tso(struct bnx_tx_ring *, struct mbuf **, 25866deb1c1SSepherosa Ziehau uint16_t *, uint16_t *); 259329f9016SSepherosa Ziehau static void bnx_setup_serialize(struct bnx_softc *); 2607dbaa833SSepherosa Ziehau static void bnx_set_tick_cpuid(struct bnx_softc *, boolean_t); 261695a8586SSepherosa Ziehau static void bnx_setup_ring_cnt(struct bnx_softc *); 2626c8d8eccSSepherosa Ziehau 263b19ddf7eSSepherosa Ziehau static struct pktinfo *bnx_rss_info(struct pktinfo *, 264b19ddf7eSSepherosa Ziehau const struct bge_rx_bd *); 265695a8586SSepherosa Ziehau static void bnx_init_rss(struct bnx_softc *); 2666c8d8eccSSepherosa Ziehau static void bnx_reset(struct bnx_softc *); 2676c8d8eccSSepherosa Ziehau static int bnx_chipinit(struct bnx_softc *); 2686c8d8eccSSepherosa Ziehau static int bnx_blockinit(struct bnx_softc *); 2696c8d8eccSSepherosa Ziehau static void bnx_stop_block(struct bnx_softc *, bus_size_t, uint32_t); 270695a8586SSepherosa Ziehau static void bnx_enable_msi(struct bnx_softc *, boolean_t); 2716c8d8eccSSepherosa Ziehau static void bnx_setmulti(struct bnx_softc *); 2726c8d8eccSSepherosa Ziehau static void bnx_setpromisc(struct bnx_softc *); 2736c8d8eccSSepherosa Ziehau static void bnx_stats_update_regs(struct bnx_softc *); 2746c8d8eccSSepherosa Ziehau static uint32_t bnx_dma_swap_options(struct bnx_softc *); 2756c8d8eccSSepherosa Ziehau 2766c8d8eccSSepherosa Ziehau static uint32_t bnx_readmem_ind(struct bnx_softc *, uint32_t); 2776c8d8eccSSepherosa Ziehau static void bnx_writemem_ind(struct bnx_softc *, uint32_t, uint32_t); 2786c8d8eccSSepherosa Ziehau #ifdef notdef 2796c8d8eccSSepherosa Ziehau static uint32_t bnx_readreg_ind(struct bnx_softc *, uint32_t); 2806c8d8eccSSepherosa Ziehau #endif 2816c8d8eccSSepherosa Ziehau static void bnx_writemem_direct(struct bnx_softc *, uint32_t, uint32_t); 2826c8d8eccSSepherosa Ziehau static void bnx_writembx(struct bnx_softc *, int, int); 2836c8d8eccSSepherosa Ziehau static int bnx_read_nvram(struct bnx_softc *, caddr_t, int, int); 2846c8d8eccSSepherosa Ziehau static uint8_t bnx_eeprom_getbyte(struct bnx_softc *, uint32_t, uint8_t *); 2856c8d8eccSSepherosa Ziehau static int bnx_read_eeprom(struct bnx_softc *, caddr_t, uint32_t, size_t); 2866c8d8eccSSepherosa Ziehau 2876c8d8eccSSepherosa Ziehau static void bnx_tbi_link_upd(struct bnx_softc *, uint32_t); 2886c8d8eccSSepherosa Ziehau static void bnx_copper_link_upd(struct bnx_softc *, uint32_t); 2896c8d8eccSSepherosa Ziehau static void bnx_autopoll_link_upd(struct bnx_softc *, uint32_t); 2906c8d8eccSSepherosa Ziehau static void bnx_link_poll(struct bnx_softc *); 2916c8d8eccSSepherosa Ziehau 2926c8d8eccSSepherosa Ziehau static int bnx_get_eaddr_mem(struct bnx_softc *, uint8_t[]); 2936c8d8eccSSepherosa Ziehau static int bnx_get_eaddr_nvram(struct bnx_softc *, uint8_t[]); 2946c8d8eccSSepherosa Ziehau static int bnx_get_eaddr_eeprom(struct bnx_softc *, uint8_t[]); 2956c8d8eccSSepherosa Ziehau static int bnx_get_eaddr(struct bnx_softc *, uint8_t[]); 2966c8d8eccSSepherosa Ziehau 2976c8d8eccSSepherosa Ziehau static void bnx_coal_change(struct bnx_softc *); 298aad4de2bSSepherosa Ziehau static int bnx_sysctl_force_defrag(SYSCTL_HANDLER_ARGS); 299472c99c8SSepherosa Ziehau static int bnx_sysctl_tx_wreg(SYSCTL_HANDLER_ARGS); 3006c8d8eccSSepherosa Ziehau static int bnx_sysctl_rx_coal_ticks(SYSCTL_HANDLER_ARGS); 3016c8d8eccSSepherosa Ziehau static int bnx_sysctl_tx_coal_ticks(SYSCTL_HANDLER_ARGS); 3026c8d8eccSSepherosa Ziehau static int bnx_sysctl_rx_coal_bds(SYSCTL_HANDLER_ARGS); 303a86cc105SSepherosa Ziehau static int bnx_sysctl_rx_coal_bds_poll(SYSCTL_HANDLER_ARGS); 3046c8d8eccSSepherosa Ziehau static int bnx_sysctl_tx_coal_bds(SYSCTL_HANDLER_ARGS); 30527357d84SSepherosa Ziehau static int bnx_sysctl_tx_coal_bds_poll(SYSCTL_HANDLER_ARGS); 3066c8d8eccSSepherosa Ziehau static int bnx_sysctl_rx_coal_bds_int(SYSCTL_HANDLER_ARGS); 3076c8d8eccSSepherosa Ziehau static int bnx_sysctl_tx_coal_bds_int(SYSCTL_HANDLER_ARGS); 3086c8d8eccSSepherosa Ziehau static int bnx_sysctl_coal_chg(SYSCTL_HANDLER_ARGS, uint32_t *, 3096c8d8eccSSepherosa Ziehau int, int, uint32_t); 310841cdf08SSepherosa Ziehau static int bnx_sysctl_std_refill(SYSCTL_HANDLER_ARGS); 3116c8d8eccSSepherosa Ziehau 3124aa71e73SSepherosa Ziehau static void bnx_sig_post_reset(struct bnx_softc *, int); 3134aa71e73SSepherosa Ziehau static void bnx_sig_pre_reset(struct bnx_softc *, int); 3149f5082d5SSepherosa Ziehau static void bnx_ape_lock_init(struct bnx_softc *); 3159f5082d5SSepherosa Ziehau static void bnx_ape_read_fw_ver(struct bnx_softc *); 3169f5082d5SSepherosa Ziehau static int bnx_ape_lock(struct bnx_softc *, int); 3179f5082d5SSepherosa Ziehau static void bnx_ape_unlock(struct bnx_softc *, int); 3189f5082d5SSepherosa Ziehau static void bnx_ape_send_event(struct bnx_softc *, uint32_t); 3199f5082d5SSepherosa Ziehau static void bnx_ape_driver_state_change(struct bnx_softc *, int); 3204aa71e73SSepherosa Ziehau 3216c8d8eccSSepherosa Ziehau static int bnx_msi_enable = 1; 322695a8586SSepherosa Ziehau static int bnx_msix_enable = 1; 323695a8586SSepherosa Ziehau 324695a8586SSepherosa Ziehau static int bnx_rx_rings = 0; /* auto */ 325695a8586SSepherosa Ziehau static int bnx_tx_rings = 0; /* auto */ 326695a8586SSepherosa Ziehau 3276c8d8eccSSepherosa Ziehau TUNABLE_INT("hw.bnx.msi.enable", &bnx_msi_enable); 328695a8586SSepherosa Ziehau TUNABLE_INT("hw.bnx.msix.enable", &bnx_msix_enable); 329695a8586SSepherosa Ziehau TUNABLE_INT("hw.bnx.rx_rings", &bnx_rx_rings); 330695a8586SSepherosa Ziehau TUNABLE_INT("hw.bnx.tx_rings", &bnx_tx_rings); 3316c8d8eccSSepherosa Ziehau 3326c8d8eccSSepherosa Ziehau static device_method_t bnx_methods[] = { 3336c8d8eccSSepherosa Ziehau /* Device interface */ 3346c8d8eccSSepherosa Ziehau DEVMETHOD(device_probe, bnx_probe), 3356c8d8eccSSepherosa Ziehau DEVMETHOD(device_attach, bnx_attach), 3366c8d8eccSSepherosa Ziehau DEVMETHOD(device_detach, bnx_detach), 3376c8d8eccSSepherosa Ziehau DEVMETHOD(device_shutdown, bnx_shutdown), 3386c8d8eccSSepherosa Ziehau DEVMETHOD(device_suspend, bnx_suspend), 3396c8d8eccSSepherosa Ziehau DEVMETHOD(device_resume, bnx_resume), 3406c8d8eccSSepherosa Ziehau 3416c8d8eccSSepherosa Ziehau /* bus interface */ 3426c8d8eccSSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 3436c8d8eccSSepherosa Ziehau DEVMETHOD(bus_driver_added, bus_generic_driver_added), 3446c8d8eccSSepherosa Ziehau 3456c8d8eccSSepherosa Ziehau /* MII interface */ 3466c8d8eccSSepherosa Ziehau DEVMETHOD(miibus_readreg, bnx_miibus_readreg), 3476c8d8eccSSepherosa Ziehau DEVMETHOD(miibus_writereg, bnx_miibus_writereg), 3486c8d8eccSSepherosa Ziehau DEVMETHOD(miibus_statchg, bnx_miibus_statchg), 3496c8d8eccSSepherosa Ziehau 350d3c9c58eSSascha Wildner DEVMETHOD_END 3516c8d8eccSSepherosa Ziehau }; 3526c8d8eccSSepherosa Ziehau 3536c8d8eccSSepherosa Ziehau static DEFINE_CLASS_0(bnx, bnx_driver, bnx_methods, sizeof(struct bnx_softc)); 3546c8d8eccSSepherosa Ziehau static devclass_t bnx_devclass; 3556c8d8eccSSepherosa Ziehau 3566c8d8eccSSepherosa Ziehau DECLARE_DUMMY_MODULE(if_bnx); 3571996f1e5SSepherosa Ziehau MODULE_DEPEND(if_bnx, miibus, 1, 1, 1); 3586c8d8eccSSepherosa Ziehau DRIVER_MODULE(if_bnx, pci, bnx_driver, bnx_devclass, NULL, NULL); 3596c8d8eccSSepherosa Ziehau DRIVER_MODULE(miibus, bnx, miibus_driver, miibus_devclass, NULL, NULL); 3606c8d8eccSSepherosa Ziehau 3616c8d8eccSSepherosa Ziehau static uint32_t 3626c8d8eccSSepherosa Ziehau bnx_readmem_ind(struct bnx_softc *sc, uint32_t off) 3636c8d8eccSSepherosa Ziehau { 3646c8d8eccSSepherosa Ziehau device_t dev = sc->bnx_dev; 3656c8d8eccSSepherosa Ziehau uint32_t val; 3666c8d8eccSSepherosa Ziehau 3676c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4); 3686c8d8eccSSepherosa Ziehau val = pci_read_config(dev, BGE_PCI_MEMWIN_DATA, 4); 3696c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4); 3706c8d8eccSSepherosa Ziehau return (val); 3716c8d8eccSSepherosa Ziehau } 3726c8d8eccSSepherosa Ziehau 3736c8d8eccSSepherosa Ziehau static void 3746c8d8eccSSepherosa Ziehau bnx_writemem_ind(struct bnx_softc *sc, uint32_t off, uint32_t val) 3756c8d8eccSSepherosa Ziehau { 3766c8d8eccSSepherosa Ziehau device_t dev = sc->bnx_dev; 3776c8d8eccSSepherosa Ziehau 3786c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4); 3796c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_DATA, val, 4); 3806c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4); 3816c8d8eccSSepherosa Ziehau } 3826c8d8eccSSepherosa Ziehau 3836c8d8eccSSepherosa Ziehau static void 3846c8d8eccSSepherosa Ziehau bnx_writemem_direct(struct bnx_softc *sc, uint32_t off, uint32_t val) 3856c8d8eccSSepherosa Ziehau { 3866c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, off, val); 3876c8d8eccSSepherosa Ziehau } 3886c8d8eccSSepherosa Ziehau 3896c8d8eccSSepherosa Ziehau static void 3906c8d8eccSSepherosa Ziehau bnx_writembx(struct bnx_softc *sc, int off, int val) 3916c8d8eccSSepherosa Ziehau { 3926c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, off, val); 3936c8d8eccSSepherosa Ziehau } 3946c8d8eccSSepherosa Ziehau 3956c8d8eccSSepherosa Ziehau /* 3966c8d8eccSSepherosa Ziehau * Read a sequence of bytes from NVRAM. 3976c8d8eccSSepherosa Ziehau */ 3986c8d8eccSSepherosa Ziehau static int 3996c8d8eccSSepherosa Ziehau bnx_read_nvram(struct bnx_softc *sc, caddr_t dest, int off, int cnt) 4006c8d8eccSSepherosa Ziehau { 4016c8d8eccSSepherosa Ziehau return (1); 4026c8d8eccSSepherosa Ziehau } 4036c8d8eccSSepherosa Ziehau 4046c8d8eccSSepherosa Ziehau /* 4056c8d8eccSSepherosa Ziehau * Read a byte of data stored in the EEPROM at address 'addr.' The 4066c8d8eccSSepherosa Ziehau * BCM570x supports both the traditional bitbang interface and an 4076c8d8eccSSepherosa Ziehau * auto access interface for reading the EEPROM. We use the auto 4086c8d8eccSSepherosa Ziehau * access method. 4096c8d8eccSSepherosa Ziehau */ 4106c8d8eccSSepherosa Ziehau static uint8_t 4116c8d8eccSSepherosa Ziehau bnx_eeprom_getbyte(struct bnx_softc *sc, uint32_t addr, uint8_t *dest) 4126c8d8eccSSepherosa Ziehau { 4136c8d8eccSSepherosa Ziehau int i; 4146c8d8eccSSepherosa Ziehau uint32_t byte = 0; 4156c8d8eccSSepherosa Ziehau 4166c8d8eccSSepherosa Ziehau /* 4176c8d8eccSSepherosa Ziehau * Enable use of auto EEPROM access so we can avoid 4186c8d8eccSSepherosa Ziehau * having to use the bitbang method. 4196c8d8eccSSepherosa Ziehau */ 4206c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_AUTO_EEPROM); 4216c8d8eccSSepherosa Ziehau 4226c8d8eccSSepherosa Ziehau /* Reset the EEPROM, load the clock period. */ 4236c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_EE_ADDR, 4246c8d8eccSSepherosa Ziehau BGE_EEADDR_RESET|BGE_EEHALFCLK(BGE_HALFCLK_384SCL)); 4256c8d8eccSSepherosa Ziehau DELAY(20); 4266c8d8eccSSepherosa Ziehau 4276c8d8eccSSepherosa Ziehau /* Issue the read EEPROM command. */ 4286c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_EE_ADDR, BGE_EE_READCMD | addr); 4296c8d8eccSSepherosa Ziehau 4306c8d8eccSSepherosa Ziehau /* Wait for completion */ 4316c8d8eccSSepherosa Ziehau for(i = 0; i < BNX_TIMEOUT * 10; i++) { 4326c8d8eccSSepherosa Ziehau DELAY(10); 4336c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_EE_ADDR) & BGE_EEADDR_DONE) 4346c8d8eccSSepherosa Ziehau break; 4356c8d8eccSSepherosa Ziehau } 4366c8d8eccSSepherosa Ziehau 4376c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 4386c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "eeprom read timed out\n"); 4396c8d8eccSSepherosa Ziehau return(1); 4406c8d8eccSSepherosa Ziehau } 4416c8d8eccSSepherosa Ziehau 4426c8d8eccSSepherosa Ziehau /* Get result. */ 4436c8d8eccSSepherosa Ziehau byte = CSR_READ_4(sc, BGE_EE_DATA); 4446c8d8eccSSepherosa Ziehau 4456c8d8eccSSepherosa Ziehau *dest = (byte >> ((addr % 4) * 8)) & 0xFF; 4466c8d8eccSSepherosa Ziehau 4476c8d8eccSSepherosa Ziehau return(0); 4486c8d8eccSSepherosa Ziehau } 4496c8d8eccSSepherosa Ziehau 4506c8d8eccSSepherosa Ziehau /* 4516c8d8eccSSepherosa Ziehau * Read a sequence of bytes from the EEPROM. 4526c8d8eccSSepherosa Ziehau */ 4536c8d8eccSSepherosa Ziehau static int 4546c8d8eccSSepherosa Ziehau bnx_read_eeprom(struct bnx_softc *sc, caddr_t dest, uint32_t off, size_t len) 4556c8d8eccSSepherosa Ziehau { 4566c8d8eccSSepherosa Ziehau size_t i; 4576c8d8eccSSepherosa Ziehau int err; 4586c8d8eccSSepherosa Ziehau uint8_t byte; 4596c8d8eccSSepherosa Ziehau 4606c8d8eccSSepherosa Ziehau for (byte = 0, err = 0, i = 0; i < len; i++) { 4616c8d8eccSSepherosa Ziehau err = bnx_eeprom_getbyte(sc, off + i, &byte); 4626c8d8eccSSepherosa Ziehau if (err) 4636c8d8eccSSepherosa Ziehau break; 4646c8d8eccSSepherosa Ziehau *(dest + i) = byte; 4656c8d8eccSSepherosa Ziehau } 4666c8d8eccSSepherosa Ziehau 4676c8d8eccSSepherosa Ziehau return(err ? 1 : 0); 4686c8d8eccSSepherosa Ziehau } 4696c8d8eccSSepherosa Ziehau 4706c8d8eccSSepherosa Ziehau static int 4716c8d8eccSSepherosa Ziehau bnx_miibus_readreg(device_t dev, int phy, int reg) 4726c8d8eccSSepherosa Ziehau { 4736c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 4746c8d8eccSSepherosa Ziehau uint32_t val; 4756c8d8eccSSepherosa Ziehau int i; 4766c8d8eccSSepherosa Ziehau 4776c8d8eccSSepherosa Ziehau KASSERT(phy == sc->bnx_phyno, 4786c8d8eccSSepherosa Ziehau ("invalid phyno %d, should be %d", phy, sc->bnx_phyno)); 4796c8d8eccSSepherosa Ziehau 4809f5082d5SSepherosa Ziehau if (bnx_ape_lock(sc, sc->bnx_phy_ape_lock) != 0) 4819f5082d5SSepherosa Ziehau return 0; 4829f5082d5SSepherosa Ziehau 4836c8d8eccSSepherosa Ziehau /* Clear the autopoll bit if set, otherwise may trigger PCI errors. */ 4846c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 4856c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, 4866c8d8eccSSepherosa Ziehau sc->bnx_mi_mode & ~BGE_MIMODE_AUTOPOLL); 4876c8d8eccSSepherosa Ziehau DELAY(80); 4886c8d8eccSSepherosa Ziehau } 4896c8d8eccSSepherosa Ziehau 4906c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_READ | BGE_MICOMM_BUSY | 4916c8d8eccSSepherosa Ziehau BGE_MIPHY(phy) | BGE_MIREG(reg)); 4926c8d8eccSSepherosa Ziehau 4936c8d8eccSSepherosa Ziehau /* Poll for the PHY register access to complete. */ 4946c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 4956c8d8eccSSepherosa Ziehau DELAY(10); 4966c8d8eccSSepherosa Ziehau val = CSR_READ_4(sc, BGE_MI_COMM); 4976c8d8eccSSepherosa Ziehau if ((val & BGE_MICOMM_BUSY) == 0) { 4986c8d8eccSSepherosa Ziehau DELAY(5); 4996c8d8eccSSepherosa Ziehau val = CSR_READ_4(sc, BGE_MI_COMM); 5006c8d8eccSSepherosa Ziehau break; 5016c8d8eccSSepherosa Ziehau } 5026c8d8eccSSepherosa Ziehau } 5036c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 5046c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "PHY read timed out " 5056c8d8eccSSepherosa Ziehau "(phy %d, reg %d, val 0x%08x)\n", phy, reg, val); 5066c8d8eccSSepherosa Ziehau val = 0; 5076c8d8eccSSepherosa Ziehau } 5086c8d8eccSSepherosa Ziehau 5096c8d8eccSSepherosa Ziehau /* Restore the autopoll bit if necessary. */ 5106c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 5116c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, sc->bnx_mi_mode); 5126c8d8eccSSepherosa Ziehau DELAY(80); 5136c8d8eccSSepherosa Ziehau } 5146c8d8eccSSepherosa Ziehau 5159f5082d5SSepherosa Ziehau bnx_ape_unlock(sc, sc->bnx_phy_ape_lock); 5169f5082d5SSepherosa Ziehau 5176c8d8eccSSepherosa Ziehau if (val & BGE_MICOMM_READFAIL) 5186c8d8eccSSepherosa Ziehau return 0; 5196c8d8eccSSepherosa Ziehau 5206c8d8eccSSepherosa Ziehau return (val & 0xFFFF); 5216c8d8eccSSepherosa Ziehau } 5226c8d8eccSSepherosa Ziehau 5236c8d8eccSSepherosa Ziehau static int 5246c8d8eccSSepherosa Ziehau bnx_miibus_writereg(device_t dev, int phy, int reg, int val) 5256c8d8eccSSepherosa Ziehau { 5266c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 5276c8d8eccSSepherosa Ziehau int i; 5286c8d8eccSSepherosa Ziehau 5296c8d8eccSSepherosa Ziehau KASSERT(phy == sc->bnx_phyno, 5306c8d8eccSSepherosa Ziehau ("invalid phyno %d, should be %d", phy, sc->bnx_phyno)); 5316c8d8eccSSepherosa Ziehau 5329f5082d5SSepherosa Ziehau if (bnx_ape_lock(sc, sc->bnx_phy_ape_lock) != 0) 5339f5082d5SSepherosa Ziehau return 0; 5349f5082d5SSepherosa Ziehau 5356c8d8eccSSepherosa Ziehau /* Clear the autopoll bit if set, otherwise may trigger PCI errors. */ 5366c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 5376c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, 5386c8d8eccSSepherosa Ziehau sc->bnx_mi_mode & ~BGE_MIMODE_AUTOPOLL); 5396c8d8eccSSepherosa Ziehau DELAY(80); 5406c8d8eccSSepherosa Ziehau } 5416c8d8eccSSepherosa Ziehau 5426c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_WRITE | BGE_MICOMM_BUSY | 5436c8d8eccSSepherosa Ziehau BGE_MIPHY(phy) | BGE_MIREG(reg) | val); 5446c8d8eccSSepherosa Ziehau 5456c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 5466c8d8eccSSepherosa Ziehau DELAY(10); 5476c8d8eccSSepherosa Ziehau if (!(CSR_READ_4(sc, BGE_MI_COMM) & BGE_MICOMM_BUSY)) { 5486c8d8eccSSepherosa Ziehau DELAY(5); 5496c8d8eccSSepherosa Ziehau CSR_READ_4(sc, BGE_MI_COMM); /* dummy read */ 5506c8d8eccSSepherosa Ziehau break; 5516c8d8eccSSepherosa Ziehau } 5526c8d8eccSSepherosa Ziehau } 5536c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 5546c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "PHY write timed out " 5556c8d8eccSSepherosa Ziehau "(phy %d, reg %d, val %d)\n", phy, reg, val); 5566c8d8eccSSepherosa Ziehau } 5576c8d8eccSSepherosa Ziehau 5586c8d8eccSSepherosa Ziehau /* Restore the autopoll bit if necessary. */ 5596c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 5606c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, sc->bnx_mi_mode); 5616c8d8eccSSepherosa Ziehau DELAY(80); 5626c8d8eccSSepherosa Ziehau } 5636c8d8eccSSepherosa Ziehau 5649f5082d5SSepherosa Ziehau bnx_ape_unlock(sc, sc->bnx_phy_ape_lock); 5659f5082d5SSepherosa Ziehau 5666c8d8eccSSepherosa Ziehau return 0; 5676c8d8eccSSepherosa Ziehau } 5686c8d8eccSSepherosa Ziehau 5696c8d8eccSSepherosa Ziehau static void 5706c8d8eccSSepherosa Ziehau bnx_miibus_statchg(device_t dev) 5716c8d8eccSSepherosa Ziehau { 5726c8d8eccSSepherosa Ziehau struct bnx_softc *sc; 5736c8d8eccSSepherosa Ziehau struct mii_data *mii; 5744aa71e73SSepherosa Ziehau uint32_t mac_mode; 5756c8d8eccSSepherosa Ziehau 5766c8d8eccSSepherosa Ziehau sc = device_get_softc(dev); 5774aa71e73SSepherosa Ziehau if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING) == 0) 5784aa71e73SSepherosa Ziehau return; 5794aa71e73SSepherosa Ziehau 5806c8d8eccSSepherosa Ziehau mii = device_get_softc(sc->bnx_miibus); 5816c8d8eccSSepherosa Ziehau 5826c8d8eccSSepherosa Ziehau if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 5836c8d8eccSSepherosa Ziehau (IFM_ACTIVE | IFM_AVALID)) { 5846c8d8eccSSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) { 5856c8d8eccSSepherosa Ziehau case IFM_10_T: 5866c8d8eccSSepherosa Ziehau case IFM_100_TX: 5876c8d8eccSSepherosa Ziehau sc->bnx_link = 1; 5886c8d8eccSSepherosa Ziehau break; 5896c8d8eccSSepherosa Ziehau case IFM_1000_T: 5906c8d8eccSSepherosa Ziehau case IFM_1000_SX: 5916c8d8eccSSepherosa Ziehau case IFM_2500_SX: 5926c8d8eccSSepherosa Ziehau sc->bnx_link = 1; 5936c8d8eccSSepherosa Ziehau break; 5946c8d8eccSSepherosa Ziehau default: 5956c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 5966c8d8eccSSepherosa Ziehau break; 5976c8d8eccSSepherosa Ziehau } 5986c8d8eccSSepherosa Ziehau } else { 5996c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 6006c8d8eccSSepherosa Ziehau } 6016c8d8eccSSepherosa Ziehau if (sc->bnx_link == 0) 6026c8d8eccSSepherosa Ziehau return; 6036c8d8eccSSepherosa Ziehau 6044aa71e73SSepherosa Ziehau /* 6054aa71e73SSepherosa Ziehau * APE firmware touches these registers to keep the MAC 6064aa71e73SSepherosa Ziehau * connected to the outside world. Try to keep the 6074aa71e73SSepherosa Ziehau * accesses atomic. 6084aa71e73SSepherosa Ziehau */ 6096c8d8eccSSepherosa Ziehau 6104aa71e73SSepherosa Ziehau mac_mode = CSR_READ_4(sc, BGE_MAC_MODE) & 6114aa71e73SSepherosa Ziehau ~(BGE_MACMODE_PORTMODE | BGE_MACMODE_HALF_DUPLEX); 6124aa71e73SSepherosa Ziehau 6134aa71e73SSepherosa Ziehau if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 6144aa71e73SSepherosa Ziehau IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) 6154aa71e73SSepherosa Ziehau mac_mode |= BGE_PORTMODE_GMII; 6164aa71e73SSepherosa Ziehau else 6174aa71e73SSepherosa Ziehau mac_mode |= BGE_PORTMODE_MII; 6184aa71e73SSepherosa Ziehau 6194aa71e73SSepherosa Ziehau if ((mii->mii_media_active & IFM_GMASK) != IFM_FDX) 6204aa71e73SSepherosa Ziehau mac_mode |= BGE_MACMODE_HALF_DUPLEX; 6214aa71e73SSepherosa Ziehau 6224aa71e73SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_MODE, mac_mode); 6234aa71e73SSepherosa Ziehau DELAY(40); 6246c8d8eccSSepherosa Ziehau } 6256c8d8eccSSepherosa Ziehau 6266c8d8eccSSepherosa Ziehau /* 6276c8d8eccSSepherosa Ziehau * Memory management for jumbo frames. 6286c8d8eccSSepherosa Ziehau */ 6296c8d8eccSSepherosa Ziehau static int 6306c8d8eccSSepherosa Ziehau bnx_alloc_jumbo_mem(struct bnx_softc *sc) 6316c8d8eccSSepherosa Ziehau { 6326c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 6336c8d8eccSSepherosa Ziehau struct bnx_jslot *entry; 6346c8d8eccSSepherosa Ziehau uint8_t *ptr; 6356c8d8eccSSepherosa Ziehau bus_addr_t paddr; 6366c8d8eccSSepherosa Ziehau int i, error; 6376c8d8eccSSepherosa Ziehau 6386c8d8eccSSepherosa Ziehau /* 6396c8d8eccSSepherosa Ziehau * Create tag for jumbo mbufs. 6406c8d8eccSSepherosa Ziehau * This is really a bit of a kludge. We allocate a special 6416c8d8eccSSepherosa Ziehau * jumbo buffer pool which (thanks to the way our DMA 6426c8d8eccSSepherosa Ziehau * memory allocation works) will consist of contiguous 6436c8d8eccSSepherosa Ziehau * pages. This means that even though a jumbo buffer might 6446c8d8eccSSepherosa Ziehau * be larger than a page size, we don't really need to 6456c8d8eccSSepherosa Ziehau * map it into more than one DMA segment. However, the 6466c8d8eccSSepherosa Ziehau * default mbuf tag will result in multi-segment mappings, 6476c8d8eccSSepherosa Ziehau * so we have to create a special jumbo mbuf tag that 6486c8d8eccSSepherosa Ziehau * lets us get away with mapping the jumbo buffers as 6496c8d8eccSSepherosa Ziehau * a single segment. I think eventually the driver should 6506c8d8eccSSepherosa Ziehau * be changed so that it uses ordinary mbufs and cluster 6516c8d8eccSSepherosa Ziehau * buffers, i.e. jumbo frames can span multiple DMA 6526c8d8eccSSepherosa Ziehau * descriptors. But that's a project for another day. 6536c8d8eccSSepherosa Ziehau */ 6546c8d8eccSSepherosa Ziehau 6556c8d8eccSSepherosa Ziehau /* 6566c8d8eccSSepherosa Ziehau * Create DMA stuffs for jumbo RX ring. 6576c8d8eccSSepherosa Ziehau */ 6586c8d8eccSSepherosa Ziehau error = bnx_dma_block_alloc(sc, BGE_JUMBO_RX_RING_SZ, 6596c8d8eccSSepherosa Ziehau &sc->bnx_cdata.bnx_rx_jumbo_ring_tag, 6606c8d8eccSSepherosa Ziehau &sc->bnx_cdata.bnx_rx_jumbo_ring_map, 6616c8d8eccSSepherosa Ziehau (void *)&sc->bnx_ldata.bnx_rx_jumbo_ring, 6626c8d8eccSSepherosa Ziehau &sc->bnx_ldata.bnx_rx_jumbo_ring_paddr); 6636c8d8eccSSepherosa Ziehau if (error) { 6646c8d8eccSSepherosa Ziehau if_printf(ifp, "could not create jumbo RX ring\n"); 6656c8d8eccSSepherosa Ziehau return error; 6666c8d8eccSSepherosa Ziehau } 6676c8d8eccSSepherosa Ziehau 6686c8d8eccSSepherosa Ziehau /* 6696c8d8eccSSepherosa Ziehau * Create DMA stuffs for jumbo buffer block. 6706c8d8eccSSepherosa Ziehau */ 6716c8d8eccSSepherosa Ziehau error = bnx_dma_block_alloc(sc, BNX_JMEM, 6726c8d8eccSSepherosa Ziehau &sc->bnx_cdata.bnx_jumbo_tag, 6736c8d8eccSSepherosa Ziehau &sc->bnx_cdata.bnx_jumbo_map, 6746c8d8eccSSepherosa Ziehau (void **)&sc->bnx_ldata.bnx_jumbo_buf, 6756c8d8eccSSepherosa Ziehau &paddr); 6766c8d8eccSSepherosa Ziehau if (error) { 6776c8d8eccSSepherosa Ziehau if_printf(ifp, "could not create jumbo buffer\n"); 6786c8d8eccSSepherosa Ziehau return error; 6796c8d8eccSSepherosa Ziehau } 6806c8d8eccSSepherosa Ziehau 6816c8d8eccSSepherosa Ziehau SLIST_INIT(&sc->bnx_jfree_listhead); 6826c8d8eccSSepherosa Ziehau 6836c8d8eccSSepherosa Ziehau /* 6846c8d8eccSSepherosa Ziehau * Now divide it up into 9K pieces and save the addresses 6856c8d8eccSSepherosa Ziehau * in an array. Note that we play an evil trick here by using 6866c8d8eccSSepherosa Ziehau * the first few bytes in the buffer to hold the the address 6876c8d8eccSSepherosa Ziehau * of the softc structure for this interface. This is because 6886c8d8eccSSepherosa Ziehau * bnx_jfree() needs it, but it is called by the mbuf management 6896c8d8eccSSepherosa Ziehau * code which will not pass it to us explicitly. 6906c8d8eccSSepherosa Ziehau */ 6916c8d8eccSSepherosa Ziehau for (i = 0, ptr = sc->bnx_ldata.bnx_jumbo_buf; i < BNX_JSLOTS; i++) { 6926c8d8eccSSepherosa Ziehau entry = &sc->bnx_cdata.bnx_jslots[i]; 6936c8d8eccSSepherosa Ziehau entry->bnx_sc = sc; 6946c8d8eccSSepherosa Ziehau entry->bnx_buf = ptr; 6956c8d8eccSSepherosa Ziehau entry->bnx_paddr = paddr; 6966c8d8eccSSepherosa Ziehau entry->bnx_inuse = 0; 6976c8d8eccSSepherosa Ziehau entry->bnx_slot = i; 6986c8d8eccSSepherosa Ziehau SLIST_INSERT_HEAD(&sc->bnx_jfree_listhead, entry, jslot_link); 6996c8d8eccSSepherosa Ziehau 7006c8d8eccSSepherosa Ziehau ptr += BNX_JLEN; 7016c8d8eccSSepherosa Ziehau paddr += BNX_JLEN; 7026c8d8eccSSepherosa Ziehau } 7036c8d8eccSSepherosa Ziehau return 0; 7046c8d8eccSSepherosa Ziehau } 7056c8d8eccSSepherosa Ziehau 7066c8d8eccSSepherosa Ziehau static void 7076c8d8eccSSepherosa Ziehau bnx_free_jumbo_mem(struct bnx_softc *sc) 7086c8d8eccSSepherosa Ziehau { 7096c8d8eccSSepherosa Ziehau /* Destroy jumbo RX ring. */ 7106c8d8eccSSepherosa Ziehau bnx_dma_block_free(sc->bnx_cdata.bnx_rx_jumbo_ring_tag, 7116c8d8eccSSepherosa Ziehau sc->bnx_cdata.bnx_rx_jumbo_ring_map, 7126c8d8eccSSepherosa Ziehau sc->bnx_ldata.bnx_rx_jumbo_ring); 7136c8d8eccSSepherosa Ziehau 7146c8d8eccSSepherosa Ziehau /* Destroy jumbo buffer block. */ 7156c8d8eccSSepherosa Ziehau bnx_dma_block_free(sc->bnx_cdata.bnx_jumbo_tag, 7166c8d8eccSSepherosa Ziehau sc->bnx_cdata.bnx_jumbo_map, 7176c8d8eccSSepherosa Ziehau sc->bnx_ldata.bnx_jumbo_buf); 7186c8d8eccSSepherosa Ziehau } 7196c8d8eccSSepherosa Ziehau 7206c8d8eccSSepherosa Ziehau /* 7216c8d8eccSSepherosa Ziehau * Allocate a jumbo buffer. 7226c8d8eccSSepherosa Ziehau */ 7236c8d8eccSSepherosa Ziehau static struct bnx_jslot * 7246c8d8eccSSepherosa Ziehau bnx_jalloc(struct bnx_softc *sc) 7256c8d8eccSSepherosa Ziehau { 7266c8d8eccSSepherosa Ziehau struct bnx_jslot *entry; 7276c8d8eccSSepherosa Ziehau 7286c8d8eccSSepherosa Ziehau lwkt_serialize_enter(&sc->bnx_jslot_serializer); 7296c8d8eccSSepherosa Ziehau entry = SLIST_FIRST(&sc->bnx_jfree_listhead); 7306c8d8eccSSepherosa Ziehau if (entry) { 7316c8d8eccSSepherosa Ziehau SLIST_REMOVE_HEAD(&sc->bnx_jfree_listhead, jslot_link); 7326c8d8eccSSepherosa Ziehau entry->bnx_inuse = 1; 7336c8d8eccSSepherosa Ziehau } else { 7346c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "no free jumbo buffers\n"); 7356c8d8eccSSepherosa Ziehau } 7366c8d8eccSSepherosa Ziehau lwkt_serialize_exit(&sc->bnx_jslot_serializer); 7376c8d8eccSSepherosa Ziehau return(entry); 7386c8d8eccSSepherosa Ziehau } 7396c8d8eccSSepherosa Ziehau 7406c8d8eccSSepherosa Ziehau /* 7416c8d8eccSSepherosa Ziehau * Adjust usage count on a jumbo buffer. 7426c8d8eccSSepherosa Ziehau */ 7436c8d8eccSSepherosa Ziehau static void 7446c8d8eccSSepherosa Ziehau bnx_jref(void *arg) 7456c8d8eccSSepherosa Ziehau { 7466c8d8eccSSepherosa Ziehau struct bnx_jslot *entry = (struct bnx_jslot *)arg; 7476c8d8eccSSepherosa Ziehau struct bnx_softc *sc = entry->bnx_sc; 7486c8d8eccSSepherosa Ziehau 7496c8d8eccSSepherosa Ziehau if (sc == NULL) 7506c8d8eccSSepherosa Ziehau panic("bnx_jref: can't find softc pointer!"); 7516c8d8eccSSepherosa Ziehau 7526c8d8eccSSepherosa Ziehau if (&sc->bnx_cdata.bnx_jslots[entry->bnx_slot] != entry) { 7536c8d8eccSSepherosa Ziehau panic("bnx_jref: asked to reference buffer " 7546c8d8eccSSepherosa Ziehau "that we don't manage!"); 7556c8d8eccSSepherosa Ziehau } else if (entry->bnx_inuse == 0) { 7566c8d8eccSSepherosa Ziehau panic("bnx_jref: buffer already free!"); 7576c8d8eccSSepherosa Ziehau } else { 7586c8d8eccSSepherosa Ziehau atomic_add_int(&entry->bnx_inuse, 1); 7596c8d8eccSSepherosa Ziehau } 7606c8d8eccSSepherosa Ziehau } 7616c8d8eccSSepherosa Ziehau 7626c8d8eccSSepherosa Ziehau /* 7636c8d8eccSSepherosa Ziehau * Release a jumbo buffer. 7646c8d8eccSSepherosa Ziehau */ 7656c8d8eccSSepherosa Ziehau static void 7666c8d8eccSSepherosa Ziehau bnx_jfree(void *arg) 7676c8d8eccSSepherosa Ziehau { 7686c8d8eccSSepherosa Ziehau struct bnx_jslot *entry = (struct bnx_jslot *)arg; 7696c8d8eccSSepherosa Ziehau struct bnx_softc *sc = entry->bnx_sc; 7706c8d8eccSSepherosa Ziehau 7716c8d8eccSSepherosa Ziehau if (sc == NULL) 7726c8d8eccSSepherosa Ziehau panic("bnx_jfree: can't find softc pointer!"); 7736c8d8eccSSepherosa Ziehau 7746c8d8eccSSepherosa Ziehau if (&sc->bnx_cdata.bnx_jslots[entry->bnx_slot] != entry) { 7756c8d8eccSSepherosa Ziehau panic("bnx_jfree: asked to free buffer that we don't manage!"); 7766c8d8eccSSepherosa Ziehau } else if (entry->bnx_inuse == 0) { 7776c8d8eccSSepherosa Ziehau panic("bnx_jfree: buffer already free!"); 7786c8d8eccSSepherosa Ziehau } else { 7796c8d8eccSSepherosa Ziehau /* 7806c8d8eccSSepherosa Ziehau * Possible MP race to 0, use the serializer. The atomic insn 7816c8d8eccSSepherosa Ziehau * is still needed for races against bnx_jref(). 7826c8d8eccSSepherosa Ziehau */ 7836c8d8eccSSepherosa Ziehau lwkt_serialize_enter(&sc->bnx_jslot_serializer); 7846c8d8eccSSepherosa Ziehau atomic_subtract_int(&entry->bnx_inuse, 1); 7856c8d8eccSSepherosa Ziehau if (entry->bnx_inuse == 0) { 7866c8d8eccSSepherosa Ziehau SLIST_INSERT_HEAD(&sc->bnx_jfree_listhead, 7876c8d8eccSSepherosa Ziehau entry, jslot_link); 7886c8d8eccSSepherosa Ziehau } 7896c8d8eccSSepherosa Ziehau lwkt_serialize_exit(&sc->bnx_jslot_serializer); 7906c8d8eccSSepherosa Ziehau } 7916c8d8eccSSepherosa Ziehau } 7926c8d8eccSSepherosa Ziehau 7936c8d8eccSSepherosa Ziehau 7946c8d8eccSSepherosa Ziehau /* 7956c8d8eccSSepherosa Ziehau * Intialize a standard receive ring descriptor. 7966c8d8eccSSepherosa Ziehau */ 7976c8d8eccSSepherosa Ziehau static int 798beedf5beSSepherosa Ziehau bnx_newbuf_std(struct bnx_rx_ret_ring *ret, int i, int init) 7996c8d8eccSSepherosa Ziehau { 8006c8d8eccSSepherosa Ziehau struct mbuf *m_new = NULL; 8016c8d8eccSSepherosa Ziehau bus_dma_segment_t seg; 8026c8d8eccSSepherosa Ziehau bus_dmamap_t map; 8036c8d8eccSSepherosa Ziehau int error, nsegs; 804beedf5beSSepherosa Ziehau struct bnx_rx_buf *rb; 8056c8d8eccSSepherosa Ziehau 806841cdf08SSepherosa Ziehau rb = &ret->bnx_std->bnx_rx_std_buf[i]; 807841cdf08SSepherosa Ziehau KASSERT(!rb->bnx_rx_refilled, ("RX buf %dth has been refilled", i)); 808841cdf08SSepherosa Ziehau 809b5523eacSSascha Wildner m_new = m_getcl(init ? M_WAITOK : M_NOWAIT, MT_DATA, M_PKTHDR); 810841cdf08SSepherosa Ziehau if (m_new == NULL) { 811841cdf08SSepherosa Ziehau error = ENOBUFS; 812841cdf08SSepherosa Ziehau goto back; 813841cdf08SSepherosa Ziehau } 8146c8d8eccSSepherosa Ziehau m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 8156c8d8eccSSepherosa Ziehau m_adj(m_new, ETHER_ALIGN); 8166c8d8eccSSepherosa Ziehau 817beedf5beSSepherosa Ziehau error = bus_dmamap_load_mbuf_segment(ret->bnx_rx_mtag, 818beedf5beSSepherosa Ziehau ret->bnx_rx_tmpmap, m_new, &seg, 1, &nsegs, BUS_DMA_NOWAIT); 8196c8d8eccSSepherosa Ziehau if (error) { 8206c8d8eccSSepherosa Ziehau m_freem(m_new); 821841cdf08SSepherosa Ziehau goto back; 8226c8d8eccSSepherosa Ziehau } 8236c8d8eccSSepherosa Ziehau 8246c8d8eccSSepherosa Ziehau if (!init) { 825beedf5beSSepherosa Ziehau bus_dmamap_sync(ret->bnx_rx_mtag, rb->bnx_rx_dmamap, 8266c8d8eccSSepherosa Ziehau BUS_DMASYNC_POSTREAD); 827beedf5beSSepherosa Ziehau bus_dmamap_unload(ret->bnx_rx_mtag, rb->bnx_rx_dmamap); 8286c8d8eccSSepherosa Ziehau } 8296c8d8eccSSepherosa Ziehau 830beedf5beSSepherosa Ziehau map = ret->bnx_rx_tmpmap; 831beedf5beSSepherosa Ziehau ret->bnx_rx_tmpmap = rb->bnx_rx_dmamap; 8326c8d8eccSSepherosa Ziehau 833841cdf08SSepherosa Ziehau rb->bnx_rx_dmamap = map; 834beedf5beSSepherosa Ziehau rb->bnx_rx_mbuf = m_new; 835beedf5beSSepherosa Ziehau rb->bnx_rx_paddr = seg.ds_addr; 836695a8586SSepherosa Ziehau rb->bnx_rx_len = m_new->m_len; 837841cdf08SSepherosa Ziehau back: 838841cdf08SSepherosa Ziehau cpu_sfence(); 839841cdf08SSepherosa Ziehau rb->bnx_rx_refilled = 1; 840841cdf08SSepherosa Ziehau return error; 8416c8d8eccSSepherosa Ziehau } 8426c8d8eccSSepherosa Ziehau 8436c8d8eccSSepherosa Ziehau static void 844beedf5beSSepherosa Ziehau bnx_setup_rxdesc_std(struct bnx_rx_std_ring *std, int i) 8456c8d8eccSSepherosa Ziehau { 846841cdf08SSepherosa Ziehau struct bnx_rx_buf *rb; 8476c8d8eccSSepherosa Ziehau struct bge_rx_bd *r; 848695a8586SSepherosa Ziehau bus_addr_t paddr; 849695a8586SSepherosa Ziehau int len; 8506c8d8eccSSepherosa Ziehau 851beedf5beSSepherosa Ziehau rb = &std->bnx_rx_std_buf[i]; 852841cdf08SSepherosa Ziehau KASSERT(rb->bnx_rx_refilled, ("RX buf %dth is not refilled", i)); 853695a8586SSepherosa Ziehau 854695a8586SSepherosa Ziehau paddr = rb->bnx_rx_paddr; 855695a8586SSepherosa Ziehau len = rb->bnx_rx_len; 856695a8586SSepherosa Ziehau 857695a8586SSepherosa Ziehau cpu_mfence(); 858695a8586SSepherosa Ziehau 859841cdf08SSepherosa Ziehau rb->bnx_rx_refilled = 0; 8606c8d8eccSSepherosa Ziehau 861841cdf08SSepherosa Ziehau r = &std->bnx_rx_std_ring[i]; 862695a8586SSepherosa Ziehau r->bge_addr.bge_addr_lo = BGE_ADDR_LO(paddr); 863695a8586SSepherosa Ziehau r->bge_addr.bge_addr_hi = BGE_ADDR_HI(paddr); 864695a8586SSepherosa Ziehau r->bge_len = len; 8656c8d8eccSSepherosa Ziehau r->bge_idx = i; 8666c8d8eccSSepherosa Ziehau r->bge_flags = BGE_RXBDFLAG_END; 8676c8d8eccSSepherosa Ziehau } 8686c8d8eccSSepherosa Ziehau 8696c8d8eccSSepherosa Ziehau /* 8706c8d8eccSSepherosa Ziehau * Initialize a jumbo receive ring descriptor. This allocates 8716c8d8eccSSepherosa Ziehau * a jumbo buffer from the pool managed internally by the driver. 8726c8d8eccSSepherosa Ziehau */ 8736c8d8eccSSepherosa Ziehau static int 8746c8d8eccSSepherosa Ziehau bnx_newbuf_jumbo(struct bnx_softc *sc, int i, int init) 8756c8d8eccSSepherosa Ziehau { 8766c8d8eccSSepherosa Ziehau struct mbuf *m_new = NULL; 8776c8d8eccSSepherosa Ziehau struct bnx_jslot *buf; 8786c8d8eccSSepherosa Ziehau bus_addr_t paddr; 8796c8d8eccSSepherosa Ziehau 8806c8d8eccSSepherosa Ziehau /* Allocate the mbuf. */ 881b5523eacSSascha Wildner MGETHDR(m_new, init ? M_WAITOK : M_NOWAIT, MT_DATA); 8826c8d8eccSSepherosa Ziehau if (m_new == NULL) 8836c8d8eccSSepherosa Ziehau return ENOBUFS; 8846c8d8eccSSepherosa Ziehau 8856c8d8eccSSepherosa Ziehau /* Allocate the jumbo buffer */ 8866c8d8eccSSepherosa Ziehau buf = bnx_jalloc(sc); 8876c8d8eccSSepherosa Ziehau if (buf == NULL) { 8886c8d8eccSSepherosa Ziehau m_freem(m_new); 8896c8d8eccSSepherosa Ziehau return ENOBUFS; 8906c8d8eccSSepherosa Ziehau } 8916c8d8eccSSepherosa Ziehau 8926c8d8eccSSepherosa Ziehau /* Attach the buffer to the mbuf. */ 8936c8d8eccSSepherosa Ziehau m_new->m_ext.ext_arg = buf; 8946c8d8eccSSepherosa Ziehau m_new->m_ext.ext_buf = buf->bnx_buf; 8956c8d8eccSSepherosa Ziehau m_new->m_ext.ext_free = bnx_jfree; 8966c8d8eccSSepherosa Ziehau m_new->m_ext.ext_ref = bnx_jref; 8976c8d8eccSSepherosa Ziehau m_new->m_ext.ext_size = BNX_JUMBO_FRAMELEN; 8986c8d8eccSSepherosa Ziehau 8996c8d8eccSSepherosa Ziehau m_new->m_flags |= M_EXT; 9006c8d8eccSSepherosa Ziehau 9016c8d8eccSSepherosa Ziehau m_new->m_data = m_new->m_ext.ext_buf; 9026c8d8eccSSepherosa Ziehau m_new->m_len = m_new->m_pkthdr.len = m_new->m_ext.ext_size; 9036c8d8eccSSepherosa Ziehau 9046c8d8eccSSepherosa Ziehau paddr = buf->bnx_paddr; 9056c8d8eccSSepherosa Ziehau m_adj(m_new, ETHER_ALIGN); 9066c8d8eccSSepherosa Ziehau paddr += ETHER_ALIGN; 9076c8d8eccSSepherosa Ziehau 9086c8d8eccSSepherosa Ziehau /* Save necessary information */ 909beedf5beSSepherosa Ziehau sc->bnx_cdata.bnx_rx_jumbo_chain[i].bnx_rx_mbuf = m_new; 910beedf5beSSepherosa Ziehau sc->bnx_cdata.bnx_rx_jumbo_chain[i].bnx_rx_paddr = paddr; 9116c8d8eccSSepherosa Ziehau 9126c8d8eccSSepherosa Ziehau /* Set up the descriptor. */ 9136c8d8eccSSepherosa Ziehau bnx_setup_rxdesc_jumbo(sc, i); 9146c8d8eccSSepherosa Ziehau return 0; 9156c8d8eccSSepherosa Ziehau } 9166c8d8eccSSepherosa Ziehau 9176c8d8eccSSepherosa Ziehau static void 9186c8d8eccSSepherosa Ziehau bnx_setup_rxdesc_jumbo(struct bnx_softc *sc, int i) 9196c8d8eccSSepherosa Ziehau { 9206c8d8eccSSepherosa Ziehau struct bge_rx_bd *r; 921beedf5beSSepherosa Ziehau struct bnx_rx_buf *rc; 9226c8d8eccSSepherosa Ziehau 9236c8d8eccSSepherosa Ziehau r = &sc->bnx_ldata.bnx_rx_jumbo_ring[i]; 9246c8d8eccSSepherosa Ziehau rc = &sc->bnx_cdata.bnx_rx_jumbo_chain[i]; 9256c8d8eccSSepherosa Ziehau 926beedf5beSSepherosa Ziehau r->bge_addr.bge_addr_lo = BGE_ADDR_LO(rc->bnx_rx_paddr); 927beedf5beSSepherosa Ziehau r->bge_addr.bge_addr_hi = BGE_ADDR_HI(rc->bnx_rx_paddr); 928beedf5beSSepherosa Ziehau r->bge_len = rc->bnx_rx_mbuf->m_len; 9296c8d8eccSSepherosa Ziehau r->bge_idx = i; 9306c8d8eccSSepherosa Ziehau r->bge_flags = BGE_RXBDFLAG_END|BGE_RXBDFLAG_JUMBO_RING; 9316c8d8eccSSepherosa Ziehau } 9326c8d8eccSSepherosa Ziehau 9336c8d8eccSSepherosa Ziehau static int 934beedf5beSSepherosa Ziehau bnx_init_rx_ring_std(struct bnx_rx_std_ring *std) 9356c8d8eccSSepherosa Ziehau { 9366c8d8eccSSepherosa Ziehau int i, error; 9376c8d8eccSSepherosa Ziehau 9386c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_STD_RX_RING_CNT; i++) { 939beedf5beSSepherosa Ziehau /* Use the first RX return ring's tmp RX mbuf DMA map */ 940beedf5beSSepherosa Ziehau error = bnx_newbuf_std(&std->bnx_sc->bnx_rx_ret_ring[0], i, 1); 9416c8d8eccSSepherosa Ziehau if (error) 9426c8d8eccSSepherosa Ziehau return error; 943841cdf08SSepherosa Ziehau bnx_setup_rxdesc_std(std, i); 94487c7a7cfSSascha Wildner } 9456c8d8eccSSepherosa Ziehau 946625c3ba3SSepherosa Ziehau std->bnx_rx_std_used = 0; 947841cdf08SSepherosa Ziehau std->bnx_rx_std_refill = 0; 948841cdf08SSepherosa Ziehau std->bnx_rx_std_running = 0; 949841cdf08SSepherosa Ziehau cpu_sfence(); 950841cdf08SSepherosa Ziehau lwkt_serialize_handler_enable(&std->bnx_rx_std_serialize); 951841cdf08SSepherosa Ziehau 952beedf5beSSepherosa Ziehau std->bnx_rx_std = BGE_STD_RX_RING_CNT - 1; 953beedf5beSSepherosa Ziehau bnx_writembx(std->bnx_sc, BGE_MBX_RX_STD_PROD_LO, std->bnx_rx_std); 9546c8d8eccSSepherosa Ziehau 9556c8d8eccSSepherosa Ziehau return(0); 9566c8d8eccSSepherosa Ziehau } 9576c8d8eccSSepherosa Ziehau 9586c8d8eccSSepherosa Ziehau static void 959beedf5beSSepherosa Ziehau bnx_free_rx_ring_std(struct bnx_rx_std_ring *std) 9606c8d8eccSSepherosa Ziehau { 9616c8d8eccSSepherosa Ziehau int i; 9626c8d8eccSSepherosa Ziehau 963841cdf08SSepherosa Ziehau lwkt_serialize_handler_disable(&std->bnx_rx_std_serialize); 964841cdf08SSepherosa Ziehau 9656c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_STD_RX_RING_CNT; i++) { 966beedf5beSSepherosa Ziehau struct bnx_rx_buf *rb = &std->bnx_rx_std_buf[i]; 9676c8d8eccSSepherosa Ziehau 968841cdf08SSepherosa Ziehau rb->bnx_rx_refilled = 0; 969beedf5beSSepherosa Ziehau if (rb->bnx_rx_mbuf != NULL) { 970beedf5beSSepherosa Ziehau bus_dmamap_unload(std->bnx_rx_mtag, rb->bnx_rx_dmamap); 971beedf5beSSepherosa Ziehau m_freem(rb->bnx_rx_mbuf); 972beedf5beSSepherosa Ziehau rb->bnx_rx_mbuf = NULL; 9736c8d8eccSSepherosa Ziehau } 974beedf5beSSepherosa Ziehau bzero(&std->bnx_rx_std_ring[i], sizeof(struct bge_rx_bd)); 9756c8d8eccSSepherosa Ziehau } 9766c8d8eccSSepherosa Ziehau } 9776c8d8eccSSepherosa Ziehau 9786c8d8eccSSepherosa Ziehau static int 9796c8d8eccSSepherosa Ziehau bnx_init_rx_ring_jumbo(struct bnx_softc *sc) 9806c8d8eccSSepherosa Ziehau { 9816c8d8eccSSepherosa Ziehau struct bge_rcb *rcb; 9826c8d8eccSSepherosa Ziehau int i, error; 9836c8d8eccSSepherosa Ziehau 9846c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) { 9856c8d8eccSSepherosa Ziehau error = bnx_newbuf_jumbo(sc, i, 1); 9866c8d8eccSSepherosa Ziehau if (error) 9876c8d8eccSSepherosa Ziehau return error; 98887c7a7cfSSascha Wildner } 9896c8d8eccSSepherosa Ziehau 9906c8d8eccSSepherosa Ziehau sc->bnx_jumbo = BGE_JUMBO_RX_RING_CNT - 1; 9916c8d8eccSSepherosa Ziehau 9926c8d8eccSSepherosa Ziehau rcb = &sc->bnx_ldata.bnx_info.bnx_jumbo_rx_rcb; 9936c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(0, 0); 9946c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags); 9956c8d8eccSSepherosa Ziehau 9966c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bnx_jumbo); 9976c8d8eccSSepherosa Ziehau 9986c8d8eccSSepherosa Ziehau return(0); 9996c8d8eccSSepherosa Ziehau } 10006c8d8eccSSepherosa Ziehau 10016c8d8eccSSepherosa Ziehau static void 10026c8d8eccSSepherosa Ziehau bnx_free_rx_ring_jumbo(struct bnx_softc *sc) 10036c8d8eccSSepherosa Ziehau { 10046c8d8eccSSepherosa Ziehau int i; 10056c8d8eccSSepherosa Ziehau 10066c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) { 1007beedf5beSSepherosa Ziehau struct bnx_rx_buf *rc = &sc->bnx_cdata.bnx_rx_jumbo_chain[i]; 10086c8d8eccSSepherosa Ziehau 1009beedf5beSSepherosa Ziehau if (rc->bnx_rx_mbuf != NULL) { 1010beedf5beSSepherosa Ziehau m_freem(rc->bnx_rx_mbuf); 1011beedf5beSSepherosa Ziehau rc->bnx_rx_mbuf = NULL; 10126c8d8eccSSepherosa Ziehau } 10136c8d8eccSSepherosa Ziehau bzero(&sc->bnx_ldata.bnx_rx_jumbo_ring[i], 10146c8d8eccSSepherosa Ziehau sizeof(struct bge_rx_bd)); 10156c8d8eccSSepherosa Ziehau } 10166c8d8eccSSepherosa Ziehau } 10176c8d8eccSSepherosa Ziehau 10186c8d8eccSSepherosa Ziehau static void 101933a04907SSepherosa Ziehau bnx_free_tx_ring(struct bnx_tx_ring *txr) 10206c8d8eccSSepherosa Ziehau { 10216c8d8eccSSepherosa Ziehau int i; 10226c8d8eccSSepherosa Ziehau 10236c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_TX_RING_CNT; i++) { 1024fa4b1067SSepherosa Ziehau struct bnx_tx_buf *buf = &txr->bnx_tx_buf[i]; 1025fa4b1067SSepherosa Ziehau 1026fa4b1067SSepherosa Ziehau if (buf->bnx_tx_mbuf != NULL) { 102733a04907SSepherosa Ziehau bus_dmamap_unload(txr->bnx_tx_mtag, 1028fa4b1067SSepherosa Ziehau buf->bnx_tx_dmamap); 1029fa4b1067SSepherosa Ziehau m_freem(buf->bnx_tx_mbuf); 1030fa4b1067SSepherosa Ziehau buf->bnx_tx_mbuf = NULL; 10316c8d8eccSSepherosa Ziehau } 103233a04907SSepherosa Ziehau bzero(&txr->bnx_tx_ring[i], sizeof(struct bge_tx_bd)); 10336c8d8eccSSepherosa Ziehau } 103433a04907SSepherosa Ziehau txr->bnx_tx_saved_considx = BNX_TXCONS_UNSET; 10356c8d8eccSSepherosa Ziehau } 10366c8d8eccSSepherosa Ziehau 10376c8d8eccSSepherosa Ziehau static int 103833a04907SSepherosa Ziehau bnx_init_tx_ring(struct bnx_tx_ring *txr) 10396c8d8eccSSepherosa Ziehau { 1040fa639b88SSepherosa Ziehau txr->bnx_tx_cnt = 0; 104133a04907SSepherosa Ziehau txr->bnx_tx_saved_considx = 0; 104233a04907SSepherosa Ziehau txr->bnx_tx_prodidx = 0; 10436c8d8eccSSepherosa Ziehau 10446c8d8eccSSepherosa Ziehau /* Initialize transmit producer index for host-memory send ring. */ 10458bd43d5dSSepherosa Ziehau bnx_writembx(txr->bnx_sc, txr->bnx_tx_mbx, txr->bnx_tx_prodidx); 10466c8d8eccSSepherosa Ziehau 10476c8d8eccSSepherosa Ziehau return(0); 10486c8d8eccSSepherosa Ziehau } 10496c8d8eccSSepherosa Ziehau 10506c8d8eccSSepherosa Ziehau static void 10516c8d8eccSSepherosa Ziehau bnx_setmulti(struct bnx_softc *sc) 10526c8d8eccSSepherosa Ziehau { 10536c8d8eccSSepherosa Ziehau struct ifnet *ifp; 10546c8d8eccSSepherosa Ziehau struct ifmultiaddr *ifma; 10556c8d8eccSSepherosa Ziehau uint32_t hashes[4] = { 0, 0, 0, 0 }; 10566c8d8eccSSepherosa Ziehau int h, i; 10576c8d8eccSSepherosa Ziehau 10586c8d8eccSSepherosa Ziehau ifp = &sc->arpcom.ac_if; 10596c8d8eccSSepherosa Ziehau 10606c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 10616c8d8eccSSepherosa Ziehau for (i = 0; i < 4; i++) 10626c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0xFFFFFFFF); 10636c8d8eccSSepherosa Ziehau return; 10646c8d8eccSSepherosa Ziehau } 10656c8d8eccSSepherosa Ziehau 10666c8d8eccSSepherosa Ziehau /* First, zot all the existing filters. */ 10676c8d8eccSSepherosa Ziehau for (i = 0; i < 4; i++) 10686c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0); 10696c8d8eccSSepherosa Ziehau 10706c8d8eccSSepherosa Ziehau /* Now program new ones. */ 10716c8d8eccSSepherosa Ziehau TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 10726c8d8eccSSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 10736c8d8eccSSepherosa Ziehau continue; 10746c8d8eccSSepherosa Ziehau h = ether_crc32_le( 10756c8d8eccSSepherosa Ziehau LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 10766c8d8eccSSepherosa Ziehau ETHER_ADDR_LEN) & 0x7f; 10776c8d8eccSSepherosa Ziehau hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F); 10786c8d8eccSSepherosa Ziehau } 10796c8d8eccSSepherosa Ziehau 10806c8d8eccSSepherosa Ziehau for (i = 0; i < 4; i++) 10816c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), hashes[i]); 10826c8d8eccSSepherosa Ziehau } 10836c8d8eccSSepherosa Ziehau 10846c8d8eccSSepherosa Ziehau /* 10856c8d8eccSSepherosa Ziehau * Do endian, PCI and DMA initialization. Also check the on-board ROM 10866c8d8eccSSepherosa Ziehau * self-test results. 10876c8d8eccSSepherosa Ziehau */ 10886c8d8eccSSepherosa Ziehau static int 10896c8d8eccSSepherosa Ziehau bnx_chipinit(struct bnx_softc *sc) 10906c8d8eccSSepherosa Ziehau { 10916c8d8eccSSepherosa Ziehau uint32_t dma_rw_ctl, mode_ctl; 10926c8d8eccSSepherosa Ziehau int i; 10936c8d8eccSSepherosa Ziehau 10946c8d8eccSSepherosa Ziehau /* Set endian type before we access any non-PCI registers. */ 10956c8d8eccSSepherosa Ziehau pci_write_config(sc->bnx_dev, BGE_PCI_MISC_CTL, 10966c8d8eccSSepherosa Ziehau BGE_INIT | BGE_PCIMISCCTL_TAGGED_STATUS, 4); 10976c8d8eccSSepherosa Ziehau 10986c8d8eccSSepherosa Ziehau /* 10996c8d8eccSSepherosa Ziehau * Clear the MAC statistics block in the NIC's 11006c8d8eccSSepherosa Ziehau * internal memory. 11016c8d8eccSSepherosa Ziehau */ 11026c8d8eccSSepherosa Ziehau for (i = BGE_STATS_BLOCK; 11036c8d8eccSSepherosa Ziehau i < BGE_STATS_BLOCK_END + 1; i += sizeof(uint32_t)) 11046c8d8eccSSepherosa Ziehau BNX_MEMWIN_WRITE(sc, i, 0); 11056c8d8eccSSepherosa Ziehau 11066c8d8eccSSepherosa Ziehau for (i = BGE_STATUS_BLOCK; 11076c8d8eccSSepherosa Ziehau i < BGE_STATUS_BLOCK_END + 1; i += sizeof(uint32_t)) 11086c8d8eccSSepherosa Ziehau BNX_MEMWIN_WRITE(sc, i, 0); 11096c8d8eccSSepherosa Ziehau 1110d7872545SSepherosa Ziehau if (BNX_IS_57765_FAMILY(sc)) { 1111d7872545SSepherosa Ziehau uint32_t val; 1112d7872545SSepherosa Ziehau 1113d7872545SSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM57765_A0) { 1114d7872545SSepherosa Ziehau mode_ctl = CSR_READ_4(sc, BGE_MODE_CTL); 1115d7872545SSepherosa Ziehau val = mode_ctl & ~BGE_MODECTL_PCIE_PORTS; 1116d7872545SSepherosa Ziehau 1117d7872545SSepherosa Ziehau /* Access the lower 1K of PL PCI-E block registers. */ 1118d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, 1119d7872545SSepherosa Ziehau val | BGE_MODECTL_PCIE_PL_SEL); 1120d7872545SSepherosa Ziehau 1121d7872545SSepherosa Ziehau val = CSR_READ_4(sc, BGE_PCIE_PL_LO_PHYCTL5); 1122d7872545SSepherosa Ziehau val |= BGE_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ; 1123d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_PCIE_PL_LO_PHYCTL5, val); 1124d7872545SSepherosa Ziehau 1125d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, mode_ctl); 1126d7872545SSepherosa Ziehau } 1127d7872545SSepherosa Ziehau if (sc->bnx_chiprev != BGE_CHIPREV_57765_AX) { 11281749651bSSepherosa Ziehau /* Fix transmit hangs */ 11291749651bSSepherosa Ziehau val = CSR_READ_4(sc, BGE_CPMU_PADRNG_CTL); 11301749651bSSepherosa Ziehau val |= BGE_CPMU_PADRNG_CTL_RDIV2; 11311749651bSSepherosa Ziehau CSR_WRITE_4(sc, BGE_CPMU_PADRNG_CTL, val); 11321749651bSSepherosa Ziehau 1133d7872545SSepherosa Ziehau mode_ctl = CSR_READ_4(sc, BGE_MODE_CTL); 1134d7872545SSepherosa Ziehau val = mode_ctl & ~BGE_MODECTL_PCIE_PORTS; 1135d7872545SSepherosa Ziehau 1136d7872545SSepherosa Ziehau /* Access the lower 1K of DL PCI-E block registers. */ 1137d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, 1138d7872545SSepherosa Ziehau val | BGE_MODECTL_PCIE_DL_SEL); 1139d7872545SSepherosa Ziehau 1140d7872545SSepherosa Ziehau val = CSR_READ_4(sc, BGE_PCIE_DL_LO_FTSMAX); 1141d7872545SSepherosa Ziehau val &= ~BGE_PCIE_DL_LO_FTSMAX_MASK; 1142d7872545SSepherosa Ziehau val |= BGE_PCIE_DL_LO_FTSMAX_VAL; 1143d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_PCIE_DL_LO_FTSMAX, val); 1144d7872545SSepherosa Ziehau 1145d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, mode_ctl); 1146d7872545SSepherosa Ziehau } 1147d7872545SSepherosa Ziehau 1148d7872545SSepherosa Ziehau val = CSR_READ_4(sc, BGE_CPMU_LSPD_10MB_CLK); 1149d7872545SSepherosa Ziehau val &= ~BGE_CPMU_LSPD_10MB_MACCLK_MASK; 1150d7872545SSepherosa Ziehau val |= BGE_CPMU_LSPD_10MB_MACCLK_6_25; 1151d7872545SSepherosa Ziehau CSR_WRITE_4(sc, BGE_CPMU_LSPD_10MB_CLK, val); 1152d7872545SSepherosa Ziehau } 1153d7872545SSepherosa Ziehau 11542890cca3SSepherosa Ziehau /* 11552890cca3SSepherosa Ziehau * Set up the PCI DMA control register. 11562890cca3SSepherosa Ziehau */ 11572890cca3SSepherosa Ziehau dma_rw_ctl = pci_read_config(sc->bnx_dev, BGE_PCI_DMA_RW_CTL, 4); 11582890cca3SSepherosa Ziehau /* 11592890cca3SSepherosa Ziehau * Disable 32bytes cache alignment for DMA write to host memory 11602890cca3SSepherosa Ziehau * 11612890cca3SSepherosa Ziehau * NOTE: 11622890cca3SSepherosa Ziehau * 64bytes cache alignment for DMA write to host memory is still 11632890cca3SSepherosa Ziehau * enabled. 11642890cca3SSepherosa Ziehau */ 11652890cca3SSepherosa Ziehau dma_rw_ctl |= BGE_PCIDMARWCTL_DIS_CACHE_ALIGNMENT; 11666c8d8eccSSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM57765_A0) 11676c8d8eccSSepherosa Ziehau dma_rw_ctl &= ~BGE_PCIDMARWCTL_CRDRDR_RDMA_MRRS_MSK; 11686c8d8eccSSepherosa Ziehau /* 11696c8d8eccSSepherosa Ziehau * Enable HW workaround for controllers that misinterpret 11706c8d8eccSSepherosa Ziehau * a status tag update and leave interrupts permanently 11716c8d8eccSSepherosa Ziehau * disabled. 11726c8d8eccSSepherosa Ziehau */ 11736c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev != BGE_ASICREV_BCM5717 && 1174b96cbbb6SSepherosa Ziehau sc->bnx_asicrev != BGE_ASICREV_BCM5762 && 11752890cca3SSepherosa Ziehau !BNX_IS_57765_FAMILY(sc)) 11766c8d8eccSSepherosa Ziehau dma_rw_ctl |= BGE_PCIDMARWCTL_TAGGED_STATUS_WA; 11772890cca3SSepherosa Ziehau if (bootverbose) { 11782890cca3SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "DMA read/write %#x\n", 11792890cca3SSepherosa Ziehau dma_rw_ctl); 11806c8d8eccSSepherosa Ziehau } 11816c8d8eccSSepherosa Ziehau pci_write_config(sc->bnx_dev, BGE_PCI_DMA_RW_CTL, dma_rw_ctl, 4); 11826c8d8eccSSepherosa Ziehau 11836c8d8eccSSepherosa Ziehau /* 11846c8d8eccSSepherosa Ziehau * Set up general mode register. 11856c8d8eccSSepherosa Ziehau */ 11869f5082d5SSepherosa Ziehau mode_ctl = bnx_dma_swap_options(sc); 11879f5082d5SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 11889f5082d5SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 11899f5082d5SSepherosa Ziehau /* Retain Host-2-BMC settings written by APE firmware. */ 11909f5082d5SSepherosa Ziehau mode_ctl |= CSR_READ_4(sc, BGE_MODE_CTL) & 11919f5082d5SSepherosa Ziehau (BGE_MODECTL_BYTESWAP_B2HRX_DATA | 11929f5082d5SSepherosa Ziehau BGE_MODECTL_WORDSWAP_B2HRX_DATA | 11939f5082d5SSepherosa Ziehau BGE_MODECTL_B2HRX_ENABLE | BGE_MODECTL_HTX2B_ENABLE); 11949f5082d5SSepherosa Ziehau } 11959f5082d5SSepherosa Ziehau mode_ctl |= BGE_MODECTL_MAC_ATTN_INTR | 11966c8d8eccSSepherosa Ziehau BGE_MODECTL_HOST_SEND_BDS | BGE_MODECTL_TX_NO_PHDR_CSUM; 11976c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, mode_ctl); 11986c8d8eccSSepherosa Ziehau 11996c8d8eccSSepherosa Ziehau /* 12006c8d8eccSSepherosa Ziehau * Disable memory write invalidate. Apparently it is not supported 12016c8d8eccSSepherosa Ziehau * properly by these devices. Also ensure that INTx isn't disabled, 12026c8d8eccSSepherosa Ziehau * as these chips need it even when using MSI. 12036c8d8eccSSepherosa Ziehau */ 12046c8d8eccSSepherosa Ziehau PCI_CLRBIT(sc->bnx_dev, BGE_PCI_CMD, 12056c8d8eccSSepherosa Ziehau (PCIM_CMD_MWRICEN | PCIM_CMD_INTxDIS), 4); 12066c8d8eccSSepherosa Ziehau 12076c8d8eccSSepherosa Ziehau /* Set the timer prescaler (always 66Mhz) */ 12086c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MISC_CFG, 65 << 1/*BGE_32BITTIME_66MHZ*/); 12096c8d8eccSSepherosa Ziehau 12106c8d8eccSSepherosa Ziehau return(0); 12116c8d8eccSSepherosa Ziehau } 12126c8d8eccSSepherosa Ziehau 12136c8d8eccSSepherosa Ziehau static int 12146c8d8eccSSepherosa Ziehau bnx_blockinit(struct bnx_softc *sc) 12156c8d8eccSSepherosa Ziehau { 1216695a8586SSepherosa Ziehau struct bnx_intr_data *intr; 12176c8d8eccSSepherosa Ziehau struct bge_rcb *rcb; 12186c8d8eccSSepherosa Ziehau bus_size_t vrcb; 12196c8d8eccSSepherosa Ziehau bge_hostaddr taddr; 12206c8d8eccSSepherosa Ziehau uint32_t val; 12216c8d8eccSSepherosa Ziehau int i, limit; 12226c8d8eccSSepherosa Ziehau 12236c8d8eccSSepherosa Ziehau /* 12246c8d8eccSSepherosa Ziehau * Initialize the memory window pointer register so that 12256c8d8eccSSepherosa Ziehau * we can access the first 32K of internal NIC RAM. This will 12266c8d8eccSSepherosa Ziehau * allow us to set up the TX send ring RCBs and the RX return 12276c8d8eccSSepherosa Ziehau * ring RCBs, plus other things which live in NIC memory. 12286c8d8eccSSepherosa Ziehau */ 12296c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_PCI_MEMWIN_BASEADDR, 0); 12306c8d8eccSSepherosa Ziehau 12316c8d8eccSSepherosa Ziehau /* Configure mbuf pool watermarks */ 1232f368d0d9SSepherosa Ziehau if (BNX_IS_57765_PLUS(sc)) { 12336c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0); 12346c8d8eccSSepherosa Ziehau if (sc->arpcom.ac_if.if_mtu > ETHERMTU) { 12356c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x7e); 12366c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0xea); 12376c8d8eccSSepherosa Ziehau } else { 12386c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x2a); 12396c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0xa0); 12406c8d8eccSSepherosa Ziehau } 12416c8d8eccSSepherosa Ziehau } else { 12426c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0); 12436c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x10); 12446c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0x60); 12456c8d8eccSSepherosa Ziehau } 12466c8d8eccSSepherosa Ziehau 12476c8d8eccSSepherosa Ziehau /* Configure DMA resource watermarks */ 12486c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_LOWAT, 5); 12496c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_HIWAT, 10); 12506c8d8eccSSepherosa Ziehau 12516c8d8eccSSepherosa Ziehau /* Enable buffer manager */ 12526c8d8eccSSepherosa Ziehau val = BGE_BMANMODE_ENABLE | BGE_BMANMODE_LOMBUF_ATTN; 12536c8d8eccSSepherosa Ziehau /* 12546c8d8eccSSepherosa Ziehau * Change the arbitration algorithm of TXMBUF read request to 12556c8d8eccSSepherosa Ziehau * round-robin instead of priority based for BCM5719. When 12566c8d8eccSSepherosa Ziehau * TXFIFO is almost empty, RDMA will hold its request until 12576c8d8eccSSepherosa Ziehau * TXFIFO is not almost empty. 12586c8d8eccSSepherosa Ziehau */ 12596c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719) 12606c8d8eccSSepherosa Ziehau val |= BGE_BMANMODE_NO_TX_UNDERRUN; 1261e5eebe34SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5717 || 1262e5eebe34SSepherosa Ziehau sc->bnx_chipid == BGE_CHIPID_BCM5719_A0 || 1263e5eebe34SSepherosa Ziehau sc->bnx_chipid == BGE_CHIPID_BCM5720_A0) 1264e5eebe34SSepherosa Ziehau val |= BGE_BMANMODE_LOMBUF_ATTN; 12656c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_BMAN_MODE, val); 12666c8d8eccSSepherosa Ziehau 12676c8d8eccSSepherosa Ziehau /* Poll for buffer manager start indication */ 12686c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 12696c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_BMAN_MODE) & BGE_BMANMODE_ENABLE) 12706c8d8eccSSepherosa Ziehau break; 12716c8d8eccSSepherosa Ziehau DELAY(10); 12726c8d8eccSSepherosa Ziehau } 12736c8d8eccSSepherosa Ziehau 12746c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 12756c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 12766c8d8eccSSepherosa Ziehau "buffer manager failed to start\n"); 12776c8d8eccSSepherosa Ziehau return(ENXIO); 12786c8d8eccSSepherosa Ziehau } 12796c8d8eccSSepherosa Ziehau 12806c8d8eccSSepherosa Ziehau /* Enable flow-through queues */ 12816c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_FTQ_RESET, 0xFFFFFFFF); 12826c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_FTQ_RESET, 0); 12836c8d8eccSSepherosa Ziehau 12846c8d8eccSSepherosa Ziehau /* Wait until queue initialization is complete */ 12856c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 12866c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_FTQ_RESET) == 0) 12876c8d8eccSSepherosa Ziehau break; 12886c8d8eccSSepherosa Ziehau DELAY(10); 12896c8d8eccSSepherosa Ziehau } 12906c8d8eccSSepherosa Ziehau 12916c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 12926c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 12936c8d8eccSSepherosa Ziehau "flow-through queue init failed\n"); 12946c8d8eccSSepherosa Ziehau return(ENXIO); 12956c8d8eccSSepherosa Ziehau } 12966c8d8eccSSepherosa Ziehau 12976c8d8eccSSepherosa Ziehau /* 12986c8d8eccSSepherosa Ziehau * Summary of rings supported by the controller: 12996c8d8eccSSepherosa Ziehau * 13006c8d8eccSSepherosa Ziehau * Standard Receive Producer Ring 13016c8d8eccSSepherosa Ziehau * - This ring is used to feed receive buffers for "standard" 13026c8d8eccSSepherosa Ziehau * sized frames (typically 1536 bytes) to the controller. 13036c8d8eccSSepherosa Ziehau * 13046c8d8eccSSepherosa Ziehau * Jumbo Receive Producer Ring 13056c8d8eccSSepherosa Ziehau * - This ring is used to feed receive buffers for jumbo sized 13066c8d8eccSSepherosa Ziehau * frames (i.e. anything bigger than the "standard" frames) 13076c8d8eccSSepherosa Ziehau * to the controller. 13086c8d8eccSSepherosa Ziehau * 13096c8d8eccSSepherosa Ziehau * Mini Receive Producer Ring 13106c8d8eccSSepherosa Ziehau * - This ring is used to feed receive buffers for "mini" 13116c8d8eccSSepherosa Ziehau * sized frames to the controller. 13126c8d8eccSSepherosa Ziehau * - This feature required external memory for the controller 13136c8d8eccSSepherosa Ziehau * but was never used in a production system. Should always 13146c8d8eccSSepherosa Ziehau * be disabled. 13156c8d8eccSSepherosa Ziehau * 13166c8d8eccSSepherosa Ziehau * Receive Return Ring 13176c8d8eccSSepherosa Ziehau * - After the controller has placed an incoming frame into a 13186c8d8eccSSepherosa Ziehau * receive buffer that buffer is moved into a receive return 13196c8d8eccSSepherosa Ziehau * ring. The driver is then responsible to passing the 13202a581495SSepherosa Ziehau * buffer up to the stack. BCM5718/BCM57785 families support 13212a581495SSepherosa Ziehau * multiple receive return rings. 13226c8d8eccSSepherosa Ziehau * 13236c8d8eccSSepherosa Ziehau * Send Ring 13242a581495SSepherosa Ziehau * - This ring is used for outgoing frames. BCM5719/BCM5720 13252a581495SSepherosa Ziehau * support multiple send rings. 13266c8d8eccSSepherosa Ziehau */ 13276c8d8eccSSepherosa Ziehau 13286c8d8eccSSepherosa Ziehau /* Initialize the standard receive producer ring control block. */ 13296c8d8eccSSepherosa Ziehau rcb = &sc->bnx_ldata.bnx_info.bnx_std_rx_rcb; 13306c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_lo = 1331beedf5beSSepherosa Ziehau BGE_ADDR_LO(sc->bnx_rx_std_ring.bnx_rx_std_ring_paddr); 13326c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_hi = 1333beedf5beSSepherosa Ziehau BGE_ADDR_HI(sc->bnx_rx_std_ring.bnx_rx_std_ring_paddr); 1334f368d0d9SSepherosa Ziehau if (BNX_IS_57765_PLUS(sc)) { 13356c8d8eccSSepherosa Ziehau /* 13366c8d8eccSSepherosa Ziehau * Bits 31-16: Programmable ring size (2048, 1024, 512, .., 32) 13376c8d8eccSSepherosa Ziehau * Bits 15-2 : Maximum RX frame size 13386c8d8eccSSepherosa Ziehau * Bit 1 : 1 = Ring Disabled, 0 = Ring ENabled 13396c8d8eccSSepherosa Ziehau * Bit 0 : Reserved 13406c8d8eccSSepherosa Ziehau */ 13416c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags = 13426c8d8eccSSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(512, BNX_MAX_FRAMELEN << 2); 13436c8d8eccSSepherosa Ziehau } else { 13446c8d8eccSSepherosa Ziehau /* 13456c8d8eccSSepherosa Ziehau * Bits 31-16: Programmable ring size (512, 256, 128, 64, 32) 13466c8d8eccSSepherosa Ziehau * Bits 15-2 : Reserved (should be 0) 13476c8d8eccSSepherosa Ziehau * Bit 1 : 1 = Ring Disabled, 0 = Ring Enabled 13486c8d8eccSSepherosa Ziehau * Bit 0 : Reserved 13496c8d8eccSSepherosa Ziehau */ 13506c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(512, 0); 13516c8d8eccSSepherosa Ziehau } 1352303fdc72SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) 13536c8d8eccSSepherosa Ziehau rcb->bge_nicaddr = BGE_STD_RX_RINGS_5717; 13546c8d8eccSSepherosa Ziehau else 13556c8d8eccSSepherosa Ziehau rcb->bge_nicaddr = BGE_STD_RX_RINGS; 13566c8d8eccSSepherosa Ziehau /* Write the standard receive producer ring control block. */ 13576c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_HI, rcb->bge_hostaddr.bge_addr_hi); 13586c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_LO, rcb->bge_hostaddr.bge_addr_lo); 13596c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_STD_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags); 1360695a8586SSepherosa Ziehau if (!BNX_IS_5717_PLUS(sc)) 13616c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_STD_RCB_NICADDR, rcb->bge_nicaddr); 13626c8d8eccSSepherosa Ziehau /* Reset the standard receive producer ring producer index. */ 13636c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_RX_STD_PROD_LO, 0); 13646c8d8eccSSepherosa Ziehau 13656c8d8eccSSepherosa Ziehau /* 13666c8d8eccSSepherosa Ziehau * Initialize the jumbo RX producer ring control 13676c8d8eccSSepherosa Ziehau * block. We set the 'ring disabled' bit in the 13686c8d8eccSSepherosa Ziehau * flags field until we're actually ready to start 13696c8d8eccSSepherosa Ziehau * using this ring (i.e. once we set the MTU 13706c8d8eccSSepherosa Ziehau * high enough to require it). 13716c8d8eccSSepherosa Ziehau */ 13726c8d8eccSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) { 13736c8d8eccSSepherosa Ziehau rcb = &sc->bnx_ldata.bnx_info.bnx_jumbo_rx_rcb; 13746c8d8eccSSepherosa Ziehau /* Get the jumbo receive producer ring RCB parameters. */ 13756c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_lo = 13766c8d8eccSSepherosa Ziehau BGE_ADDR_LO(sc->bnx_ldata.bnx_rx_jumbo_ring_paddr); 13776c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_hi = 13786c8d8eccSSepherosa Ziehau BGE_ADDR_HI(sc->bnx_ldata.bnx_rx_jumbo_ring_paddr); 13796c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags = 13806c8d8eccSSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(BNX_MAX_FRAMELEN, 13816c8d8eccSSepherosa Ziehau BGE_RCB_FLAG_RING_DISABLED); 1382303fdc72SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) 13836c8d8eccSSepherosa Ziehau rcb->bge_nicaddr = BGE_JUMBO_RX_RINGS_5717; 13846c8d8eccSSepherosa Ziehau else 13856c8d8eccSSepherosa Ziehau rcb->bge_nicaddr = BGE_JUMBO_RX_RINGS; 13866c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_HADDR_HI, 13876c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_hi); 13886c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_HADDR_LO, 13896c8d8eccSSepherosa Ziehau rcb->bge_hostaddr.bge_addr_lo); 13906c8d8eccSSepherosa Ziehau /* Program the jumbo receive producer ring RCB parameters. */ 13916c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, 13926c8d8eccSSepherosa Ziehau rcb->bge_maxlen_flags); 13936c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_NICADDR, rcb->bge_nicaddr); 13946c8d8eccSSepherosa Ziehau /* Reset the jumbo receive producer ring producer index. */ 13956c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, 0); 13966c8d8eccSSepherosa Ziehau } 13976c8d8eccSSepherosa Ziehau 13986c8d8eccSSepherosa Ziehau /* 13996c8d8eccSSepherosa Ziehau * The BD ring replenish thresholds control how often the 14006c8d8eccSSepherosa Ziehau * hardware fetches new BD's from the producer rings in host 14016c8d8eccSSepherosa Ziehau * memory. Setting the value too low on a busy system can 14026c8d8eccSSepherosa Ziehau * starve the hardware and recue the throughpout. 14036c8d8eccSSepherosa Ziehau * 14046c8d8eccSSepherosa Ziehau * Set the BD ring replentish thresholds. The recommended 14056c8d8eccSSepherosa Ziehau * values are 1/8th the number of descriptors allocated to 14066c8d8eccSSepherosa Ziehau * each ring. 14076c8d8eccSSepherosa Ziehau */ 14086c8d8eccSSepherosa Ziehau val = 8; 14096c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RBDI_STD_REPL_THRESH, val); 14106c8d8eccSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) { 14116c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RBDI_JUMBO_REPL_THRESH, 14126c8d8eccSSepherosa Ziehau BGE_JUMBO_RX_RING_CNT/8); 14136c8d8eccSSepherosa Ziehau } 1414f368d0d9SSepherosa Ziehau if (BNX_IS_57765_PLUS(sc)) { 14156c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_STD_REPLENISH_LWM, 32); 14166c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_JMB_REPLENISH_LWM, 16); 14176c8d8eccSSepherosa Ziehau } 14186c8d8eccSSepherosa Ziehau 14196c8d8eccSSepherosa Ziehau /* 14206c8d8eccSSepherosa Ziehau * Disable all send rings by setting the 'ring disabled' bit 14216c8d8eccSSepherosa Ziehau * in the flags field of all the TX send ring control blocks, 14226c8d8eccSSepherosa Ziehau * located in NIC memory. 14236c8d8eccSSepherosa Ziehau */ 142480969639SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) 142580969639SSepherosa Ziehau limit = 4; 1426b96cbbb6SSepherosa Ziehau else if (BNX_IS_57765_FAMILY(sc) || 1427b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) 14284f23029eSSepherosa Ziehau limit = 2; 142980969639SSepherosa Ziehau else 14306c8d8eccSSepherosa Ziehau limit = 1; 14316c8d8eccSSepherosa Ziehau vrcb = BGE_MEMWIN_START + BGE_SEND_RING_RCB; 14326c8d8eccSSepherosa Ziehau for (i = 0; i < limit; i++) { 14336c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, 14346c8d8eccSSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_RING_DISABLED)); 14356c8d8eccSSepherosa Ziehau vrcb += sizeof(struct bge_rcb); 14366c8d8eccSSepherosa Ziehau } 14376c8d8eccSSepherosa Ziehau 1438695a8586SSepherosa Ziehau /* 1439695a8586SSepherosa Ziehau * Configure send ring RCBs 1440695a8586SSepherosa Ziehau */ 14416c8d8eccSSepherosa Ziehau vrcb = BGE_MEMWIN_START + BGE_SEND_RING_RCB; 1442695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 1443695a8586SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 1444695a8586SSepherosa Ziehau 144533a04907SSepherosa Ziehau BGE_HOSTADDR(taddr, txr->bnx_tx_ring_paddr); 1446695a8586SSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, 1447695a8586SSepherosa Ziehau taddr.bge_addr_hi); 1448695a8586SSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, 1449695a8586SSepherosa Ziehau taddr.bge_addr_lo); 14506c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, 14516c8d8eccSSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(BGE_TX_RING_CNT, 0)); 1452695a8586SSepherosa Ziehau vrcb += sizeof(struct bge_rcb); 1453695a8586SSepherosa Ziehau } 14546c8d8eccSSepherosa Ziehau 14556c8d8eccSSepherosa Ziehau /* 14566c8d8eccSSepherosa Ziehau * Disable all receive return rings by setting the 14576c8d8eccSSepherosa Ziehau * 'ring disabled' bit in the flags field of all the receive 14586c8d8eccSSepherosa Ziehau * return ring control blocks, located in NIC memory. 14596c8d8eccSSepherosa Ziehau */ 146080969639SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) { 14616c8d8eccSSepherosa Ziehau /* Should be 17, use 16 until we get an SRAM map. */ 14626c8d8eccSSepherosa Ziehau limit = 16; 1463b96cbbb6SSepherosa Ziehau } else if (BNX_IS_57765_FAMILY(sc) || 1464b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 14656c8d8eccSSepherosa Ziehau limit = 4; 14666c8d8eccSSepherosa Ziehau } else { 14676c8d8eccSSepherosa Ziehau limit = 1; 14686c8d8eccSSepherosa Ziehau } 14696c8d8eccSSepherosa Ziehau /* Disable all receive return rings. */ 14706c8d8eccSSepherosa Ziehau vrcb = BGE_MEMWIN_START + BGE_RX_RETURN_RING_RCB; 14716c8d8eccSSepherosa Ziehau for (i = 0; i < limit; i++) { 14726c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, 0); 14736c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, 0); 14746c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, 14756c8d8eccSSepherosa Ziehau BGE_RCB_FLAG_RING_DISABLED); 14766c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_RX_CONS0_LO + 14776c8d8eccSSepherosa Ziehau (i * (sizeof(uint64_t))), 0); 14786c8d8eccSSepherosa Ziehau vrcb += sizeof(struct bge_rcb); 14796c8d8eccSSepherosa Ziehau } 14806c8d8eccSSepherosa Ziehau 14816c8d8eccSSepherosa Ziehau /* 14822a581495SSepherosa Ziehau * Set up receive return rings. 14836c8d8eccSSepherosa Ziehau */ 14846c8d8eccSSepherosa Ziehau vrcb = BGE_MEMWIN_START + BGE_RX_RETURN_RING_RCB; 1485695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 1486695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[i]; 1487695a8586SSepherosa Ziehau 1488beedf5beSSepherosa Ziehau BGE_HOSTADDR(taddr, ret->bnx_rx_ret_ring_paddr); 1489695a8586SSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, 1490695a8586SSepherosa Ziehau taddr.bge_addr_hi); 1491695a8586SSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, 1492695a8586SSepherosa Ziehau taddr.bge_addr_lo); 14936c8d8eccSSepherosa Ziehau RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, 1494e0f74fc8SSepherosa Ziehau BGE_RCB_MAXLEN_FLAGS(BNX_RETURN_RING_CNT, 0)); 1495695a8586SSepherosa Ziehau vrcb += sizeof(struct bge_rcb); 1496695a8586SSepherosa Ziehau } 14976c8d8eccSSepherosa Ziehau 14986c8d8eccSSepherosa Ziehau /* Set random backoff seed for TX */ 14996c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_TX_RANDOM_BACKOFF, 15004aa71e73SSepherosa Ziehau (sc->arpcom.ac_enaddr[0] + sc->arpcom.ac_enaddr[1] + 15016c8d8eccSSepherosa Ziehau sc->arpcom.ac_enaddr[2] + sc->arpcom.ac_enaddr[3] + 15024aa71e73SSepherosa Ziehau sc->arpcom.ac_enaddr[4] + sc->arpcom.ac_enaddr[5]) & 15036c8d8eccSSepherosa Ziehau BGE_TX_BACKOFF_SEED_MASK); 15046c8d8eccSSepherosa Ziehau 15056c8d8eccSSepherosa Ziehau /* Set inter-packet gap */ 15066c8d8eccSSepherosa Ziehau val = 0x2620; 1507b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 1508b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 15096c8d8eccSSepherosa Ziehau val |= CSR_READ_4(sc, BGE_TX_LENGTHS) & 15106c8d8eccSSepherosa Ziehau (BGE_TXLEN_JMB_FRM_LEN_MSK | BGE_TXLEN_CNT_DN_VAL_MSK); 15116c8d8eccSSepherosa Ziehau } 15126c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_TX_LENGTHS, val); 15136c8d8eccSSepherosa Ziehau 15146c8d8eccSSepherosa Ziehau /* 15156c8d8eccSSepherosa Ziehau * Specify which ring to use for packets that don't match 15166c8d8eccSSepherosa Ziehau * any RX rules. 15176c8d8eccSSepherosa Ziehau */ 15186c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_RULES_CFG, 0x08); 15196c8d8eccSSepherosa Ziehau 15206c8d8eccSSepherosa Ziehau /* 15216c8d8eccSSepherosa Ziehau * Configure number of RX lists. One interrupt distribution 15226c8d8eccSSepherosa Ziehau * list, sixteen active lists, one bad frames class. 15236c8d8eccSSepherosa Ziehau */ 15246c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RXLP_CFG, 0x181); 15256c8d8eccSSepherosa Ziehau 15266c8d8eccSSepherosa Ziehau /* Inialize RX list placement stats mask. */ 15276c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RXLP_STATS_ENABLE_MASK, 0x007FFFFF); 15286c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RXLP_STATS_CTL, 0x1); 15296c8d8eccSSepherosa Ziehau 15306c8d8eccSSepherosa Ziehau /* Disable host coalescing until we get it set up */ 15316c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_MODE, 0x00000000); 15326c8d8eccSSepherosa Ziehau 15336c8d8eccSSepherosa Ziehau /* Poll to make sure it's shut down. */ 15346c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 15356c8d8eccSSepherosa Ziehau if (!(CSR_READ_4(sc, BGE_HCC_MODE) & BGE_HCCMODE_ENABLE)) 15366c8d8eccSSepherosa Ziehau break; 15376c8d8eccSSepherosa Ziehau DELAY(10); 15386c8d8eccSSepherosa Ziehau } 15396c8d8eccSSepherosa Ziehau 15406c8d8eccSSepherosa Ziehau if (i == BNX_TIMEOUT) { 15416c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 15426c8d8eccSSepherosa Ziehau "host coalescing engine failed to idle\n"); 15436c8d8eccSSepherosa Ziehau return(ENXIO); 15446c8d8eccSSepherosa Ziehau } 15456c8d8eccSSepherosa Ziehau 15466c8d8eccSSepherosa Ziehau /* Set up host coalescing defaults */ 1547695a8586SSepherosa Ziehau sc->bnx_coal_chg = BNX_RX_COAL_TICKS_CHG | 1548695a8586SSepherosa Ziehau BNX_TX_COAL_TICKS_CHG | 1549695a8586SSepherosa Ziehau BNX_RX_COAL_BDS_CHG | 1550695a8586SSepherosa Ziehau BNX_TX_COAL_BDS_CHG | 1551695a8586SSepherosa Ziehau BNX_RX_COAL_BDS_INT_CHG | 1552695a8586SSepherosa Ziehau BNX_TX_COAL_BDS_INT_CHG; 1553695a8586SSepherosa Ziehau bnx_coal_change(sc); 15546c8d8eccSSepherosa Ziehau 1555695a8586SSepherosa Ziehau /* 1556695a8586SSepherosa Ziehau * Set up addresses of status blocks 1557695a8586SSepherosa Ziehau */ 1558695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 15590a806e3aSSepherosa Ziehau bzero(intr->bnx_status_block, BGE_STATUS_BLK_SZ); 15606c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_HI, 15610a806e3aSSepherosa Ziehau BGE_ADDR_HI(intr->bnx_status_block_paddr)); 15626c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_LO, 15630a806e3aSSepherosa Ziehau BGE_ADDR_LO(intr->bnx_status_block_paddr)); 1564695a8586SSepherosa Ziehau for (i = 1; i < sc->bnx_intr_cnt; ++i) { 1565695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[i]; 1566695a8586SSepherosa Ziehau bzero(intr->bnx_status_block, BGE_STATUS_BLK_SZ); 1567695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_STATUSBLK_ADDR_HI + ((i - 1) * 8), 1568695a8586SSepherosa Ziehau BGE_ADDR_HI(intr->bnx_status_block_paddr)); 1569695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_STATUSBLK_ADDR_LO + ((i - 1) * 8), 1570695a8586SSepherosa Ziehau BGE_ADDR_LO(intr->bnx_status_block_paddr)); 1571695a8586SSepherosa Ziehau } 15726c8d8eccSSepherosa Ziehau 15736c8d8eccSSepherosa Ziehau /* Set up status block partail update size. */ 15746c8d8eccSSepherosa Ziehau val = BGE_STATBLKSZ_32BYTE; 15756c8d8eccSSepherosa Ziehau #if 0 15766c8d8eccSSepherosa Ziehau /* 15776c8d8eccSSepherosa Ziehau * Does not seem to have visible effect in both 15786c8d8eccSSepherosa Ziehau * bulk data (1472B UDP datagram) and tiny data 15796c8d8eccSSepherosa Ziehau * (18B UDP datagram) TX tests. 15806c8d8eccSSepherosa Ziehau */ 15816c8d8eccSSepherosa Ziehau val |= BGE_HCCMODE_CLRTICK_TX; 15826c8d8eccSSepherosa Ziehau #endif 15836c8d8eccSSepherosa Ziehau /* Turn on host coalescing state machine */ 15846c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_MODE, val | BGE_HCCMODE_ENABLE); 15856c8d8eccSSepherosa Ziehau 15866c8d8eccSSepherosa Ziehau /* Turn on RX BD completion state machine and enable attentions */ 15876c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RBDC_MODE, 15886c8d8eccSSepherosa Ziehau BGE_RBDCMODE_ENABLE|BGE_RBDCMODE_ATTN); 15896c8d8eccSSepherosa Ziehau 15906c8d8eccSSepherosa Ziehau /* Turn on RX list placement state machine */ 15916c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RXLP_MODE, BGE_RXLPMODE_ENABLE); 15926c8d8eccSSepherosa Ziehau 15936c8d8eccSSepherosa Ziehau val = BGE_MACMODE_TXDMA_ENB | BGE_MACMODE_RXDMA_ENB | 15946c8d8eccSSepherosa Ziehau BGE_MACMODE_RX_STATS_CLEAR | BGE_MACMODE_TX_STATS_CLEAR | 15956c8d8eccSSepherosa Ziehau BGE_MACMODE_RX_STATS_ENB | BGE_MACMODE_TX_STATS_ENB | 15966c8d8eccSSepherosa Ziehau BGE_MACMODE_FRMHDR_DMA_ENB; 15976c8d8eccSSepherosa Ziehau 15986c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) 15996c8d8eccSSepherosa Ziehau val |= BGE_PORTMODE_TBI; 16006c8d8eccSSepherosa Ziehau else if (sc->bnx_flags & BNX_FLAG_MII_SERDES) 16016c8d8eccSSepherosa Ziehau val |= BGE_PORTMODE_GMII; 16026c8d8eccSSepherosa Ziehau else 16036c8d8eccSSepherosa Ziehau val |= BGE_PORTMODE_MII; 16046c8d8eccSSepherosa Ziehau 16059f5082d5SSepherosa Ziehau /* Allow APE to send/receive frames. */ 16069f5082d5SSepherosa Ziehau if (sc->bnx_mfw_flags & BNX_MFW_ON_APE) 16079f5082d5SSepherosa Ziehau val |= BGE_MACMODE_APE_RX_EN | BGE_MACMODE_APE_TX_EN; 16089f5082d5SSepherosa Ziehau 16096c8d8eccSSepherosa Ziehau /* Turn on DMA, clear stats */ 16106c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_MODE, val); 16114aa71e73SSepherosa Ziehau DELAY(40); 16126c8d8eccSSepherosa Ziehau 16136c8d8eccSSepherosa Ziehau /* Set misc. local control, enable interrupts on attentions */ 16144aa71e73SSepherosa Ziehau BNX_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_ONATTN); 16156c8d8eccSSepherosa Ziehau 16166c8d8eccSSepherosa Ziehau #ifdef notdef 16176c8d8eccSSepherosa Ziehau /* Assert GPIO pins for PHY reset */ 16186c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_MISCIO_OUT0| 16196c8d8eccSSepherosa Ziehau BGE_MLC_MISCIO_OUT1|BGE_MLC_MISCIO_OUT2); 16206c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_MISCIO_OUTEN0| 16216c8d8eccSSepherosa Ziehau BGE_MLC_MISCIO_OUTEN1|BGE_MLC_MISCIO_OUTEN2); 16226c8d8eccSSepherosa Ziehau #endif 16236c8d8eccSSepherosa Ziehau 1624695a8586SSepherosa Ziehau if (sc->bnx_intr_type == PCI_INTR_TYPE_MSIX) 1625695a8586SSepherosa Ziehau bnx_enable_msi(sc, TRUE); 1626695a8586SSepherosa Ziehau 16276c8d8eccSSepherosa Ziehau /* Turn on write DMA state machine */ 16286c8d8eccSSepherosa Ziehau val = BGE_WDMAMODE_ENABLE|BGE_WDMAMODE_ALL_ATTNS; 16296c8d8eccSSepherosa Ziehau /* Enable host coalescing bug fix. */ 16306c8d8eccSSepherosa Ziehau val |= BGE_WDMAMODE_STATUS_TAG_FIX; 16316c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5785) { 16326c8d8eccSSepherosa Ziehau /* Request larger DMA burst size to get better performance. */ 16336c8d8eccSSepherosa Ziehau val |= BGE_WDMAMODE_BURST_ALL_DATA; 16346c8d8eccSSepherosa Ziehau } 16356c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_WDMA_MODE, val); 16366c8d8eccSSepherosa Ziehau DELAY(40); 16376c8d8eccSSepherosa Ziehau 16383730a14dSSepherosa Ziehau if (BNX_IS_57765_PLUS(sc)) { 1639b96cbbb6SSepherosa Ziehau uint32_t dmactl, dmactl_reg; 16406c8d8eccSSepherosa Ziehau 1641b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5762) 1642b96cbbb6SSepherosa Ziehau dmactl_reg = BGE_RDMA_RSRVCTRL2; 1643b96cbbb6SSepherosa Ziehau else 1644b96cbbb6SSepherosa Ziehau dmactl_reg = BGE_RDMA_RSRVCTRL; 1645b96cbbb6SSepherosa Ziehau 1646b96cbbb6SSepherosa Ziehau dmactl = CSR_READ_4(sc, dmactl_reg); 16476c8d8eccSSepherosa Ziehau /* 16486c8d8eccSSepherosa Ziehau * Adjust tx margin to prevent TX data corruption and 16496c8d8eccSSepherosa Ziehau * fix internal FIFO overflow. 16506c8d8eccSSepherosa Ziehau */ 16516c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719 || 1652b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 1653b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 16546c8d8eccSSepherosa Ziehau dmactl &= ~(BGE_RDMA_RSRVCTRL_FIFO_LWM_MASK | 16556c8d8eccSSepherosa Ziehau BGE_RDMA_RSRVCTRL_FIFO_HWM_MASK | 16566c8d8eccSSepherosa Ziehau BGE_RDMA_RSRVCTRL_TXMRGN_MASK); 16576c8d8eccSSepherosa Ziehau dmactl |= BGE_RDMA_RSRVCTRL_FIFO_LWM_1_5K | 16586c8d8eccSSepherosa Ziehau BGE_RDMA_RSRVCTRL_FIFO_HWM_1_5K | 16596c8d8eccSSepherosa Ziehau BGE_RDMA_RSRVCTRL_TXMRGN_320B; 16606c8d8eccSSepherosa Ziehau } 16616c8d8eccSSepherosa Ziehau /* 16626c8d8eccSSepherosa Ziehau * Enable fix for read DMA FIFO overruns. 16636c8d8eccSSepherosa Ziehau * The fix is to limit the number of RX BDs 16646c8d8eccSSepherosa Ziehau * the hardware would fetch at a fime. 16656c8d8eccSSepherosa Ziehau */ 1666b96cbbb6SSepherosa Ziehau CSR_WRITE_4(sc, dmactl_reg, 16676c8d8eccSSepherosa Ziehau dmactl | BGE_RDMA_RSRVCTRL_FIFO_OFLW_FIX); 16686c8d8eccSSepherosa Ziehau } 16696c8d8eccSSepherosa Ziehau 16706c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719) { 16716c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL, 16726c8d8eccSSepherosa Ziehau CSR_READ_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL) | 16736c8d8eccSSepherosa Ziehau BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_BD_4K | 16746c8d8eccSSepherosa Ziehau BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_LSO_4K); 1675b96cbbb6SSepherosa Ziehau } else if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 1676b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 1677b96cbbb6SSepherosa Ziehau uint32_t ctrl_reg; 1678b96cbbb6SSepherosa Ziehau 1679b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5762) 1680b96cbbb6SSepherosa Ziehau ctrl_reg = BGE_RDMA_LSO_CRPTEN_CTRL2; 1681b96cbbb6SSepherosa Ziehau else 1682b96cbbb6SSepherosa Ziehau ctrl_reg = BGE_RDMA_LSO_CRPTEN_CTRL; 1683b96cbbb6SSepherosa Ziehau 16846c8d8eccSSepherosa Ziehau /* 16856c8d8eccSSepherosa Ziehau * Allow 4KB burst length reads for non-LSO frames. 16866c8d8eccSSepherosa Ziehau * Enable 512B burst length reads for buffer descriptors. 16876c8d8eccSSepherosa Ziehau */ 1688b96cbbb6SSepherosa Ziehau CSR_WRITE_4(sc, ctrl_reg, 1689b96cbbb6SSepherosa Ziehau CSR_READ_4(sc, ctrl_reg) | 16906c8d8eccSSepherosa Ziehau BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_BD_512 | 16916c8d8eccSSepherosa Ziehau BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_LSO_4K); 16926c8d8eccSSepherosa Ziehau } 16936c8d8eccSSepherosa Ziehau 16946c8d8eccSSepherosa Ziehau /* Turn on read DMA state machine */ 16956c8d8eccSSepherosa Ziehau val = BGE_RDMAMODE_ENABLE | BGE_RDMAMODE_ALL_ATTNS; 16966c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5717) 16976c8d8eccSSepherosa Ziehau val |= BGE_RDMAMODE_MULT_DMA_RD_DIS; 16986c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5784 || 16996c8d8eccSSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5785 || 17006c8d8eccSSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM57780) { 17016c8d8eccSSepherosa Ziehau val |= BGE_RDMAMODE_BD_SBD_CRPT_ATTN | 17026c8d8eccSSepherosa Ziehau BGE_RDMAMODE_MBUF_RBD_CRPT_ATTN | 17036c8d8eccSSepherosa Ziehau BGE_RDMAMODE_MBUF_SBD_CRPT_ATTN; 17046c8d8eccSSepherosa Ziehau } 1705b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 1706b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 17076c8d8eccSSepherosa Ziehau val |= CSR_READ_4(sc, BGE_RDMA_MODE) & 17086c8d8eccSSepherosa Ziehau BGE_RDMAMODE_H2BNC_VLAN_DET; 17096c8d8eccSSepherosa Ziehau /* 17106c8d8eccSSepherosa Ziehau * Allow multiple outstanding read requests from 17116c8d8eccSSepherosa Ziehau * non-LSO read DMA engine. 17126c8d8eccSSepherosa Ziehau */ 17136c8d8eccSSepherosa Ziehau val &= ~BGE_RDMAMODE_MULT_DMA_RD_DIS; 17146c8d8eccSSepherosa Ziehau } 171560e67e3fSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM57766) 171660e67e3fSSepherosa Ziehau val |= BGE_RDMAMODE_JMB_2K_MMRR; 171766deb1c1SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TSO) 171866deb1c1SSepherosa Ziehau val |= BGE_RDMAMODE_TSO4_ENABLE; 17196c8d8eccSSepherosa Ziehau val |= BGE_RDMAMODE_FIFO_LONG_BURST; 17206c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RDMA_MODE, val); 17216c8d8eccSSepherosa Ziehau DELAY(40); 17226c8d8eccSSepherosa Ziehau 17236c8d8eccSSepherosa Ziehau /* Turn on RX data completion state machine */ 17246c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RDC_MODE, BGE_RDCMODE_ENABLE); 17256c8d8eccSSepherosa Ziehau 17266c8d8eccSSepherosa Ziehau /* Turn on RX BD initiator state machine */ 17276c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RBDI_MODE, BGE_RBDIMODE_ENABLE); 17286c8d8eccSSepherosa Ziehau 17296c8d8eccSSepherosa Ziehau /* Turn on RX data and RX BD initiator state machine */ 17306c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RDBDI_MODE, BGE_RDBDIMODE_ENABLE); 17316c8d8eccSSepherosa Ziehau 17326c8d8eccSSepherosa Ziehau /* Turn on send BD completion state machine */ 17336c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SBDC_MODE, BGE_SBDCMODE_ENABLE); 17346c8d8eccSSepherosa Ziehau 17356c8d8eccSSepherosa Ziehau /* Turn on send data completion state machine */ 17366c8d8eccSSepherosa Ziehau val = BGE_SDCMODE_ENABLE; 17376c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5761) 17386c8d8eccSSepherosa Ziehau val |= BGE_SDCMODE_CDELAY; 17396c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDC_MODE, val); 17406c8d8eccSSepherosa Ziehau 17416c8d8eccSSepherosa Ziehau /* Turn on send data initiator state machine */ 174266deb1c1SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TSO) { 174366deb1c1SSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE | 174466deb1c1SSepherosa Ziehau BGE_SDIMODE_HW_LSO_PRE_DMA); 174566deb1c1SSepherosa Ziehau } else { 17466c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE); 174766deb1c1SSepherosa Ziehau } 17486c8d8eccSSepherosa Ziehau 17496c8d8eccSSepherosa Ziehau /* Turn on send BD initiator state machine */ 1750695a8586SSepherosa Ziehau val = BGE_SBDIMODE_ENABLE; 1751695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt > 1) 1752695a8586SSepherosa Ziehau val |= BGE_SBDIMODE_MULTI_TXR; 1753695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_SBDI_MODE, val); 17546c8d8eccSSepherosa Ziehau 17556c8d8eccSSepherosa Ziehau /* Turn on send BD selector state machine */ 17566c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SRS_MODE, BGE_SRSMODE_ENABLE); 17576c8d8eccSSepherosa Ziehau 17586c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDI_STATS_ENABLE_MASK, 0x007FFFFF); 17596c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SDI_STATS_CTL, 17606c8d8eccSSepherosa Ziehau BGE_SDISTATSCTL_ENABLE|BGE_SDISTATSCTL_FASTER); 17616c8d8eccSSepherosa Ziehau 17626c8d8eccSSepherosa Ziehau /* ack/clear link change events */ 17636c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED| 17646c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED|BGE_MACSTAT_MI_COMPLETE| 17656c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 17666c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_STS, 0); 17676c8d8eccSSepherosa Ziehau 17686c8d8eccSSepherosa Ziehau /* 17696c8d8eccSSepherosa Ziehau * Enable attention when the link has changed state for 17706c8d8eccSSepherosa Ziehau * devices that use auto polling. 17716c8d8eccSSepherosa Ziehau */ 17726c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 17736c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_STS, BGE_MISTS_LINK); 17746c8d8eccSSepherosa Ziehau } else { 17756c8d8eccSSepherosa Ziehau if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 17766c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, sc->bnx_mi_mode); 17776c8d8eccSSepherosa Ziehau DELAY(80); 17786c8d8eccSSepherosa Ziehau } 17796c8d8eccSSepherosa Ziehau } 17806c8d8eccSSepherosa Ziehau 17816c8d8eccSSepherosa Ziehau /* 17826c8d8eccSSepherosa Ziehau * Clear any pending link state attention. 17836c8d8eccSSepherosa Ziehau * Otherwise some link state change events may be lost until attention 17846c8d8eccSSepherosa Ziehau * is cleared by bnx_intr() -> bnx_softc.bnx_link_upd() sequence. 17856c8d8eccSSepherosa Ziehau * It's not necessary on newer BCM chips - perhaps enabling link 17866c8d8eccSSepherosa Ziehau * state change attentions implies clearing pending attention. 17876c8d8eccSSepherosa Ziehau */ 17886c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED| 17896c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED|BGE_MACSTAT_MI_COMPLETE| 17906c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 17916c8d8eccSSepherosa Ziehau 17926c8d8eccSSepherosa Ziehau /* Enable link state change attentions. */ 17936c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MAC_EVT_ENB, BGE_EVTENB_LINK_CHANGED); 17946c8d8eccSSepherosa Ziehau 17956c8d8eccSSepherosa Ziehau return(0); 17966c8d8eccSSepherosa Ziehau } 17976c8d8eccSSepherosa Ziehau 17986c8d8eccSSepherosa Ziehau /* 17996c8d8eccSSepherosa Ziehau * Probe for a Broadcom chip. Check the PCI vendor and device IDs 18006c8d8eccSSepherosa Ziehau * against our list and return its name if we find a match. Note 18016c8d8eccSSepherosa Ziehau * that since the Broadcom controller contains VPD support, we 18026c8d8eccSSepherosa Ziehau * can get the device name string from the controller itself instead 18036c8d8eccSSepherosa Ziehau * of the compiled-in string. This is a little slow, but it guarantees 18046c8d8eccSSepherosa Ziehau * we'll always announce the right product name. 18056c8d8eccSSepherosa Ziehau */ 18066c8d8eccSSepherosa Ziehau static int 18076c8d8eccSSepherosa Ziehau bnx_probe(device_t dev) 18086c8d8eccSSepherosa Ziehau { 18096c8d8eccSSepherosa Ziehau const struct bnx_type *t; 18106c8d8eccSSepherosa Ziehau uint16_t product, vendor; 18116c8d8eccSSepherosa Ziehau 18126c8d8eccSSepherosa Ziehau if (!pci_is_pcie(dev)) 18136c8d8eccSSepherosa Ziehau return ENXIO; 18146c8d8eccSSepherosa Ziehau 18156c8d8eccSSepherosa Ziehau product = pci_get_device(dev); 18166c8d8eccSSepherosa Ziehau vendor = pci_get_vendor(dev); 18176c8d8eccSSepherosa Ziehau 18186c8d8eccSSepherosa Ziehau for (t = bnx_devs; t->bnx_name != NULL; t++) { 18196c8d8eccSSepherosa Ziehau if (vendor == t->bnx_vid && product == t->bnx_did) 18206c8d8eccSSepherosa Ziehau break; 18216c8d8eccSSepherosa Ziehau } 18226c8d8eccSSepherosa Ziehau if (t->bnx_name == NULL) 18236c8d8eccSSepherosa Ziehau return ENXIO; 18246c8d8eccSSepherosa Ziehau 18256c8d8eccSSepherosa Ziehau device_set_desc(dev, t->bnx_name); 18266c8d8eccSSepherosa Ziehau return 0; 18276c8d8eccSSepherosa Ziehau } 18286c8d8eccSSepherosa Ziehau 18296c8d8eccSSepherosa Ziehau static int 18306c8d8eccSSepherosa Ziehau bnx_attach(device_t dev) 18316c8d8eccSSepherosa Ziehau { 18326c8d8eccSSepherosa Ziehau struct ifnet *ifp; 18336c8d8eccSSepherosa Ziehau struct bnx_softc *sc; 1834841cdf08SSepherosa Ziehau struct bnx_rx_std_ring *std; 183526595b18SSascha Wildner struct sysctl_ctx_list *ctx; 183626595b18SSascha Wildner struct sysctl_oid_list *tree; 1837e594b5c4SSepherosa Ziehau uint32_t hwcfg = 0; 1838841cdf08SSepherosa Ziehau int error = 0, rid, capmask, i, std_cpuid, std_cpuid_def; 18396c8d8eccSSepherosa Ziehau uint8_t ether_addr[ETHER_ADDR_LEN]; 184007e9f7c0SSascha Wildner uint16_t product; 18416c8d8eccSSepherosa Ziehau uintptr_t mii_priv = 0; 1842695a8586SSepherosa Ziehau #if defined(BNX_TSO_DEBUG) || defined(BNX_RSS_DEBUG) || defined(BNX_TSS_DEBUG) 184366deb1c1SSepherosa Ziehau char desc[32]; 184466deb1c1SSepherosa Ziehau #endif 18456c8d8eccSSepherosa Ziehau 18466c8d8eccSSepherosa Ziehau sc = device_get_softc(dev); 18476c8d8eccSSepherosa Ziehau sc->bnx_dev = dev; 18487dbaa833SSepherosa Ziehau callout_init_mp(&sc->bnx_tick_timer); 18496c8d8eccSSepherosa Ziehau lwkt_serialize_init(&sc->bnx_jslot_serializer); 1850f33ac8a4SSepherosa Ziehau lwkt_serialize_init(&sc->bnx_main_serialize); 18516c8d8eccSSepherosa Ziehau 1852695a8586SSepherosa Ziehau /* Always setup interrupt mailboxes */ 1853695a8586SSepherosa Ziehau for (i = 0; i < BNX_INTR_MAX; ++i) { 1854695a8586SSepherosa Ziehau callout_init_mp(&sc->bnx_intr_data[i].bnx_intr_timer); 1855695a8586SSepherosa Ziehau sc->bnx_intr_data[i].bnx_sc = sc; 1856695a8586SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_mbx = BGE_MBX_IRQ0_LO + (i * 8); 1857695a8586SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_rid = -1; 1858695a8586SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_cpuid = -1; 1859695a8586SSepherosa Ziehau } 1860695a8586SSepherosa Ziehau 18619f5082d5SSepherosa Ziehau sc->bnx_func_addr = pci_get_function(dev); 18626c8d8eccSSepherosa Ziehau product = pci_get_device(dev); 18636c8d8eccSSepherosa Ziehau 18646c8d8eccSSepherosa Ziehau #ifndef BURN_BRIDGES 18656c8d8eccSSepherosa Ziehau if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 18666c8d8eccSSepherosa Ziehau uint32_t irq, mem; 18676c8d8eccSSepherosa Ziehau 18686c8d8eccSSepherosa Ziehau irq = pci_read_config(dev, PCIR_INTLINE, 4); 18696c8d8eccSSepherosa Ziehau mem = pci_read_config(dev, BGE_PCI_BAR0, 4); 18706c8d8eccSSepherosa Ziehau 18716c8d8eccSSepherosa Ziehau device_printf(dev, "chip is in D%d power mode " 18726c8d8eccSSepherosa Ziehau "-- setting to D0\n", pci_get_powerstate(dev)); 18736c8d8eccSSepherosa Ziehau 18746c8d8eccSSepherosa Ziehau pci_set_powerstate(dev, PCI_POWERSTATE_D0); 18756c8d8eccSSepherosa Ziehau 18766c8d8eccSSepherosa Ziehau pci_write_config(dev, PCIR_INTLINE, irq, 4); 18776c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_BAR0, mem, 4); 18786c8d8eccSSepherosa Ziehau } 18796c8d8eccSSepherosa Ziehau #endif /* !BURN_BRIDGE */ 18806c8d8eccSSepherosa Ziehau 18816c8d8eccSSepherosa Ziehau /* 18826c8d8eccSSepherosa Ziehau * Map control/status registers. 18836c8d8eccSSepherosa Ziehau */ 18846c8d8eccSSepherosa Ziehau pci_enable_busmaster(dev); 18856c8d8eccSSepherosa Ziehau 18866c8d8eccSSepherosa Ziehau rid = BGE_PCI_BAR0; 18876c8d8eccSSepherosa Ziehau sc->bnx_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 18886c8d8eccSSepherosa Ziehau RF_ACTIVE); 18896c8d8eccSSepherosa Ziehau 18906c8d8eccSSepherosa Ziehau if (sc->bnx_res == NULL) { 18916c8d8eccSSepherosa Ziehau device_printf(dev, "couldn't map memory\n"); 18926c8d8eccSSepherosa Ziehau return ENXIO; 18936c8d8eccSSepherosa Ziehau } 18946c8d8eccSSepherosa Ziehau 18956c8d8eccSSepherosa Ziehau sc->bnx_btag = rman_get_bustag(sc->bnx_res); 18966c8d8eccSSepherosa Ziehau sc->bnx_bhandle = rman_get_bushandle(sc->bnx_res); 18976c8d8eccSSepherosa Ziehau 18986c8d8eccSSepherosa Ziehau /* Save various chip information */ 18996c8d8eccSSepherosa Ziehau sc->bnx_chipid = 19006c8d8eccSSepherosa Ziehau pci_read_config(dev, BGE_PCI_MISC_CTL, 4) >> 19016c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_ASICREV_SHIFT; 19026c8d8eccSSepherosa Ziehau if (BGE_ASICREV(sc->bnx_chipid) == BGE_ASICREV_USE_PRODID_REG) { 19036c8d8eccSSepherosa Ziehau /* All chips having dedicated ASICREV register have CPMU */ 19046c8d8eccSSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_CPMU; 19056c8d8eccSSepherosa Ziehau 19066c8d8eccSSepherosa Ziehau switch (product) { 19076c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5717: 1908d79f5d8fSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5717C: 19096c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5718: 19106c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5719: 19116c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5720_ALT: 1912b96cbbb6SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5725: 1913b96cbbb6SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5727: 1914b96cbbb6SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM5762: 19156c8d8eccSSepherosa Ziehau sc->bnx_chipid = pci_read_config(dev, 19166c8d8eccSSepherosa Ziehau BGE_PCI_GEN2_PRODID_ASICREV, 4); 19176c8d8eccSSepherosa Ziehau break; 19186c8d8eccSSepherosa Ziehau 19196c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57761: 192032ff3c80SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57762: 19216c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57765: 192232ff3c80SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57766: 19236c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57781: 192432ff3c80SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57782: 19256c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57785: 192632ff3c80SSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57786: 19276c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57791: 19286c8d8eccSSepherosa Ziehau case PCI_PRODUCT_BROADCOM_BCM57795: 19296c8d8eccSSepherosa Ziehau sc->bnx_chipid = pci_read_config(dev, 19306c8d8eccSSepherosa Ziehau BGE_PCI_GEN15_PRODID_ASICREV, 4); 19316c8d8eccSSepherosa Ziehau break; 19326c8d8eccSSepherosa Ziehau 19336c8d8eccSSepherosa Ziehau default: 19346c8d8eccSSepherosa Ziehau sc->bnx_chipid = pci_read_config(dev, 19356c8d8eccSSepherosa Ziehau BGE_PCI_PRODID_ASICREV, 4); 19366c8d8eccSSepherosa Ziehau break; 19376c8d8eccSSepherosa Ziehau } 19386c8d8eccSSepherosa Ziehau } 1939d79f5d8fSSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM5717_C0) 1940d79f5d8fSSepherosa Ziehau sc->bnx_chipid = BGE_CHIPID_BCM5720_A0; 1941d79f5d8fSSepherosa Ziehau 19426c8d8eccSSepherosa Ziehau sc->bnx_asicrev = BGE_ASICREV(sc->bnx_chipid); 19436c8d8eccSSepherosa Ziehau sc->bnx_chiprev = BGE_CHIPREV(sc->bnx_chipid); 19446c8d8eccSSepherosa Ziehau 19456c8d8eccSSepherosa Ziehau switch (sc->bnx_asicrev) { 19466c8d8eccSSepherosa Ziehau case BGE_ASICREV_BCM5717: 19476c8d8eccSSepherosa Ziehau case BGE_ASICREV_BCM5719: 19486c8d8eccSSepherosa Ziehau case BGE_ASICREV_BCM5720: 1949f368d0d9SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_5717_PLUS | BNX_FLAG_57765_PLUS; 1950f368d0d9SSepherosa Ziehau break; 1951f368d0d9SSepherosa Ziehau 1952b96cbbb6SSepherosa Ziehau case BGE_ASICREV_BCM5762: 1953b96cbbb6SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_57765_PLUS; 1954b96cbbb6SSepherosa Ziehau break; 1955b96cbbb6SSepherosa Ziehau 19566c8d8eccSSepherosa Ziehau case BGE_ASICREV_BCM57765: 195732ff3c80SSepherosa Ziehau case BGE_ASICREV_BCM57766: 1958f368d0d9SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_57765_FAMILY | BNX_FLAG_57765_PLUS; 19596c8d8eccSSepherosa Ziehau break; 19606c8d8eccSSepherosa Ziehau } 19616c8d8eccSSepherosa Ziehau 19624aa71e73SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5717 || 19634aa71e73SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5719 || 19644aa71e73SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 19654aa71e73SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) 19664aa71e73SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_APE; 19674aa71e73SSepherosa Ziehau 196866deb1c1SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_TSO; 196966deb1c1SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719 && 197066deb1c1SSepherosa Ziehau sc->bnx_chipid == BGE_CHIPID_BCM5719_A0) 197166deb1c1SSepherosa Ziehau sc->bnx_flags &= ~BNX_FLAG_TSO; 197266deb1c1SSepherosa Ziehau 1973df9ccc98SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5717 || 1974df9ccc98SSepherosa Ziehau BNX_IS_57765_FAMILY(sc)) { 1975df9ccc98SSepherosa Ziehau /* 1976df9ccc98SSepherosa Ziehau * All BCM57785 and BCM5718 families chips have a bug that 1977df9ccc98SSepherosa Ziehau * under certain situation interrupt will not be enabled 197897ba8fc5SSepherosa Ziehau * even if status tag is written to interrupt mailbox. 1979df9ccc98SSepherosa Ziehau * 1980df9ccc98SSepherosa Ziehau * While BCM5719 and BCM5720 have a hardware workaround 1981df9ccc98SSepherosa Ziehau * which could fix the above bug. 1982df9ccc98SSepherosa Ziehau * See the comment near BGE_PCIDMARWCTL_TAGGED_STATUS_WA in 1983df9ccc98SSepherosa Ziehau * bnx_chipinit(). 1984df9ccc98SSepherosa Ziehau * 1985df9ccc98SSepherosa Ziehau * For the rest of the chips in these two families, we will 1986df9ccc98SSepherosa Ziehau * have to poll the status block at high rate (10ms currently) 1987df9ccc98SSepherosa Ziehau * to check whether the interrupt is hosed or not. 1988695a8586SSepherosa Ziehau * See bnx_check_intr_*() for details. 1989df9ccc98SSepherosa Ziehau */ 1990df9ccc98SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_STATUSTAG_BUG; 1991df9ccc98SSepherosa Ziehau } 1992df9ccc98SSepherosa Ziehau 19936c8d8eccSSepherosa Ziehau sc->bnx_pciecap = pci_get_pciecap_ptr(sc->bnx_dev); 19946c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719 || 19956c8d8eccSSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5720) 19966c8d8eccSSepherosa Ziehau pcie_set_max_readrq(dev, PCIEM_DEVCTL_MAX_READRQ_2048); 19976c8d8eccSSepherosa Ziehau else 19986c8d8eccSSepherosa Ziehau pcie_set_max_readrq(dev, PCIEM_DEVCTL_MAX_READRQ_4096); 19996c8d8eccSSepherosa Ziehau device_printf(dev, "CHIP ID 0x%08x; " 20006c8d8eccSSepherosa Ziehau "ASIC REV 0x%02x; CHIP REV 0x%02x\n", 20016c8d8eccSSepherosa Ziehau sc->bnx_chipid, sc->bnx_asicrev, sc->bnx_chiprev); 20026c8d8eccSSepherosa Ziehau 20036c8d8eccSSepherosa Ziehau /* 20046c8d8eccSSepherosa Ziehau * Set various PHY quirk flags. 20056c8d8eccSSepherosa Ziehau */ 20066c8d8eccSSepherosa Ziehau 20076c8d8eccSSepherosa Ziehau capmask = MII_CAPMASK_DEFAULT; 200846283a40SSepherosa Ziehau if (product == PCI_PRODUCT_BROADCOM_BCM57791 || 200946283a40SSepherosa Ziehau product == PCI_PRODUCT_BROADCOM_BCM57795) { 20106c8d8eccSSepherosa Ziehau /* 10/100 only */ 20116c8d8eccSSepherosa Ziehau capmask &= ~BMSR_EXTSTAT; 20126c8d8eccSSepherosa Ziehau } 20136c8d8eccSSepherosa Ziehau 20146c8d8eccSSepherosa Ziehau mii_priv |= BRGPHY_FLAG_WIRESPEED; 2015b96cbbb6SSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM5762_A0) 2016b96cbbb6SSepherosa Ziehau mii_priv |= BRGPHY_FLAG_5762_A0; 20176c8d8eccSSepherosa Ziehau 20189f5082d5SSepherosa Ziehau /* 20199f5082d5SSepherosa Ziehau * Chips with APE need BAR2 access for APE registers/memory. 20209f5082d5SSepherosa Ziehau */ 20219f5082d5SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_APE) { 20229f5082d5SSepherosa Ziehau uint32_t pcistate; 20239f5082d5SSepherosa Ziehau 20249f5082d5SSepherosa Ziehau rid = PCIR_BAR(2); 20259f5082d5SSepherosa Ziehau sc->bnx_res2 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 20269f5082d5SSepherosa Ziehau RF_ACTIVE); 20279f5082d5SSepherosa Ziehau if (sc->bnx_res2 == NULL) { 20289f5082d5SSepherosa Ziehau device_printf(dev, "couldn't map BAR2 memory\n"); 20299f5082d5SSepherosa Ziehau error = ENXIO; 20309f5082d5SSepherosa Ziehau goto fail; 20319f5082d5SSepherosa Ziehau } 20329f5082d5SSepherosa Ziehau 20339f5082d5SSepherosa Ziehau /* Enable APE register/memory access by host driver. */ 20349f5082d5SSepherosa Ziehau pcistate = pci_read_config(dev, BGE_PCI_PCISTATE, 4); 20359f5082d5SSepherosa Ziehau pcistate |= BGE_PCISTATE_ALLOW_APE_CTLSPC_WR | 20369f5082d5SSepherosa Ziehau BGE_PCISTATE_ALLOW_APE_SHMEM_WR | 20379f5082d5SSepherosa Ziehau BGE_PCISTATE_ALLOW_APE_PSPACE_WR; 20389f5082d5SSepherosa Ziehau pci_write_config(dev, BGE_PCI_PCISTATE, pcistate, 4); 20399f5082d5SSepherosa Ziehau 20409f5082d5SSepherosa Ziehau bnx_ape_lock_init(sc); 20419f5082d5SSepherosa Ziehau bnx_ape_read_fw_ver(sc); 20429f5082d5SSepherosa Ziehau } 20439f5082d5SSepherosa Ziehau 20446c8d8eccSSepherosa Ziehau /* Initialize if_name earlier, so if_printf could be used */ 20456c8d8eccSSepherosa Ziehau ifp = &sc->arpcom.ac_if; 20466c8d8eccSSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 20476c8d8eccSSepherosa Ziehau 20484aa71e73SSepherosa Ziehau /* 20494aa71e73SSepherosa Ziehau * Try to reset the chip. 20504aa71e73SSepherosa Ziehau */ 20514aa71e73SSepherosa Ziehau bnx_sig_pre_reset(sc, BNX_RESET_SHUTDOWN); 20526c8d8eccSSepherosa Ziehau bnx_reset(sc); 20534aa71e73SSepherosa Ziehau bnx_sig_post_reset(sc, BNX_RESET_SHUTDOWN); 20546c8d8eccSSepherosa Ziehau 20556c8d8eccSSepherosa Ziehau if (bnx_chipinit(sc)) { 20566c8d8eccSSepherosa Ziehau device_printf(dev, "chip initialization failed\n"); 20576c8d8eccSSepherosa Ziehau error = ENXIO; 20586c8d8eccSSepherosa Ziehau goto fail; 20596c8d8eccSSepherosa Ziehau } 20606c8d8eccSSepherosa Ziehau 20616c8d8eccSSepherosa Ziehau /* 20626c8d8eccSSepherosa Ziehau * Get station address 20636c8d8eccSSepherosa Ziehau */ 20646c8d8eccSSepherosa Ziehau error = bnx_get_eaddr(sc, ether_addr); 20656c8d8eccSSepherosa Ziehau if (error) { 20666c8d8eccSSepherosa Ziehau device_printf(dev, "failed to read station address\n"); 20676c8d8eccSSepherosa Ziehau goto fail; 20686c8d8eccSSepherosa Ziehau } 20696c8d8eccSSepherosa Ziehau 2070695a8586SSepherosa Ziehau /* Setup RX/TX and interrupt count */ 2071695a8586SSepherosa Ziehau bnx_setup_ring_cnt(sc); 207233a04907SSepherosa Ziehau 20734fa38985SSepherosa Ziehau if ((sc->bnx_rx_retcnt == 1 && sc->bnx_tx_ringcnt == 1) || 20744fa38985SSepherosa Ziehau (sc->bnx_rx_retcnt > 1 && sc->bnx_tx_ringcnt > 1)) { 20754fa38985SSepherosa Ziehau /* 20764fa38985SSepherosa Ziehau * The RX ring and the corresponding TX ring processing 20774fa38985SSepherosa Ziehau * should be on the same CPU, since they share the same 20784fa38985SSepherosa Ziehau * status block. 20794fa38985SSepherosa Ziehau */ 20804fa38985SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_RXTX_BUNDLE; 20814fa38985SSepherosa Ziehau if (bootverbose) 20824fa38985SSepherosa Ziehau device_printf(dev, "RX/TX bundle\n"); 2083695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt > 1) { 2084695a8586SSepherosa Ziehau /* 2085695a8586SSepherosa Ziehau * Multiple TX rings do not share status block 2086695a8586SSepherosa Ziehau * with link status, so link status will have 2087695a8586SSepherosa Ziehau * to save its own status_tag. 2088695a8586SSepherosa Ziehau */ 2089695a8586SSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_STATUS_HASTAG; 2090695a8586SSepherosa Ziehau if (bootverbose) 2091695a8586SSepherosa Ziehau device_printf(dev, "status needs tag\n"); 2092695a8586SSepherosa Ziehau } 20934fa38985SSepherosa Ziehau } else { 20944fa38985SSepherosa Ziehau KKASSERT(sc->bnx_rx_retcnt > 1 && sc->bnx_tx_ringcnt == 1); 2095695a8586SSepherosa Ziehau if (bootverbose) 2096695a8586SSepherosa Ziehau device_printf(dev, "RX/TX not bundled\n"); 20974fa38985SSepherosa Ziehau } 20984fa38985SSepherosa Ziehau 2099beedf5beSSepherosa Ziehau error = bnx_dma_alloc(dev); 21006c8d8eccSSepherosa Ziehau if (error) 21016c8d8eccSSepherosa Ziehau goto fail; 21026c8d8eccSSepherosa Ziehau 210316b32c4cSSepherosa Ziehau /* 210416b32c4cSSepherosa Ziehau * Allocate interrupt 210516b32c4cSSepherosa Ziehau */ 21060c7da01dSSepherosa Ziehau error = bnx_alloc_intr(sc); 21070c7da01dSSepherosa Ziehau if (error) 210816b32c4cSSepherosa Ziehau goto fail; 210916b32c4cSSepherosa Ziehau 2110329f9016SSepherosa Ziehau /* Setup serializers */ 2111329f9016SSepherosa Ziehau bnx_setup_serialize(sc); 2112329f9016SSepherosa Ziehau 21136c8d8eccSSepherosa Ziehau /* Set default tuneable values. */ 21146c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_ticks = BNX_RX_COAL_TICKS_DEF; 21156c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_ticks = BNX_TX_COAL_TICKS_DEF; 21166c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_bds = BNX_RX_COAL_BDS_DEF; 2117a86cc105SSepherosa Ziehau sc->bnx_rx_coal_bds_poll = sc->bnx_rx_ret_ring[0].bnx_rx_cntmax; 21186c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_bds = BNX_TX_COAL_BDS_DEF; 211927357d84SSepherosa Ziehau sc->bnx_tx_coal_bds_poll = BNX_TX_COAL_BDS_POLL_DEF; 2120306e5498SSepherosa Ziehau sc->bnx_rx_coal_bds_int = BNX_RX_COAL_BDS_INT_DEF; 2121306e5498SSepherosa Ziehau sc->bnx_tx_coal_bds_int = BNX_TX_COAL_BDS_INT_DEF; 21226c8d8eccSSepherosa Ziehau 21236c8d8eccSSepherosa Ziehau /* Set up ifnet structure */ 21246c8d8eccSSepherosa Ziehau ifp->if_softc = sc; 21256c8d8eccSSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 21266c8d8eccSSepherosa Ziehau ifp->if_ioctl = bnx_ioctl; 21276c8d8eccSSepherosa Ziehau ifp->if_start = bnx_start; 212839a8d43aSSepherosa Ziehau #ifdef IFPOLL_ENABLE 212939a8d43aSSepherosa Ziehau ifp->if_npoll = bnx_npoll; 21306c8d8eccSSepherosa Ziehau #endif 21316c8d8eccSSepherosa Ziehau ifp->if_init = bnx_init; 2132329f9016SSepherosa Ziehau ifp->if_serialize = bnx_serialize; 2133329f9016SSepherosa Ziehau ifp->if_deserialize = bnx_deserialize; 2134329f9016SSepherosa Ziehau ifp->if_tryserialize = bnx_tryserialize; 2135329f9016SSepherosa Ziehau #ifdef INVARIANTS 2136329f9016SSepherosa Ziehau ifp->if_serialize_assert = bnx_serialize_assert; 2137329f9016SSepherosa Ziehau #endif 21386c8d8eccSSepherosa Ziehau ifp->if_mtu = ETHERMTU; 21396c8d8eccSSepherosa Ziehau ifp->if_capabilities = IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 21406c8d8eccSSepherosa Ziehau 21416c8d8eccSSepherosa Ziehau ifp->if_capabilities |= IFCAP_HWCSUM; 21426c8d8eccSSepherosa Ziehau ifp->if_hwassist = BNX_CSUM_FEATURES; 214366deb1c1SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TSO) { 214466deb1c1SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO; 214566deb1c1SSepherosa Ziehau ifp->if_hwassist |= CSUM_TSO; 214666deb1c1SSepherosa Ziehau } 2147b19ddf7eSSepherosa Ziehau if (BNX_RSS_ENABLED(sc)) 2148b19ddf7eSSepherosa Ziehau ifp->if_capabilities |= IFCAP_RSS; 21496c8d8eccSSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 21506c8d8eccSSepherosa Ziehau 215114929979SSepherosa Ziehau ifp->if_nmbclusters = BGE_STD_RX_RING_CNT; 215214929979SSepherosa Ziehau 2153329f9016SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, BGE_TX_RING_CNT - 1); 2154329f9016SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 2155329f9016SSepherosa Ziehau ifq_set_subq_cnt(&ifp->if_snd, sc->bnx_tx_ringcnt); 2156329f9016SSepherosa Ziehau 2157695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt > 1) { 2158*6af7a1dcSSepherosa Ziehau ifp->if_mapsubq = ifq_mapsubq_modulo; 2159*6af7a1dcSSepherosa Ziehau ifq_set_subq_divisor(&ifp->if_snd, sc->bnx_tx_ringcnt); 2160695a8586SSepherosa Ziehau } 2161695a8586SSepherosa Ziehau 21626c8d8eccSSepherosa Ziehau /* 21636c8d8eccSSepherosa Ziehau * Figure out what sort of media we have by checking the 21646c8d8eccSSepherosa Ziehau * hardware config word in the first 32k of NIC internal memory, 21656c8d8eccSSepherosa Ziehau * or fall back to examining the EEPROM if necessary. 21666c8d8eccSSepherosa Ziehau * Note: on some BCM5700 cards, this value appears to be unset. 21676c8d8eccSSepherosa Ziehau * If that's the case, we have to rely on identifying the NIC 21686c8d8eccSSepherosa Ziehau * by its PCI subsystem ID, as we do below for the SysKonnect 21696c8d8eccSSepherosa Ziehau * SK-9D41. 21706c8d8eccSSepherosa Ziehau */ 21710551ac06SSepherosa Ziehau if (bnx_readmem_ind(sc, BGE_SRAM_DATA_SIG) == BGE_SRAM_DATA_SIG_MAGIC) { 21720551ac06SSepherosa Ziehau hwcfg = bnx_readmem_ind(sc, BGE_SRAM_DATA_CFG); 21736c8d8eccSSepherosa Ziehau } else { 21746c8d8eccSSepherosa Ziehau if (bnx_read_eeprom(sc, (caddr_t)&hwcfg, BGE_EE_HWCFG_OFFSET, 21756c8d8eccSSepherosa Ziehau sizeof(hwcfg))) { 21766c8d8eccSSepherosa Ziehau device_printf(dev, "failed to read EEPROM\n"); 21776c8d8eccSSepherosa Ziehau error = ENXIO; 21786c8d8eccSSepherosa Ziehau goto fail; 21796c8d8eccSSepherosa Ziehau } 21806c8d8eccSSepherosa Ziehau hwcfg = ntohl(hwcfg); 21816c8d8eccSSepherosa Ziehau } 21826c8d8eccSSepherosa Ziehau 21836c8d8eccSSepherosa Ziehau /* The SysKonnect SK-9D41 is a 1000baseSX card. */ 21846c8d8eccSSepherosa Ziehau if (pci_get_subvendor(dev) == PCI_PRODUCT_SCHNEIDERKOCH_SK_9D41 || 21856c8d8eccSSepherosa Ziehau (hwcfg & BGE_HWCFG_MEDIA) == BGE_MEDIA_FIBER) 21866c8d8eccSSepherosa Ziehau sc->bnx_flags |= BNX_FLAG_TBI; 21876c8d8eccSSepherosa Ziehau 21886c8d8eccSSepherosa Ziehau /* Setup MI MODE */ 21896c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_CPMU) 21906c8d8eccSSepherosa Ziehau sc->bnx_mi_mode = BGE_MIMODE_500KHZ_CONST; 21916c8d8eccSSepherosa Ziehau else 21926c8d8eccSSepherosa Ziehau sc->bnx_mi_mode = BGE_MIMODE_BASE; 21936c8d8eccSSepherosa Ziehau 21946c8d8eccSSepherosa Ziehau /* Setup link status update stuffs */ 21956c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 21966c8d8eccSSepherosa Ziehau sc->bnx_link_upd = bnx_tbi_link_upd; 21976c8d8eccSSepherosa Ziehau sc->bnx_link_chg = BGE_MACSTAT_LINK_CHANGED; 21986c8d8eccSSepherosa Ziehau } else if (sc->bnx_mi_mode & BGE_MIMODE_AUTOPOLL) { 21996c8d8eccSSepherosa Ziehau sc->bnx_link_upd = bnx_autopoll_link_upd; 22006c8d8eccSSepherosa Ziehau sc->bnx_link_chg = BGE_MACSTAT_LINK_CHANGED; 22016c8d8eccSSepherosa Ziehau } else { 22026c8d8eccSSepherosa Ziehau sc->bnx_link_upd = bnx_copper_link_upd; 22036c8d8eccSSepherosa Ziehau sc->bnx_link_chg = BGE_MACSTAT_LINK_CHANGED; 22046c8d8eccSSepherosa Ziehau } 22056c8d8eccSSepherosa Ziehau 22066c8d8eccSSepherosa Ziehau /* Set default PHY address */ 22076c8d8eccSSepherosa Ziehau sc->bnx_phyno = 1; 22086c8d8eccSSepherosa Ziehau 22096c8d8eccSSepherosa Ziehau /* 22106c8d8eccSSepherosa Ziehau * PHY address mapping for various devices. 22116c8d8eccSSepherosa Ziehau * 22126c8d8eccSSepherosa Ziehau * | F0 Cu | F0 Sr | F1 Cu | F1 Sr | 22136c8d8eccSSepherosa Ziehau * ---------+-------+-------+-------+-------+ 22146c8d8eccSSepherosa Ziehau * BCM57XX | 1 | X | X | X | 22156c8d8eccSSepherosa Ziehau * BCM5717 | 1 | 8 | 2 | 9 | 22166c8d8eccSSepherosa Ziehau * BCM5719 | 1 | 8 | 2 | 9 | 22176c8d8eccSSepherosa Ziehau * BCM5720 | 1 | 8 | 2 | 9 | 22186c8d8eccSSepherosa Ziehau * 22199f5082d5SSepherosa Ziehau * | F2 Cu | F2 Sr | F3 Cu | F3 Sr | 22209f5082d5SSepherosa Ziehau * ---------+-------+-------+-------+-------+ 22219f5082d5SSepherosa Ziehau * BCM57XX | X | X | X | X | 22229f5082d5SSepherosa Ziehau * BCM5717 | X | X | X | X | 22239f5082d5SSepherosa Ziehau * BCM5719 | 3 | 10 | 4 | 11 | 22249f5082d5SSepherosa Ziehau * BCM5720 | X | X | X | X | 22259f5082d5SSepherosa Ziehau * 22266c8d8eccSSepherosa Ziehau * Other addresses may respond but they are not 22276c8d8eccSSepherosa Ziehau * IEEE compliant PHYs and should be ignored. 22286c8d8eccSSepherosa Ziehau */ 222980969639SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) { 22306c8d8eccSSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM5717_A0) { 22316c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_SGDIG_STS) & 22326c8d8eccSSepherosa Ziehau BGE_SGDIGSTS_IS_SERDES) 22339f5082d5SSepherosa Ziehau sc->bnx_phyno = sc->bnx_func_addr + 8; 22346c8d8eccSSepherosa Ziehau else 22359f5082d5SSepherosa Ziehau sc->bnx_phyno = sc->bnx_func_addr + 1; 22366c8d8eccSSepherosa Ziehau } else { 22376c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_CPMU_PHY_STRAP) & 22386c8d8eccSSepherosa Ziehau BGE_CPMU_PHY_STRAP_IS_SERDES) 22399f5082d5SSepherosa Ziehau sc->bnx_phyno = sc->bnx_func_addr + 8; 22406c8d8eccSSepherosa Ziehau else 22419f5082d5SSepherosa Ziehau sc->bnx_phyno = sc->bnx_func_addr + 1; 22426c8d8eccSSepherosa Ziehau } 22436c8d8eccSSepherosa Ziehau } 22446c8d8eccSSepherosa Ziehau 22456c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 22466c8d8eccSSepherosa Ziehau ifmedia_init(&sc->bnx_ifmedia, IFM_IMASK, 22476c8d8eccSSepherosa Ziehau bnx_ifmedia_upd, bnx_ifmedia_sts); 22486c8d8eccSSepherosa Ziehau ifmedia_add(&sc->bnx_ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL); 22496c8d8eccSSepherosa Ziehau ifmedia_add(&sc->bnx_ifmedia, 22506c8d8eccSSepherosa Ziehau IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL); 22516c8d8eccSSepherosa Ziehau ifmedia_add(&sc->bnx_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 22526c8d8eccSSepherosa Ziehau ifmedia_set(&sc->bnx_ifmedia, IFM_ETHER|IFM_AUTO); 22536c8d8eccSSepherosa Ziehau sc->bnx_ifmedia.ifm_media = sc->bnx_ifmedia.ifm_cur->ifm_media; 22546c8d8eccSSepherosa Ziehau } else { 22556c8d8eccSSepherosa Ziehau struct mii_probe_args mii_args; 22566c8d8eccSSepherosa Ziehau 22576c8d8eccSSepherosa Ziehau mii_probe_args_init(&mii_args, bnx_ifmedia_upd, bnx_ifmedia_sts); 22586c8d8eccSSepherosa Ziehau mii_args.mii_probemask = 1 << sc->bnx_phyno; 22596c8d8eccSSepherosa Ziehau mii_args.mii_capmask = capmask; 22606c8d8eccSSepherosa Ziehau mii_args.mii_privtag = MII_PRIVTAG_BRGPHY; 22616c8d8eccSSepherosa Ziehau mii_args.mii_priv = mii_priv; 22626c8d8eccSSepherosa Ziehau 22636c8d8eccSSepherosa Ziehau error = mii_probe(dev, &sc->bnx_miibus, &mii_args); 22646c8d8eccSSepherosa Ziehau if (error) { 22656c8d8eccSSepherosa Ziehau device_printf(dev, "MII without any PHY!\n"); 22666c8d8eccSSepherosa Ziehau goto fail; 22676c8d8eccSSepherosa Ziehau } 22686c8d8eccSSepherosa Ziehau } 22696c8d8eccSSepherosa Ziehau 227026595b18SSascha Wildner ctx = device_get_sysctl_ctx(sc->bnx_dev); 227126595b18SSascha Wildner tree = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bnx_dev)); 22726c8d8eccSSepherosa Ziehau 227326595b18SSascha Wildner SYSCTL_ADD_INT(ctx, tree, OID_AUTO, 227493146551SSepherosa Ziehau "rx_rings", CTLFLAG_RD, &sc->bnx_rx_retcnt, 0, "# of RX rings"); 227526595b18SSascha Wildner SYSCTL_ADD_INT(ctx, tree, OID_AUTO, 227693146551SSepherosa Ziehau "tx_rings", CTLFLAG_RD, &sc->bnx_tx_ringcnt, 0, "# of TX rings"); 227793146551SSepherosa Ziehau 227826595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "rx_coal_ticks", 22796c8d8eccSSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 22806c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_rx_coal_ticks, "I", 22816c8d8eccSSepherosa Ziehau "Receive coalescing ticks (usec)."); 228226595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tx_coal_ticks", 22836c8d8eccSSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 22846c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_tx_coal_ticks, "I", 22856c8d8eccSSepherosa Ziehau "Transmit coalescing ticks (usec)."); 228626595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "rx_coal_bds", 22876c8d8eccSSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 22886c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_rx_coal_bds, "I", 22896c8d8eccSSepherosa Ziehau "Receive max coalesced BD count."); 229026595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "rx_coal_bds_poll", 2291a86cc105SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 2292a86cc105SSepherosa Ziehau sc, 0, bnx_sysctl_rx_coal_bds_poll, "I", 2293a86cc105SSepherosa Ziehau "Receive max coalesced BD count in polling."); 229426595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tx_coal_bds", 22956c8d8eccSSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 22966c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_tx_coal_bds, "I", 22976c8d8eccSSepherosa Ziehau "Transmit max coalesced BD count."); 229826595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tx_coal_bds_poll", 229927357d84SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, 230027357d84SSepherosa Ziehau sc, 0, bnx_sysctl_tx_coal_bds_poll, "I", 230127357d84SSepherosa Ziehau "Transmit max coalesced BD count in polling."); 23026c8d8eccSSepherosa Ziehau /* 23036c8d8eccSSepherosa Ziehau * A common design characteristic for many Broadcom 23046c8d8eccSSepherosa Ziehau * client controllers is that they only support a 23056c8d8eccSSepherosa Ziehau * single outstanding DMA read operation on the PCIe 23066c8d8eccSSepherosa Ziehau * bus. This means that it will take twice as long to 23076c8d8eccSSepherosa Ziehau * fetch a TX frame that is split into header and 23086c8d8eccSSepherosa Ziehau * payload buffers as it does to fetch a single, 23096c8d8eccSSepherosa Ziehau * contiguous TX frame (2 reads vs. 1 read). For these 23106c8d8eccSSepherosa Ziehau * controllers, coalescing buffers to reduce the number 23116c8d8eccSSepherosa Ziehau * of memory reads is effective way to get maximum 23126c8d8eccSSepherosa Ziehau * performance(about 940Mbps). Without collapsing TX 23136c8d8eccSSepherosa Ziehau * buffers the maximum TCP bulk transfer performance 23146c8d8eccSSepherosa Ziehau * is about 850Mbps. However forcing coalescing mbufs 23156c8d8eccSSepherosa Ziehau * consumes a lot of CPU cycles, so leave it off by 23166c8d8eccSSepherosa Ziehau * default. 23176c8d8eccSSepherosa Ziehau */ 231826595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, 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 232326595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, 2324472c99c8SSepherosa Ziehau "tx_wreg", CTLTYPE_INT | CTLFLAG_RW, 2325472c99c8SSepherosa Ziehau sc, 0, bnx_sysctl_tx_wreg, "I", 2326c9b7f592SSepherosa Ziehau "# of segments before writing to hardware register"); 2327c9b7f592SSepherosa Ziehau 232826595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, 2329841cdf08SSepherosa Ziehau "std_refill", CTLTYPE_INT | CTLFLAG_RW, 2330841cdf08SSepherosa Ziehau sc, 0, bnx_sysctl_std_refill, "I", 2331841cdf08SSepherosa Ziehau "# of packets received before scheduling standard refilling"); 2332841cdf08SSepherosa Ziehau 233326595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, 23346c8d8eccSSepherosa Ziehau "rx_coal_bds_int", CTLTYPE_INT | CTLFLAG_RW, 23356c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_rx_coal_bds_int, "I", 23366c8d8eccSSepherosa Ziehau "Receive max coalesced BD count during interrupt."); 233726595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, 23386c8d8eccSSepherosa Ziehau "tx_coal_bds_int", CTLTYPE_INT | CTLFLAG_RW, 23396c8d8eccSSepherosa Ziehau sc, 0, bnx_sysctl_tx_coal_bds_int, "I", 23406c8d8eccSSepherosa Ziehau "Transmit max coalesced BD count during interrupt."); 23416c8d8eccSSepherosa Ziehau 234202596bedSSepherosa Ziehau if (sc->bnx_intr_type == PCI_INTR_TYPE_MSIX) { 234302596bedSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tx_cpumap", 234402596bedSSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RD, 234502596bedSSepherosa Ziehau sc->bnx_tx_rmap, 0, if_ringmap_cpumap_sysctl, "I", 234602596bedSSepherosa Ziehau "TX ring CPU map"); 234702596bedSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "rx_cpumap", 234802596bedSSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RD, 234902596bedSSepherosa Ziehau sc->bnx_rx_rmap, 0, if_ringmap_cpumap_sysctl, "I", 235002596bedSSepherosa Ziehau "RX ring CPU map"); 23514fa38985SSepherosa Ziehau } else { 235202596bedSSepherosa Ziehau #ifdef IFPOLL_ENABLE 235302596bedSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tx_poll_cpumap", 235402596bedSSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RD, 235502596bedSSepherosa Ziehau sc->bnx_tx_rmap, 0, if_ringmap_cpumap_sysctl, "I", 235602596bedSSepherosa Ziehau "TX poll CPU map"); 235702596bedSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "rx_poll_cpumap", 235802596bedSSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RD, 235902596bedSSepherosa Ziehau sc->bnx_rx_rmap, 0, if_ringmap_cpumap_sysctl, "I", 236002596bedSSepherosa Ziehau "RX poll CPU map"); 23614fa38985SSepherosa Ziehau #endif 236202596bedSSepherosa Ziehau } 23634fa38985SSepherosa Ziehau 2364695a8586SSepherosa Ziehau #ifdef BNX_RSS_DEBUG 236526595b18SSascha Wildner SYSCTL_ADD_INT(ctx, tree, OID_AUTO, 2366695a8586SSepherosa Ziehau "std_refill_mask", CTLFLAG_RD, 2367695a8586SSepherosa Ziehau &sc->bnx_rx_std_ring.bnx_rx_std_refill, 0, ""); 236826595b18SSascha Wildner SYSCTL_ADD_INT(ctx, tree, OID_AUTO, 2369625c3ba3SSepherosa Ziehau "std_used", CTLFLAG_RD, 2370625c3ba3SSepherosa Ziehau &sc->bnx_rx_std_ring.bnx_rx_std_used, 0, ""); 237126595b18SSascha Wildner SYSCTL_ADD_INT(ctx, tree, OID_AUTO, 2372695a8586SSepherosa Ziehau "rss_debug", CTLFLAG_RW, &sc->bnx_rss_debug, 0, ""); 2373695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 2374695a8586SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "rx_pkt%d", i); 237526595b18SSascha Wildner SYSCTL_ADD_ULONG(ctx, tree, OID_AUTO, 2376695a8586SSepherosa Ziehau desc, CTLFLAG_RW, &sc->bnx_rx_ret_ring[i].bnx_rx_pkt, ""); 2377625c3ba3SSepherosa Ziehau 2378625c3ba3SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "rx_force_sched%d", i); 237926595b18SSascha Wildner SYSCTL_ADD_ULONG(ctx, tree, OID_AUTO, 2380625c3ba3SSepherosa Ziehau desc, CTLFLAG_RW, 2381625c3ba3SSepherosa Ziehau &sc->bnx_rx_ret_ring[i].bnx_rx_force_sched, ""); 2382695a8586SSepherosa Ziehau } 2383695a8586SSepherosa Ziehau #endif 2384695a8586SSepherosa Ziehau #ifdef BNX_TSS_DEBUG 2385695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 2386695a8586SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "tx_pkt%d", i); 238726595b18SSascha Wildner SYSCTL_ADD_ULONG(ctx, tree, OID_AUTO, 2388695a8586SSepherosa Ziehau desc, CTLFLAG_RW, &sc->bnx_tx_ring[i].bnx_tx_pkt, ""); 2389695a8586SSepherosa Ziehau } 2390695a8586SSepherosa Ziehau #endif 2391695a8586SSepherosa Ziehau 239226595b18SSascha Wildner SYSCTL_ADD_ULONG(ctx, tree, OID_AUTO, 2393695a8586SSepherosa Ziehau "norxbds", CTLFLAG_RW, &sc->bnx_norxbds, ""); 2394695a8586SSepherosa Ziehau 239526595b18SSascha Wildner SYSCTL_ADD_ULONG(ctx, tree, OID_AUTO, 2396695a8586SSepherosa Ziehau "errors", CTLFLAG_RW, &sc->bnx_errors, ""); 2397695a8586SSepherosa Ziehau 239866deb1c1SSepherosa Ziehau #ifdef BNX_TSO_DEBUG 239966deb1c1SSepherosa Ziehau for (i = 0; i < BNX_TSO_NSTATS; ++i) { 240066deb1c1SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "tso%d", i + 1); 240126595b18SSascha Wildner SYSCTL_ADD_ULONG(ctx, tree, OID_AUTO, 240266deb1c1SSepherosa Ziehau desc, CTLFLAG_RW, &sc->bnx_tsosegs[i], ""); 240366deb1c1SSepherosa Ziehau } 240466deb1c1SSepherosa Ziehau #endif 240566deb1c1SSepherosa Ziehau 24066c8d8eccSSepherosa Ziehau /* 24076c8d8eccSSepherosa Ziehau * Call MI attach routine. 24086c8d8eccSSepherosa Ziehau */ 2409329f9016SSepherosa Ziehau ether_ifattach(ifp, ether_addr, NULL); 24106c8d8eccSSepherosa Ziehau 2411329f9016SSepherosa Ziehau /* Setup TX rings and subqueues */ 2412329f9016SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 2413329f9016SSepherosa Ziehau struct ifaltq_subque *ifsq = ifq_get_subq(&ifp->if_snd, i); 2414329f9016SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 2415329f9016SSepherosa Ziehau 2416329f9016SSepherosa Ziehau ifsq_set_cpuid(ifsq, txr->bnx_tx_cpuid); 2417329f9016SSepherosa Ziehau ifsq_set_hw_serialize(ifsq, &txr->bnx_tx_serialize); 2418329f9016SSepherosa Ziehau ifsq_set_priv(ifsq, txr); 24193397dea6SSepherosa Ziehau txr->bnx_ifsq = ifsq; 2420329f9016SSepherosa Ziehau 24213397dea6SSepherosa Ziehau ifsq_watchdog_init(&txr->bnx_tx_watchdog, ifsq, bnx_watchdog); 2422695a8586SSepherosa Ziehau 2423695a8586SSepherosa Ziehau if (bootverbose) { 2424695a8586SSepherosa Ziehau device_printf(dev, "txr %d -> cpu%d\n", i, 2425695a8586SSepherosa Ziehau txr->bnx_tx_cpuid); 2426695a8586SSepherosa Ziehau } 2427329f9016SSepherosa Ziehau } 24284c77af2dSSepherosa Ziehau 24290c7da01dSSepherosa Ziehau error = bnx_setup_intr(sc); 24306c8d8eccSSepherosa Ziehau if (error) { 24316c8d8eccSSepherosa Ziehau ether_ifdetach(ifp); 24326c8d8eccSSepherosa Ziehau goto fail; 24336c8d8eccSSepherosa Ziehau } 24347dbaa833SSepherosa Ziehau bnx_set_tick_cpuid(sc, FALSE); 24358ca0f604SSepherosa Ziehau 2436841cdf08SSepherosa Ziehau /* 2437841cdf08SSepherosa Ziehau * Create RX standard ring refilling thread 2438841cdf08SSepherosa Ziehau */ 243902596bedSSepherosa Ziehau std_cpuid_def = if_ringmap_cpumap(sc->bnx_rx_rmap, 0); 2440841cdf08SSepherosa Ziehau std_cpuid = device_getenv_int(dev, "std.cpuid", std_cpuid_def); 2441841cdf08SSepherosa Ziehau if (std_cpuid < 0 || std_cpuid >= ncpus) { 2442841cdf08SSepherosa Ziehau device_printf(dev, "invalid std.cpuid %d, use %d\n", 2443841cdf08SSepherosa Ziehau std_cpuid, std_cpuid_def); 2444841cdf08SSepherosa Ziehau std_cpuid = std_cpuid_def; 2445841cdf08SSepherosa Ziehau } 2446841cdf08SSepherosa Ziehau 2447841cdf08SSepherosa Ziehau std = &sc->bnx_rx_std_ring; 2448c450d4d8SSepherosa Ziehau lwkt_create(bnx_rx_std_refill_ithread, std, &std->bnx_rx_std_ithread, 2449c450d4d8SSepherosa Ziehau NULL, TDF_NOSTART | TDF_INTTHREAD, std_cpuid, 2450841cdf08SSepherosa Ziehau "%s std", device_get_nameunit(dev)); 2451c450d4d8SSepherosa Ziehau lwkt_setpri(std->bnx_rx_std_ithread, TDPRI_INT_MED); 2452c450d4d8SSepherosa Ziehau std->bnx_rx_std_ithread->td_preemptable = lwkt_preempt; 2453841cdf08SSepherosa Ziehau 24546c8d8eccSSepherosa Ziehau return(0); 24556c8d8eccSSepherosa Ziehau fail: 24566c8d8eccSSepherosa Ziehau bnx_detach(dev); 24576c8d8eccSSepherosa Ziehau return(error); 24586c8d8eccSSepherosa Ziehau } 24596c8d8eccSSepherosa Ziehau 24606c8d8eccSSepherosa Ziehau static int 24616c8d8eccSSepherosa Ziehau bnx_detach(device_t dev) 24626c8d8eccSSepherosa Ziehau { 24636c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 2464c450d4d8SSepherosa Ziehau struct bnx_rx_std_ring *std = &sc->bnx_rx_std_ring; 24656c8d8eccSSepherosa Ziehau 24666c8d8eccSSepherosa Ziehau if (device_is_attached(dev)) { 24676c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 24686c8d8eccSSepherosa Ziehau 2469329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 24706c8d8eccSSepherosa Ziehau bnx_stop(sc); 2471f33ac8a4SSepherosa Ziehau bnx_teardown_intr(sc, sc->bnx_intr_cnt); 2472329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 24736c8d8eccSSepherosa Ziehau 24746c8d8eccSSepherosa Ziehau ether_ifdetach(ifp); 24756c8d8eccSSepherosa Ziehau } 24766c8d8eccSSepherosa Ziehau 2477c450d4d8SSepherosa Ziehau if (std->bnx_rx_std_ithread != NULL) { 2478841cdf08SSepherosa Ziehau tsleep_interlock(std, 0); 2479695a8586SSepherosa Ziehau 2480c450d4d8SSepherosa Ziehau if (std->bnx_rx_std_ithread->td_gd == mycpu) { 2481695a8586SSepherosa Ziehau bnx_rx_std_refill_stop(std); 2482695a8586SSepherosa Ziehau } else { 2483c450d4d8SSepherosa Ziehau lwkt_send_ipiq(std->bnx_rx_std_ithread->td_gd, 2484695a8586SSepherosa Ziehau bnx_rx_std_refill_stop, std); 2485695a8586SSepherosa Ziehau } 2486695a8586SSepherosa Ziehau 2487841cdf08SSepherosa Ziehau tsleep(std, PINTERLOCKED, "bnx_detach", 0); 2488841cdf08SSepherosa Ziehau if (bootverbose) 2489841cdf08SSepherosa Ziehau device_printf(dev, "RX std ithread exited\n"); 2490695a8586SSepherosa Ziehau 2491695a8586SSepherosa Ziehau lwkt_synchronize_ipiqs("bnx_detach_ipiq"); 2492841cdf08SSepherosa Ziehau } 2493841cdf08SSepherosa Ziehau 24946c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) 24956c8d8eccSSepherosa Ziehau ifmedia_removeall(&sc->bnx_ifmedia); 24966c8d8eccSSepherosa Ziehau if (sc->bnx_miibus) 24976c8d8eccSSepherosa Ziehau device_delete_child(dev, sc->bnx_miibus); 24986c8d8eccSSepherosa Ziehau bus_generic_detach(dev); 24996c8d8eccSSepherosa Ziehau 25000c7da01dSSepherosa Ziehau bnx_free_intr(sc); 25016c8d8eccSSepherosa Ziehau 2502695a8586SSepherosa Ziehau if (sc->bnx_msix_mem_res != NULL) { 2503695a8586SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->bnx_msix_mem_rid, 2504695a8586SSepherosa Ziehau sc->bnx_msix_mem_res); 2505695a8586SSepherosa Ziehau } 25066c8d8eccSSepherosa Ziehau if (sc->bnx_res != NULL) { 25076c8d8eccSSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, 25086c8d8eccSSepherosa Ziehau BGE_PCI_BAR0, sc->bnx_res); 25096c8d8eccSSepherosa Ziehau } 25109f5082d5SSepherosa Ziehau if (sc->bnx_res2 != NULL) { 25119f5082d5SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, 25129f5082d5SSepherosa Ziehau PCIR_BAR(2), sc->bnx_res2); 25139f5082d5SSepherosa Ziehau } 25146c8d8eccSSepherosa Ziehau 25156c8d8eccSSepherosa Ziehau bnx_dma_free(sc); 25166c8d8eccSSepherosa Ziehau 2517329f9016SSepherosa Ziehau if (sc->bnx_serialize != NULL) 2518329f9016SSepherosa Ziehau kfree(sc->bnx_serialize, M_DEVBUF); 2519329f9016SSepherosa Ziehau 25206c8d8eccSSepherosa Ziehau return 0; 25216c8d8eccSSepherosa Ziehau } 25226c8d8eccSSepherosa Ziehau 25236c8d8eccSSepherosa Ziehau static void 25246c8d8eccSSepherosa Ziehau bnx_reset(struct bnx_softc *sc) 25256c8d8eccSSepherosa Ziehau { 25264aa71e73SSepherosa Ziehau device_t dev = sc->bnx_dev; 25274aa71e73SSepherosa Ziehau uint32_t cachesize, command, reset, mac_mode, mac_mode_mask; 25286c8d8eccSSepherosa Ziehau void (*write_op)(struct bnx_softc *, uint32_t, uint32_t); 25296c8d8eccSSepherosa Ziehau int i, val = 0; 25306c8d8eccSSepherosa Ziehau uint16_t devctl; 25316c8d8eccSSepherosa Ziehau 25324aa71e73SSepherosa Ziehau mac_mode_mask = BGE_MACMODE_HALF_DUPLEX | BGE_MACMODE_PORTMODE; 25339f5082d5SSepherosa Ziehau if (sc->bnx_mfw_flags & BNX_MFW_ON_APE) 25349f5082d5SSepherosa Ziehau mac_mode_mask |= BGE_MACMODE_APE_RX_EN | BGE_MACMODE_APE_TX_EN; 25354aa71e73SSepherosa Ziehau mac_mode = CSR_READ_4(sc, BGE_MAC_MODE) & mac_mode_mask; 25366c8d8eccSSepherosa Ziehau 25376c8d8eccSSepherosa Ziehau write_op = bnx_writemem_direct; 25386c8d8eccSSepherosa Ziehau 25399f5082d5SSepherosa Ziehau CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_SET1); 25409f5082d5SSepherosa Ziehau for (i = 0; i < 8000; i++) { 25419f5082d5SSepherosa Ziehau if (CSR_READ_4(sc, BGE_NVRAM_SWARB) & BGE_NVRAMSWARB_GNT1) 25429f5082d5SSepherosa Ziehau break; 25439f5082d5SSepherosa Ziehau DELAY(20); 25449f5082d5SSepherosa Ziehau } 25459f5082d5SSepherosa Ziehau if (i == 8000) 25469f5082d5SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "NVRAM lock timedout!\n"); 25479f5082d5SSepherosa Ziehau 25489f5082d5SSepherosa Ziehau /* Take APE lock when performing reset. */ 25499f5082d5SSepherosa Ziehau bnx_ape_lock(sc, BGE_APE_LOCK_GRC); 25509f5082d5SSepherosa Ziehau 25516c8d8eccSSepherosa Ziehau /* Save some important PCI state. */ 25526c8d8eccSSepherosa Ziehau cachesize = pci_read_config(dev, BGE_PCI_CACHESZ, 4); 25536c8d8eccSSepherosa Ziehau command = pci_read_config(dev, BGE_PCI_CMD, 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 25680551ac06SSepherosa Ziehau * write ~BGE_SRAM_FW_MB_MAGIC to the same location. 25696c8d8eccSSepherosa Ziehau */ 25700551ac06SSepherosa Ziehau bnx_writemem_ind(sc, BGE_SRAM_FW_MB, BGE_SRAM_FW_MB_MAGIC); 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 25994aa71e73SSepherosa Ziehau DELAY(100 * 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); 26364aa71e73SSepherosa Ziehau val = BGE_PCISTATE_ROM_ENABLE | BGE_PCISTATE_ROM_RETRY_ENABLE; 26379f5082d5SSepherosa Ziehau if (sc->bnx_mfw_flags & BNX_MFW_ON_APE) { 26389f5082d5SSepherosa Ziehau val |= BGE_PCISTATE_ALLOW_APE_CTLSPC_WR | 26399f5082d5SSepherosa Ziehau BGE_PCISTATE_ALLOW_APE_SHMEM_WR | 26409f5082d5SSepherosa Ziehau BGE_PCISTATE_ALLOW_APE_PSPACE_WR; 26419f5082d5SSepherosa Ziehau } 26424aa71e73SSepherosa Ziehau pci_write_config(dev, BGE_PCI_PCISTATE, val, 4); 26436c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_CACHESZ, cachesize, 4); 26446c8d8eccSSepherosa Ziehau pci_write_config(dev, BGE_PCI_CMD, command, 4); 26456c8d8eccSSepherosa Ziehau 26466c8d8eccSSepherosa Ziehau /* Enable memory arbiter */ 26476c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE); 26486c8d8eccSSepherosa Ziehau 26494aa71e73SSepherosa Ziehau /* Fix up byte swapping */ 26504aa71e73SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MODE_CTL, bnx_dma_swap_options(sc)); 26514aa71e73SSepherosa Ziehau 26524aa71e73SSepherosa Ziehau val = CSR_READ_4(sc, BGE_MAC_MODE); 26534aa71e73SSepherosa Ziehau val = (val & ~mac_mode_mask) | mac_mode; 26544aa71e73SSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_MODE, val); 26554aa71e73SSepherosa Ziehau DELAY(40); 26564aa71e73SSepherosa Ziehau 26579f5082d5SSepherosa Ziehau bnx_ape_unlock(sc, BGE_APE_LOCK_GRC); 26589f5082d5SSepherosa Ziehau 26596c8d8eccSSepherosa Ziehau /* 26606c8d8eccSSepherosa Ziehau * Poll until we see the 1's complement of the magic number. 2661ddd93a5cSSepherosa Ziehau * This indicates that the firmware initialization is complete. 26626c8d8eccSSepherosa Ziehau */ 26636c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_FIRMWARE_TIMEOUT; i++) { 26640551ac06SSepherosa Ziehau val = bnx_readmem_ind(sc, BGE_SRAM_FW_MB); 26650551ac06SSepherosa Ziehau if (val == ~BGE_SRAM_FW_MB_MAGIC) 26666c8d8eccSSepherosa Ziehau break; 26676c8d8eccSSepherosa Ziehau DELAY(10); 26686c8d8eccSSepherosa Ziehau } 26696c8d8eccSSepherosa Ziehau if (i == BNX_FIRMWARE_TIMEOUT) { 26706c8d8eccSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "firmware handshake " 26716c8d8eccSSepherosa Ziehau "timed out, found 0x%08x\n", val); 26726c8d8eccSSepherosa Ziehau } 26736c8d8eccSSepherosa Ziehau 26746c8d8eccSSepherosa Ziehau /* BCM57765 A0 needs additional time before accessing. */ 26756c8d8eccSSepherosa Ziehau if (sc->bnx_chipid == BGE_CHIPID_BCM57765_A0) 26766c8d8eccSSepherosa Ziehau DELAY(10 * 1000); 26776c8d8eccSSepherosa Ziehau 26786c8d8eccSSepherosa Ziehau /* 26796c8d8eccSSepherosa Ziehau * The 5704 in TBI mode apparently needs some special 26806c8d8eccSSepherosa Ziehau * adjustment to insure the SERDES drive level is set 26816c8d8eccSSepherosa Ziehau * to 1.2V. 26826c8d8eccSSepherosa Ziehau */ 26836c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5704 && 26846c8d8eccSSepherosa Ziehau (sc->bnx_flags & BNX_FLAG_TBI)) { 26856c8d8eccSSepherosa Ziehau uint32_t serdescfg; 26866c8d8eccSSepherosa Ziehau 26876c8d8eccSSepherosa Ziehau serdescfg = CSR_READ_4(sc, BGE_SERDES_CFG); 26886c8d8eccSSepherosa Ziehau serdescfg = (serdescfg & ~0xFFF) | 0x880; 26896c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_SERDES_CFG, serdescfg); 26906c8d8eccSSepherosa Ziehau } 26916c8d8eccSSepherosa Ziehau 26927892075dSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MI_MODE, 26937892075dSSepherosa Ziehau sc->bnx_mi_mode & ~BGE_MIMODE_AUTOPOLL); 26947892075dSSepherosa Ziehau DELAY(80); 26957892075dSSepherosa Ziehau 26966c8d8eccSSepherosa Ziehau /* XXX: Broadcom Linux driver. */ 26973730a14dSSepherosa Ziehau if (!BNX_IS_57765_PLUS(sc)) { 26986c8d8eccSSepherosa Ziehau uint32_t v; 26996c8d8eccSSepherosa Ziehau 27006c8d8eccSSepherosa Ziehau /* Enable Data FIFO protection. */ 2701f1f34fc4SSepherosa Ziehau v = CSR_READ_4(sc, BGE_PCIE_TLDLPL_PORT); 2702f1f34fc4SSepherosa Ziehau CSR_WRITE_4(sc, BGE_PCIE_TLDLPL_PORT, v | (1 << 25)); 27036c8d8eccSSepherosa Ziehau } 27046c8d8eccSSepherosa Ziehau 27056c8d8eccSSepherosa Ziehau DELAY(10000); 27066c8d8eccSSepherosa Ziehau 27076c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720) { 27086c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_CPMU_CLCK_ORIDE, 27096c8d8eccSSepherosa Ziehau CPMU_CLCK_ORIDE_MAC_ORIDE_EN); 27106c8d8eccSSepherosa Ziehau } 27116c8d8eccSSepherosa Ziehau } 27126c8d8eccSSepherosa Ziehau 27136c8d8eccSSepherosa Ziehau /* 27146c8d8eccSSepherosa Ziehau * Frame reception handling. This is called if there's a frame 27156c8d8eccSSepherosa Ziehau * on the receive return list. 27166c8d8eccSSepherosa Ziehau * 27176c8d8eccSSepherosa Ziehau * Note: we have to be able to handle two possibilities here: 27186c8d8eccSSepherosa Ziehau * 1) the frame is from the jumbo recieve ring 27196c8d8eccSSepherosa Ziehau * 2) the frame is from the standard receive ring 27206c8d8eccSSepherosa Ziehau */ 27216c8d8eccSSepherosa Ziehau 27226c8d8eccSSepherosa Ziehau static void 2723beedf5beSSepherosa Ziehau bnx_rxeof(struct bnx_rx_ret_ring *ret, uint16_t rx_prod, int count) 27246c8d8eccSSepherosa Ziehau { 2725beedf5beSSepherosa Ziehau struct bnx_softc *sc = ret->bnx_sc; 2726beedf5beSSepherosa Ziehau struct bnx_rx_std_ring *std = ret->bnx_std; 2727beedf5beSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2728ff37a356SSepherosa Ziehau int std_used = 0, cpuid = mycpuid; 27296c8d8eccSSepherosa Ziehau 2730beedf5beSSepherosa Ziehau while (ret->bnx_rx_saved_considx != rx_prod && count != 0) { 2731b19ddf7eSSepherosa Ziehau struct pktinfo pi0, *pi = NULL; 27326c8d8eccSSepherosa Ziehau struct bge_rx_bd *cur_rx; 2733841cdf08SSepherosa Ziehau struct bnx_rx_buf *rb; 27346c8d8eccSSepherosa Ziehau uint32_t rxidx; 27356c8d8eccSSepherosa Ziehau struct mbuf *m = NULL; 27366c8d8eccSSepherosa Ziehau uint16_t vlan_tag = 0; 27376c8d8eccSSepherosa Ziehau int have_tag = 0; 27386c8d8eccSSepherosa Ziehau 273997381780SSepherosa Ziehau --count; 274097381780SSepherosa Ziehau 2741beedf5beSSepherosa Ziehau cur_rx = &ret->bnx_rx_ret_ring[ret->bnx_rx_saved_considx]; 27426c8d8eccSSepherosa Ziehau 27436c8d8eccSSepherosa Ziehau rxidx = cur_rx->bge_idx; 2744695a8586SSepherosa Ziehau KKASSERT(rxidx < BGE_STD_RX_RING_CNT); 2745695a8586SSepherosa Ziehau 2746beedf5beSSepherosa Ziehau BNX_INC(ret->bnx_rx_saved_considx, BNX_RETURN_RING_CNT); 2747695a8586SSepherosa Ziehau #ifdef BNX_RSS_DEBUG 2748695a8586SSepherosa Ziehau ret->bnx_rx_pkt++; 2749695a8586SSepherosa Ziehau #endif 27506c8d8eccSSepherosa Ziehau 27516c8d8eccSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_VLAN_TAG) { 27526c8d8eccSSepherosa Ziehau have_tag = 1; 27536c8d8eccSSepherosa Ziehau vlan_tag = cur_rx->bge_vlan_tag; 27546c8d8eccSSepherosa Ziehau } 27556c8d8eccSSepherosa Ziehau 2756625c3ba3SSepherosa Ziehau if (ret->bnx_rx_cnt >= ret->bnx_rx_cntmax) { 2757625c3ba3SSepherosa Ziehau atomic_add_int(&std->bnx_rx_std_used, std_used); 2758625c3ba3SSepherosa Ziehau std_used = 0; 2759625c3ba3SSepherosa Ziehau 2760695a8586SSepherosa Ziehau bnx_rx_std_refill_sched(ret, std); 2761625c3ba3SSepherosa Ziehau } 2762841cdf08SSepherosa Ziehau ret->bnx_rx_cnt++; 2763625c3ba3SSepherosa Ziehau ++std_used; 27646c8d8eccSSepherosa Ziehau 2765841cdf08SSepherosa Ziehau rb = &std->bnx_rx_std_buf[rxidx]; 2766841cdf08SSepherosa Ziehau m = rb->bnx_rx_mbuf; 27676c8d8eccSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_ERROR) { 2768d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 2769841cdf08SSepherosa Ziehau cpu_sfence(); 2770841cdf08SSepherosa Ziehau rb->bnx_rx_refilled = 1; 27716c8d8eccSSepherosa Ziehau continue; 27726c8d8eccSSepherosa Ziehau } 2773841cdf08SSepherosa Ziehau if (bnx_newbuf_std(ret, rxidx, 0)) { 2774d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 27756c8d8eccSSepherosa Ziehau continue; 27766c8d8eccSSepherosa Ziehau } 27776c8d8eccSSepherosa Ziehau 2778d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 27796c8d8eccSSepherosa Ziehau m->m_pkthdr.len = m->m_len = cur_rx->bge_len - ETHER_CRC_LEN; 27806c8d8eccSSepherosa Ziehau m->m_pkthdr.rcvif = ifp; 27816c8d8eccSSepherosa Ziehau 27826c8d8eccSSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 27836c8d8eccSSepherosa Ziehau (cur_rx->bge_flags & BGE_RXBDFLAG_IPV6) == 0) { 27846c8d8eccSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_IP_CSUM) { 27856c8d8eccSSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 27866c8d8eccSSepherosa Ziehau if ((cur_rx->bge_error_flag & 27876c8d8eccSSepherosa Ziehau BGE_RXERRFLAG_IP_CSUM_NOK) == 0) 27886c8d8eccSSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 27896c8d8eccSSepherosa Ziehau } 27906c8d8eccSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_TCP_UDP_CSUM) { 27916c8d8eccSSepherosa Ziehau m->m_pkthdr.csum_data = 27926c8d8eccSSepherosa Ziehau cur_rx->bge_tcp_udp_csum; 27936c8d8eccSSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | 27946c8d8eccSSepherosa Ziehau CSUM_PSEUDO_HDR; 27956c8d8eccSSepherosa Ziehau } 27966c8d8eccSSepherosa Ziehau } 2797b19ddf7eSSepherosa Ziehau if (ifp->if_capenable & IFCAP_RSS) { 2798b19ddf7eSSepherosa Ziehau pi = bnx_rss_info(&pi0, cur_rx); 2799b19ddf7eSSepherosa Ziehau if (pi != NULL && 28007558541bSSepherosa Ziehau (cur_rx->bge_flags & BGE_RXBDFLAG_RSS_HASH)) 28017558541bSSepherosa Ziehau m_sethash(m, toeplitz_hash(cur_rx->bge_hash)); 2802b19ddf7eSSepherosa Ziehau } 28036c8d8eccSSepherosa Ziehau 28046c8d8eccSSepherosa Ziehau /* 28056c8d8eccSSepherosa Ziehau * If we received a packet with a vlan tag, pass it 28066c8d8eccSSepherosa Ziehau * to vlan_input() instead of ether_input(). 28076c8d8eccSSepherosa Ziehau */ 28086c8d8eccSSepherosa Ziehau if (have_tag) { 28096c8d8eccSSepherosa Ziehau m->m_flags |= M_VLANTAG; 28106c8d8eccSSepherosa Ziehau m->m_pkthdr.ether_vlantag = vlan_tag; 28116c8d8eccSSepherosa Ziehau } 2812be4134c6SFranco Fichtner ifp->if_input(ifp, m, pi, cpuid); 28136c8d8eccSSepherosa Ziehau } 2814ac2936fdSSepherosa Ziehau bnx_writembx(sc, ret->bnx_rx_mbx, ret->bnx_rx_saved_considx); 2815695a8586SSepherosa Ziehau 2816625c3ba3SSepherosa Ziehau if (std_used > 0) { 2817625c3ba3SSepherosa Ziehau int cur_std_used; 2818625c3ba3SSepherosa Ziehau 2819625c3ba3SSepherosa Ziehau cur_std_used = atomic_fetchadd_int(&std->bnx_rx_std_used, 2820625c3ba3SSepherosa Ziehau std_used); 2821625c3ba3SSepherosa Ziehau if (cur_std_used + std_used >= (BGE_STD_RX_RING_CNT / 2)) { 2822625c3ba3SSepherosa Ziehau #ifdef BNX_RSS_DEBUG 2823625c3ba3SSepherosa Ziehau ret->bnx_rx_force_sched++; 2824625c3ba3SSepherosa Ziehau #endif 2825695a8586SSepherosa Ziehau bnx_rx_std_refill_sched(ret, std); 28266c8d8eccSSepherosa Ziehau } 2827625c3ba3SSepherosa Ziehau } 2828625c3ba3SSepherosa Ziehau } 28296c8d8eccSSepherosa Ziehau 28306c8d8eccSSepherosa Ziehau static void 283133a04907SSepherosa Ziehau bnx_txeof(struct bnx_tx_ring *txr, uint16_t tx_cons) 28326c8d8eccSSepherosa Ziehau { 283333a04907SSepherosa Ziehau struct ifnet *ifp = &txr->bnx_sc->arpcom.ac_if; 28346c8d8eccSSepherosa Ziehau 28356c8d8eccSSepherosa Ziehau /* 28366c8d8eccSSepherosa Ziehau * Go through our tx ring and free mbufs for those 28376c8d8eccSSepherosa Ziehau * frames that have been sent. 28386c8d8eccSSepherosa Ziehau */ 283933a04907SSepherosa Ziehau while (txr->bnx_tx_saved_considx != tx_cons) { 2840fa4b1067SSepherosa Ziehau struct bnx_tx_buf *buf; 28416c8d8eccSSepherosa Ziehau uint32_t idx = 0; 28426c8d8eccSSepherosa Ziehau 284333a04907SSepherosa Ziehau idx = txr->bnx_tx_saved_considx; 2844fa4b1067SSepherosa Ziehau buf = &txr->bnx_tx_buf[idx]; 2845fa4b1067SSepherosa Ziehau if (buf->bnx_tx_mbuf != NULL) { 2846d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 2847695a8586SSepherosa Ziehau #ifdef BNX_TSS_DEBUG 2848695a8586SSepherosa Ziehau txr->bnx_tx_pkt++; 2849695a8586SSepherosa Ziehau #endif 285033a04907SSepherosa Ziehau bus_dmamap_unload(txr->bnx_tx_mtag, 2851fa4b1067SSepherosa Ziehau buf->bnx_tx_dmamap); 2852fa4b1067SSepherosa Ziehau m_freem(buf->bnx_tx_mbuf); 2853fa4b1067SSepherosa Ziehau buf->bnx_tx_mbuf = NULL; 28546c8d8eccSSepherosa Ziehau } 2855fa639b88SSepherosa Ziehau txr->bnx_tx_cnt--; 285633a04907SSepherosa Ziehau BNX_INC(txr->bnx_tx_saved_considx, BGE_TX_RING_CNT); 28576c8d8eccSSepherosa Ziehau } 28586c8d8eccSSepherosa Ziehau 2859fa639b88SSepherosa Ziehau if ((BGE_TX_RING_CNT - txr->bnx_tx_cnt) >= 28606c8d8eccSSepherosa Ziehau (BNX_NSEG_RSVD + BNX_NSEG_SPARE)) 28613397dea6SSepherosa Ziehau ifsq_clr_oactive(txr->bnx_ifsq); 28626c8d8eccSSepherosa Ziehau 2863fa639b88SSepherosa Ziehau if (txr->bnx_tx_cnt == 0) 28643397dea6SSepherosa Ziehau txr->bnx_tx_watchdog.wd_timer = 0; 28656c8d8eccSSepherosa Ziehau 28663397dea6SSepherosa Ziehau if (!ifsq_is_empty(txr->bnx_ifsq)) 28673397dea6SSepherosa Ziehau ifsq_devstart(txr->bnx_ifsq); 28686c8d8eccSSepherosa Ziehau } 28696c8d8eccSSepherosa Ziehau 287024e16e4bSSepherosa Ziehau static int 2871695a8586SSepherosa Ziehau bnx_handle_status(struct bnx_softc *sc) 2872695a8586SSepherosa Ziehau { 2873695a8586SSepherosa Ziehau uint32_t status; 287424e16e4bSSepherosa Ziehau int handle = 0; 2875695a8586SSepherosa Ziehau 2876695a8586SSepherosa Ziehau status = *sc->bnx_hw_status; 2877695a8586SSepherosa Ziehau 2878695a8586SSepherosa Ziehau if (status & BGE_STATFLAG_ERROR) { 2879695a8586SSepherosa Ziehau uint32_t val; 2880695a8586SSepherosa Ziehau int reset = 0; 2881695a8586SSepherosa Ziehau 2882695a8586SSepherosa Ziehau sc->bnx_errors++; 2883695a8586SSepherosa Ziehau 2884695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_FLOW_ATTN); 2885695a8586SSepherosa Ziehau if (val & ~BGE_FLOWATTN_MB_LOWAT) { 2886695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2887695a8586SSepherosa Ziehau "flow attn 0x%08x\n", val); 2888695a8586SSepherosa Ziehau reset = 1; 2889695a8586SSepherosa Ziehau } 2890695a8586SSepherosa Ziehau 2891695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_MSI_STATUS); 2892695a8586SSepherosa Ziehau if (val & ~BGE_MSISTAT_MSI_PCI_REQ) { 2893695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2894695a8586SSepherosa Ziehau "msi status 0x%08x\n", val); 2895695a8586SSepherosa Ziehau reset = 1; 2896695a8586SSepherosa Ziehau } 2897695a8586SSepherosa Ziehau 2898695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_RDMA_STATUS); 2899695a8586SSepherosa Ziehau if (val) { 2900695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2901695a8586SSepherosa Ziehau "rmda status 0x%08x\n", val); 2902695a8586SSepherosa Ziehau reset = 1; 2903695a8586SSepherosa Ziehau } 2904695a8586SSepherosa Ziehau 2905695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_WDMA_STATUS); 2906695a8586SSepherosa Ziehau if (val) { 2907695a8586SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2908695a8586SSepherosa Ziehau "wdma status 0x%08x\n", val); 2909695a8586SSepherosa Ziehau reset = 1; 2910695a8586SSepherosa Ziehau } 2911695a8586SSepherosa Ziehau 2912695a8586SSepherosa Ziehau if (reset) { 2913695a8586SSepherosa Ziehau bnx_serialize_skipmain(sc); 2914695a8586SSepherosa Ziehau bnx_init(sc); 2915695a8586SSepherosa Ziehau bnx_deserialize_skipmain(sc); 2916695a8586SSepherosa Ziehau } 291724e16e4bSSepherosa Ziehau handle = 1; 2918695a8586SSepherosa Ziehau } 2919695a8586SSepherosa Ziehau 292024e16e4bSSepherosa Ziehau if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) || sc->bnx_link_evt) { 292124e16e4bSSepherosa Ziehau if (bootverbose) { 292224e16e4bSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "link change, " 292324e16e4bSSepherosa Ziehau "link_evt %d\n", sc->bnx_link_evt); 292424e16e4bSSepherosa Ziehau } 2925695a8586SSepherosa Ziehau bnx_link_poll(sc); 292624e16e4bSSepherosa Ziehau handle = 1; 292724e16e4bSSepherosa Ziehau } 292824e16e4bSSepherosa Ziehau 292924e16e4bSSepherosa Ziehau return handle; 2930695a8586SSepherosa Ziehau } 2931695a8586SSepherosa Ziehau 293239a8d43aSSepherosa Ziehau #ifdef IFPOLL_ENABLE 29336c8d8eccSSepherosa Ziehau 29346c8d8eccSSepherosa Ziehau static void 29354fa38985SSepherosa Ziehau bnx_npoll_rx(struct ifnet *ifp __unused, void *xret, int cycle) 29364fa38985SSepherosa Ziehau { 29374fa38985SSepherosa Ziehau struct bnx_rx_ret_ring *ret = xret; 29384fa38985SSepherosa Ziehau uint16_t rx_prod; 29394fa38985SSepherosa Ziehau 29404fa38985SSepherosa Ziehau ASSERT_SERIALIZED(&ret->bnx_rx_ret_serialize); 29414fa38985SSepherosa Ziehau 29424fa38985SSepherosa Ziehau ret->bnx_saved_status_tag = *ret->bnx_hw_status_tag; 29434fa38985SSepherosa Ziehau cpu_lfence(); 29444fa38985SSepherosa Ziehau 29454fa38985SSepherosa Ziehau rx_prod = *ret->bnx_rx_considx; 29464fa38985SSepherosa Ziehau if (ret->bnx_rx_saved_considx != rx_prod) 29474fa38985SSepherosa Ziehau bnx_rxeof(ret, rx_prod, cycle); 29484fa38985SSepherosa Ziehau } 29494fa38985SSepherosa Ziehau 29504fa38985SSepherosa Ziehau static void 2951695a8586SSepherosa Ziehau bnx_npoll_tx_notag(struct ifnet *ifp __unused, void *xtxr, int cycle __unused) 29524fa38985SSepherosa Ziehau { 29534fa38985SSepherosa Ziehau struct bnx_tx_ring *txr = xtxr; 29544fa38985SSepherosa Ziehau uint16_t tx_cons; 29554fa38985SSepherosa Ziehau 29564fa38985SSepherosa Ziehau ASSERT_SERIALIZED(&txr->bnx_tx_serialize); 29574fa38985SSepherosa Ziehau 29584fa38985SSepherosa Ziehau tx_cons = *txr->bnx_tx_considx; 29594fa38985SSepherosa Ziehau if (txr->bnx_tx_saved_considx != tx_cons) 29604fa38985SSepherosa Ziehau bnx_txeof(txr, tx_cons); 29614fa38985SSepherosa Ziehau } 29624fa38985SSepherosa Ziehau 29634fa38985SSepherosa Ziehau static void 2964695a8586SSepherosa Ziehau bnx_npoll_tx(struct ifnet *ifp, void *xtxr, int cycle) 2965695a8586SSepherosa Ziehau { 2966695a8586SSepherosa Ziehau struct bnx_tx_ring *txr = xtxr; 2967695a8586SSepherosa Ziehau 2968695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&txr->bnx_tx_serialize); 2969695a8586SSepherosa Ziehau 2970695a8586SSepherosa Ziehau txr->bnx_saved_status_tag = *txr->bnx_hw_status_tag; 2971695a8586SSepherosa Ziehau cpu_lfence(); 2972695a8586SSepherosa Ziehau bnx_npoll_tx_notag(ifp, txr, cycle); 2973695a8586SSepherosa Ziehau } 2974695a8586SSepherosa Ziehau 2975695a8586SSepherosa Ziehau static void 2976695a8586SSepherosa Ziehau bnx_npoll_status_notag(struct ifnet *ifp) 29774fa38985SSepherosa Ziehau { 29784fa38985SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 29794fa38985SSepherosa Ziehau 29804fa38985SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 29814fa38985SSepherosa Ziehau 298224e16e4bSSepherosa Ziehau if (bnx_handle_status(sc)) { 298324e16e4bSSepherosa Ziehau /* 298424e16e4bSSepherosa Ziehau * Status changes are handled; force the chip to 298524e16e4bSSepherosa Ziehau * update the status block to reflect whether there 298624e16e4bSSepherosa Ziehau * are more status changes or not, else staled status 298724e16e4bSSepherosa Ziehau * changes are always seen. 298824e16e4bSSepherosa Ziehau */ 298924e16e4bSSepherosa Ziehau BNX_SETBIT(sc, BGE_HCC_MODE, BGE_HCCMODE_COAL_NOW); 299024e16e4bSSepherosa Ziehau } 2991695a8586SSepherosa Ziehau } 2992695a8586SSepherosa Ziehau 2993695a8586SSepherosa Ziehau static void 2994695a8586SSepherosa Ziehau bnx_npoll_status(struct ifnet *ifp) 2995695a8586SSepherosa Ziehau { 2996695a8586SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 2997695a8586SSepherosa Ziehau 2998695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 2999695a8586SSepherosa Ziehau 3000695a8586SSepherosa Ziehau sc->bnx_saved_status_tag = *sc->bnx_hw_status_tag; 3001695a8586SSepherosa Ziehau cpu_lfence(); 3002695a8586SSepherosa Ziehau bnx_npoll_status_notag(ifp); 30034fa38985SSepherosa Ziehau } 30044fa38985SSepherosa Ziehau 30054fa38985SSepherosa Ziehau static void 300639a8d43aSSepherosa Ziehau bnx_npoll(struct ifnet *ifp, struct ifpoll_info *info) 300739a8d43aSSepherosa Ziehau { 300839a8d43aSSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 30094fa38985SSepherosa Ziehau int i; 301039a8d43aSSepherosa Ziehau 3011329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 301239a8d43aSSepherosa Ziehau 301339a8d43aSSepherosa Ziehau if (info != NULL) { 3014695a8586SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_STATUS_HASTAG) 30154fa38985SSepherosa Ziehau info->ifpi_status.status_func = bnx_npoll_status; 3016695a8586SSepherosa Ziehau else 3017695a8586SSepherosa Ziehau info->ifpi_status.status_func = bnx_npoll_status_notag; 30184fa38985SSepherosa Ziehau info->ifpi_status.serializer = &sc->bnx_main_serialize; 301939a8d43aSSepherosa Ziehau 30204fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 30214fa38985SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 302202596bedSSepherosa Ziehau int cpu = if_ringmap_cpumap(sc->bnx_tx_rmap, i); 30234fa38985SSepherosa Ziehau 302402596bedSSepherosa Ziehau KKASSERT(cpu < netisr_ncpus); 3025695a8586SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_RXTX_BUNDLE) { 302602596bedSSepherosa Ziehau info->ifpi_tx[cpu].poll_func = 3027695a8586SSepherosa Ziehau bnx_npoll_tx_notag; 3028695a8586SSepherosa Ziehau } else { 302902596bedSSepherosa Ziehau info->ifpi_tx[cpu].poll_func = bnx_npoll_tx; 3030695a8586SSepherosa Ziehau } 303102596bedSSepherosa Ziehau info->ifpi_tx[cpu].arg = txr; 303202596bedSSepherosa Ziehau info->ifpi_tx[cpu].serializer = &txr->bnx_tx_serialize; 303302596bedSSepherosa Ziehau ifsq_set_cpuid(txr->bnx_ifsq, cpu); 30344fa38985SSepherosa Ziehau } 30354fa38985SSepherosa Ziehau 30364fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 30374fa38985SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[i]; 303802596bedSSepherosa Ziehau int cpu = if_ringmap_cpumap(sc->bnx_rx_rmap, i); 30394fa38985SSepherosa Ziehau 304002596bedSSepherosa Ziehau KKASSERT(cpu < netisr_ncpus); 304102596bedSSepherosa Ziehau info->ifpi_rx[cpu].poll_func = bnx_npoll_rx; 304202596bedSSepherosa Ziehau info->ifpi_rx[cpu].arg = ret; 304302596bedSSepherosa Ziehau info->ifpi_rx[cpu].serializer = 30444fa38985SSepherosa Ziehau &ret->bnx_rx_ret_serialize; 30454fa38985SSepherosa Ziehau } 304639a8d43aSSepherosa Ziehau 30477dbaa833SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 304839a8d43aSSepherosa Ziehau bnx_disable_intr(sc); 30497dbaa833SSepherosa Ziehau bnx_set_tick_cpuid(sc, TRUE); 305027357d84SSepherosa Ziehau 3051a86cc105SSepherosa Ziehau sc->bnx_coal_chg = BNX_TX_COAL_BDS_CHG | 3052a86cc105SSepherosa Ziehau BNX_RX_COAL_BDS_CHG; 305327357d84SSepherosa Ziehau bnx_coal_change(sc); 30547dbaa833SSepherosa Ziehau } 305539a8d43aSSepherosa Ziehau } else { 30564fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 30574fa38985SSepherosa Ziehau ifsq_set_cpuid(sc->bnx_tx_ring[i].bnx_ifsq, 30584fa38985SSepherosa Ziehau sc->bnx_tx_ring[i].bnx_tx_cpuid); 30594fa38985SSepherosa Ziehau } 30607dbaa833SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 3061a86cc105SSepherosa Ziehau sc->bnx_coal_chg = BNX_TX_COAL_BDS_CHG | 3062a86cc105SSepherosa Ziehau BNX_RX_COAL_BDS_CHG; 306327357d84SSepherosa Ziehau bnx_coal_change(sc); 306427357d84SSepherosa Ziehau 306539a8d43aSSepherosa Ziehau bnx_enable_intr(sc); 30667dbaa833SSepherosa Ziehau bnx_set_tick_cpuid(sc, FALSE); 30677dbaa833SSepherosa Ziehau } 306839a8d43aSSepherosa Ziehau } 306939a8d43aSSepherosa Ziehau } 307039a8d43aSSepherosa Ziehau 307139a8d43aSSepherosa Ziehau #endif /* IFPOLL_ENABLE */ 30726c8d8eccSSepherosa Ziehau 30736c8d8eccSSepherosa Ziehau static void 30746c8d8eccSSepherosa Ziehau bnx_intr_legacy(void *xsc) 30756c8d8eccSSepherosa Ziehau { 30766c8d8eccSSepherosa Ziehau struct bnx_softc *sc = xsc; 30774fa38985SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[0]; 30786c8d8eccSSepherosa Ziehau 30794fa38985SSepherosa Ziehau if (ret->bnx_saved_status_tag == *ret->bnx_hw_status_tag) { 30806c8d8eccSSepherosa Ziehau uint32_t val; 30816c8d8eccSSepherosa Ziehau 30826c8d8eccSSepherosa Ziehau val = pci_read_config(sc->bnx_dev, BGE_PCI_PCISTATE, 4); 30836c8d8eccSSepherosa Ziehau if (val & BGE_PCISTAT_INTR_NOTACT) 30846c8d8eccSSepherosa Ziehau return; 30856c8d8eccSSepherosa Ziehau } 30866c8d8eccSSepherosa Ziehau 30876c8d8eccSSepherosa Ziehau /* 30886c8d8eccSSepherosa Ziehau * NOTE: 30896c8d8eccSSepherosa Ziehau * Interrupt will have to be disabled if tagged status 30906c8d8eccSSepherosa Ziehau * is used, else interrupt will always be asserted on 30916c8d8eccSSepherosa Ziehau * certain chips (at least on BCM5750 AX/BX). 30926c8d8eccSSepherosa Ziehau */ 30936c8d8eccSSepherosa Ziehau bnx_writembx(sc, BGE_MBX_IRQ0_LO, 1); 30946c8d8eccSSepherosa Ziehau 30956c8d8eccSSepherosa Ziehau bnx_intr(sc); 30966c8d8eccSSepherosa Ziehau } 30976c8d8eccSSepherosa Ziehau 30986c8d8eccSSepherosa Ziehau static void 309903cc99fdSSepherosa Ziehau bnx_msi(void *xsc) 31006c8d8eccSSepherosa Ziehau { 31016c8d8eccSSepherosa Ziehau bnx_intr(xsc); 31026c8d8eccSSepherosa Ziehau } 31036c8d8eccSSepherosa Ziehau 31046c8d8eccSSepherosa Ziehau static void 31056c8d8eccSSepherosa Ziehau bnx_intr(struct bnx_softc *sc) 31066c8d8eccSSepherosa Ziehau { 31076c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 31084fa38985SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[0]; 31096c8d8eccSSepherosa Ziehau 3110329f9016SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 3111329f9016SSepherosa Ziehau 31124fa38985SSepherosa Ziehau ret->bnx_saved_status_tag = *ret->bnx_hw_status_tag; 31136c8d8eccSSepherosa Ziehau /* 31146c8d8eccSSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 31156c8d8eccSSepherosa Ziehau * before rx_prod, tx_cons and status. 31166c8d8eccSSepherosa Ziehau */ 31176c8d8eccSSepherosa Ziehau cpu_lfence(); 31186c8d8eccSSepherosa Ziehau 3119695a8586SSepherosa Ziehau bnx_handle_status(sc); 31206c8d8eccSSepherosa Ziehau 31216c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 31224fa38985SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[0]; 31233a16b7b8SSepherosa Ziehau uint16_t rx_prod, tx_cons; 31243a16b7b8SSepherosa Ziehau 3125329f9016SSepherosa Ziehau lwkt_serialize_enter(&ret->bnx_rx_ret_serialize); 31263a16b7b8SSepherosa Ziehau rx_prod = *ret->bnx_rx_considx; 3127beedf5beSSepherosa Ziehau if (ret->bnx_rx_saved_considx != rx_prod) 3128beedf5beSSepherosa Ziehau bnx_rxeof(ret, rx_prod, -1); 3129329f9016SSepherosa Ziehau lwkt_serialize_exit(&ret->bnx_rx_ret_serialize); 31306c8d8eccSSepherosa Ziehau 3131329f9016SSepherosa Ziehau lwkt_serialize_enter(&txr->bnx_tx_serialize); 3132329f9016SSepherosa Ziehau tx_cons = *txr->bnx_tx_considx; 313333a04907SSepherosa Ziehau if (txr->bnx_tx_saved_considx != tx_cons) 313433a04907SSepherosa Ziehau bnx_txeof(txr, tx_cons); 3135329f9016SSepherosa Ziehau lwkt_serialize_exit(&txr->bnx_tx_serialize); 31366c8d8eccSSepherosa Ziehau } 31376c8d8eccSSepherosa Ziehau 31384fa38985SSepherosa Ziehau bnx_writembx(sc, BGE_MBX_IRQ0_LO, ret->bnx_saved_status_tag << 24); 31396c8d8eccSSepherosa Ziehau } 31406c8d8eccSSepherosa Ziehau 31416c8d8eccSSepherosa Ziehau static void 3142695a8586SSepherosa Ziehau bnx_msix_tx_status(void *xtxr) 3143695a8586SSepherosa Ziehau { 3144695a8586SSepherosa Ziehau struct bnx_tx_ring *txr = xtxr; 3145695a8586SSepherosa Ziehau struct bnx_softc *sc = txr->bnx_sc; 3146695a8586SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 3147695a8586SSepherosa Ziehau 3148695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 3149695a8586SSepherosa Ziehau 3150695a8586SSepherosa Ziehau txr->bnx_saved_status_tag = *txr->bnx_hw_status_tag; 3151695a8586SSepherosa Ziehau /* 3152695a8586SSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 3153695a8586SSepherosa Ziehau * before tx_cons and status. 3154695a8586SSepherosa Ziehau */ 3155695a8586SSepherosa Ziehau cpu_lfence(); 3156695a8586SSepherosa Ziehau 3157695a8586SSepherosa Ziehau bnx_handle_status(sc); 3158695a8586SSepherosa Ziehau 3159695a8586SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 3160695a8586SSepherosa Ziehau uint16_t tx_cons; 3161695a8586SSepherosa Ziehau 3162695a8586SSepherosa Ziehau lwkt_serialize_enter(&txr->bnx_tx_serialize); 3163695a8586SSepherosa Ziehau tx_cons = *txr->bnx_tx_considx; 3164695a8586SSepherosa Ziehau if (txr->bnx_tx_saved_considx != tx_cons) 3165695a8586SSepherosa Ziehau bnx_txeof(txr, tx_cons); 3166695a8586SSepherosa Ziehau lwkt_serialize_exit(&txr->bnx_tx_serialize); 3167695a8586SSepherosa Ziehau } 3168695a8586SSepherosa Ziehau 3169695a8586SSepherosa Ziehau bnx_writembx(sc, BGE_MBX_IRQ0_LO, txr->bnx_saved_status_tag << 24); 3170695a8586SSepherosa Ziehau } 3171695a8586SSepherosa Ziehau 3172695a8586SSepherosa Ziehau static void 3173695a8586SSepherosa Ziehau bnx_msix_rx(void *xret) 3174695a8586SSepherosa Ziehau { 3175695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret = xret; 3176695a8586SSepherosa Ziehau uint16_t rx_prod; 3177695a8586SSepherosa Ziehau 3178695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&ret->bnx_rx_ret_serialize); 3179695a8586SSepherosa Ziehau 3180695a8586SSepherosa Ziehau ret->bnx_saved_status_tag = *ret->bnx_hw_status_tag; 3181695a8586SSepherosa Ziehau /* 3182695a8586SSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 3183695a8586SSepherosa Ziehau * before rx_prod. 3184695a8586SSepherosa Ziehau */ 3185695a8586SSepherosa Ziehau cpu_lfence(); 3186695a8586SSepherosa Ziehau 3187695a8586SSepherosa Ziehau rx_prod = *ret->bnx_rx_considx; 3188695a8586SSepherosa Ziehau if (ret->bnx_rx_saved_considx != rx_prod) 3189695a8586SSepherosa Ziehau bnx_rxeof(ret, rx_prod, -1); 3190695a8586SSepherosa Ziehau 3191695a8586SSepherosa Ziehau bnx_writembx(ret->bnx_sc, ret->bnx_msix_mbx, 3192695a8586SSepherosa Ziehau ret->bnx_saved_status_tag << 24); 3193695a8586SSepherosa Ziehau } 3194695a8586SSepherosa Ziehau 3195695a8586SSepherosa Ziehau static void 3196695a8586SSepherosa Ziehau bnx_msix_rxtx(void *xret) 3197695a8586SSepherosa Ziehau { 3198695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret = xret; 3199695a8586SSepherosa Ziehau struct bnx_tx_ring *txr = ret->bnx_txr; 3200695a8586SSepherosa Ziehau uint16_t rx_prod, tx_cons; 3201695a8586SSepherosa Ziehau 3202695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&ret->bnx_rx_ret_serialize); 3203695a8586SSepherosa Ziehau 3204695a8586SSepherosa Ziehau ret->bnx_saved_status_tag = *ret->bnx_hw_status_tag; 3205695a8586SSepherosa Ziehau /* 3206695a8586SSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 3207695a8586SSepherosa Ziehau * before rx_prod and tx_cons. 3208695a8586SSepherosa Ziehau */ 3209695a8586SSepherosa Ziehau cpu_lfence(); 3210695a8586SSepherosa Ziehau 3211695a8586SSepherosa Ziehau rx_prod = *ret->bnx_rx_considx; 3212695a8586SSepherosa Ziehau if (ret->bnx_rx_saved_considx != rx_prod) 3213695a8586SSepherosa Ziehau bnx_rxeof(ret, rx_prod, -1); 3214695a8586SSepherosa Ziehau 3215695a8586SSepherosa Ziehau lwkt_serialize_enter(&txr->bnx_tx_serialize); 3216695a8586SSepherosa Ziehau tx_cons = *txr->bnx_tx_considx; 3217695a8586SSepherosa Ziehau if (txr->bnx_tx_saved_considx != tx_cons) 3218695a8586SSepherosa Ziehau bnx_txeof(txr, tx_cons); 3219695a8586SSepherosa Ziehau lwkt_serialize_exit(&txr->bnx_tx_serialize); 3220695a8586SSepherosa Ziehau 3221695a8586SSepherosa Ziehau bnx_writembx(ret->bnx_sc, ret->bnx_msix_mbx, 3222695a8586SSepherosa Ziehau ret->bnx_saved_status_tag << 24); 3223695a8586SSepherosa Ziehau } 3224695a8586SSepherosa Ziehau 3225695a8586SSepherosa Ziehau static void 3226695a8586SSepherosa Ziehau bnx_msix_status(void *xsc) 3227695a8586SSepherosa Ziehau { 3228695a8586SSepherosa Ziehau struct bnx_softc *sc = xsc; 3229695a8586SSepherosa Ziehau 3230695a8586SSepherosa Ziehau ASSERT_SERIALIZED(&sc->bnx_main_serialize); 3231695a8586SSepherosa Ziehau 3232695a8586SSepherosa Ziehau sc->bnx_saved_status_tag = *sc->bnx_hw_status_tag; 3233695a8586SSepherosa Ziehau /* 3234695a8586SSepherosa Ziehau * Use a load fence to ensure that status_tag is saved 3235695a8586SSepherosa Ziehau * before status. 3236695a8586SSepherosa Ziehau */ 3237695a8586SSepherosa Ziehau cpu_lfence(); 3238695a8586SSepherosa Ziehau 3239695a8586SSepherosa Ziehau bnx_handle_status(sc); 3240695a8586SSepherosa Ziehau 3241695a8586SSepherosa Ziehau bnx_writembx(sc, BGE_MBX_IRQ0_LO, sc->bnx_saved_status_tag << 24); 3242695a8586SSepherosa Ziehau } 3243695a8586SSepherosa Ziehau 3244695a8586SSepherosa Ziehau static void 32456c8d8eccSSepherosa Ziehau bnx_tick(void *xsc) 32466c8d8eccSSepherosa Ziehau { 32476c8d8eccSSepherosa Ziehau struct bnx_softc *sc = xsc; 32486c8d8eccSSepherosa Ziehau 3249329f9016SSepherosa Ziehau lwkt_serialize_enter(&sc->bnx_main_serialize); 32506c8d8eccSSepherosa Ziehau 32516c8d8eccSSepherosa Ziehau bnx_stats_update_regs(sc); 32526c8d8eccSSepherosa Ziehau 32536c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 32546c8d8eccSSepherosa Ziehau /* 32556c8d8eccSSepherosa Ziehau * Since in TBI mode auto-polling can't be used we should poll 32566c8d8eccSSepherosa Ziehau * link status manually. Here we register pending link event 32576c8d8eccSSepherosa Ziehau * and trigger interrupt. 32586c8d8eccSSepherosa Ziehau */ 32596c8d8eccSSepherosa Ziehau sc->bnx_link_evt++; 32606c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_HCC_MODE, BGE_HCCMODE_COAL_NOW); 32616c8d8eccSSepherosa Ziehau } else if (!sc->bnx_link) { 32626c8d8eccSSepherosa Ziehau mii_tick(device_get_softc(sc->bnx_miibus)); 32636c8d8eccSSepherosa Ziehau } 32646c8d8eccSSepherosa Ziehau 32657dbaa833SSepherosa Ziehau callout_reset_bycpu(&sc->bnx_tick_timer, hz, bnx_tick, sc, 32667dbaa833SSepherosa Ziehau sc->bnx_tick_cpuid); 32676c8d8eccSSepherosa Ziehau 3268329f9016SSepherosa Ziehau lwkt_serialize_exit(&sc->bnx_main_serialize); 32696c8d8eccSSepherosa Ziehau } 32706c8d8eccSSepherosa Ziehau 32716c8d8eccSSepherosa Ziehau static void 32726c8d8eccSSepherosa Ziehau bnx_stats_update_regs(struct bnx_softc *sc) 32736c8d8eccSSepherosa Ziehau { 32746c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 32756c8d8eccSSepherosa Ziehau struct bge_mac_stats_regs stats; 3276695a8586SSepherosa Ziehau uint32_t *s, val; 32776c8d8eccSSepherosa Ziehau int i; 32786c8d8eccSSepherosa Ziehau 32796c8d8eccSSepherosa Ziehau s = (uint32_t *)&stats; 32806c8d8eccSSepherosa Ziehau for (i = 0; i < sizeof(struct bge_mac_stats_regs); i += 4) { 32816c8d8eccSSepherosa Ziehau *s = CSR_READ_4(sc, BGE_RX_STATS + i); 32826c8d8eccSSepherosa Ziehau s++; 32836c8d8eccSSepherosa Ziehau } 32846c8d8eccSSepherosa Ziehau 3285d40991efSSepherosa Ziehau IFNET_STAT_SET(ifp, collisions, 32866c8d8eccSSepherosa Ziehau (stats.dot3StatsSingleCollisionFrames + 32876c8d8eccSSepherosa Ziehau stats.dot3StatsMultipleCollisionFrames + 32886c8d8eccSSepherosa Ziehau stats.dot3StatsExcessiveCollisions + 3289d40991efSSepherosa Ziehau stats.dot3StatsLateCollisions)); 3290695a8586SSepherosa Ziehau 3291695a8586SSepherosa Ziehau val = CSR_READ_4(sc, BGE_RXLP_LOCSTAT_OUT_OF_BDS); 3292695a8586SSepherosa Ziehau sc->bnx_norxbds += val; 32936c8d8eccSSepherosa Ziehau } 32946c8d8eccSSepherosa Ziehau 32956c8d8eccSSepherosa Ziehau /* 32966c8d8eccSSepherosa Ziehau * Encapsulate an mbuf chain in the tx ring by coupling the mbuf data 32976c8d8eccSSepherosa Ziehau * pointers to descriptors. 32986c8d8eccSSepherosa Ziehau */ 32996c8d8eccSSepherosa Ziehau static int 330033a04907SSepherosa Ziehau bnx_encap(struct bnx_tx_ring *txr, struct mbuf **m_head0, uint32_t *txidx, 3301c9b7f592SSepherosa Ziehau int *segs_used) 33026c8d8eccSSepherosa Ziehau { 33036c8d8eccSSepherosa Ziehau struct bge_tx_bd *d = NULL; 330466deb1c1SSepherosa Ziehau uint16_t csum_flags = 0, vlan_tag = 0, mss = 0; 33056c8d8eccSSepherosa Ziehau bus_dma_segment_t segs[BNX_NSEG_NEW]; 33066c8d8eccSSepherosa Ziehau bus_dmamap_t map; 33076c8d8eccSSepherosa Ziehau int error, maxsegs, nsegs, idx, i; 33086c8d8eccSSepherosa Ziehau struct mbuf *m_head = *m_head0, *m_new; 33096c8d8eccSSepherosa Ziehau 331066deb1c1SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 331166deb1c1SSepherosa Ziehau #ifdef BNX_TSO_DEBUG 331266deb1c1SSepherosa Ziehau int tso_nsegs; 331366deb1c1SSepherosa Ziehau #endif 331466deb1c1SSepherosa Ziehau 331533a04907SSepherosa Ziehau error = bnx_setup_tso(txr, m_head0, &mss, &csum_flags); 331666deb1c1SSepherosa Ziehau if (error) 331766deb1c1SSepherosa Ziehau return error; 331866deb1c1SSepherosa Ziehau m_head = *m_head0; 331966deb1c1SSepherosa Ziehau 332066deb1c1SSepherosa Ziehau #ifdef BNX_TSO_DEBUG 3321f0336d39SSepherosa Ziehau tso_nsegs = (m_head->m_pkthdr.len / 3322f0336d39SSepherosa Ziehau m_head->m_pkthdr.tso_segsz) - 1; 332366deb1c1SSepherosa Ziehau if (tso_nsegs > (BNX_TSO_NSTATS - 1)) 332466deb1c1SSepherosa Ziehau tso_nsegs = BNX_TSO_NSTATS - 1; 332566deb1c1SSepherosa Ziehau else if (tso_nsegs < 0) 332666deb1c1SSepherosa Ziehau tso_nsegs = 0; 33275a0c3c3aSSascha Wildner txr->bnx_sc->bnx_tsosegs[tso_nsegs]++; 332866deb1c1SSepherosa Ziehau #endif 332966deb1c1SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & BNX_CSUM_FEATURES) { 33306c8d8eccSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 33316c8d8eccSSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_IP_CSUM; 33326c8d8eccSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) 33336c8d8eccSSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_TCP_UDP_CSUM; 33346c8d8eccSSepherosa Ziehau if (m_head->m_flags & M_LASTFRAG) 33356c8d8eccSSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_IP_FRAG_END; 33366c8d8eccSSepherosa Ziehau else if (m_head->m_flags & M_FRAG) 33376c8d8eccSSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_IP_FRAG; 33386c8d8eccSSepherosa Ziehau } 333966deb1c1SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 334066deb1c1SSepherosa Ziehau csum_flags |= BGE_TXBDFLAG_VLAN_TAG; 334166deb1c1SSepherosa Ziehau vlan_tag = m_head->m_pkthdr.ether_vlantag; 334266deb1c1SSepherosa Ziehau } 33436c8d8eccSSepherosa Ziehau 33446c8d8eccSSepherosa Ziehau idx = *txidx; 3345fa4b1067SSepherosa Ziehau map = txr->bnx_tx_buf[idx].bnx_tx_dmamap; 33466c8d8eccSSepherosa Ziehau 3347fa639b88SSepherosa Ziehau maxsegs = (BGE_TX_RING_CNT - txr->bnx_tx_cnt) - BNX_NSEG_RSVD; 33486c8d8eccSSepherosa Ziehau KASSERT(maxsegs >= BNX_NSEG_SPARE, 33496c8d8eccSSepherosa Ziehau ("not enough segments %d", maxsegs)); 33506c8d8eccSSepherosa Ziehau 33516c8d8eccSSepherosa Ziehau if (maxsegs > BNX_NSEG_NEW) 33526c8d8eccSSepherosa Ziehau maxsegs = BNX_NSEG_NEW; 33536c8d8eccSSepherosa Ziehau 33546c8d8eccSSepherosa Ziehau /* 33556c8d8eccSSepherosa Ziehau * Pad outbound frame to BGE_MIN_FRAMELEN for an unusual reason. 33566c8d8eccSSepherosa Ziehau * The bge hardware will pad out Tx runts to BGE_MIN_FRAMELEN, 33576c8d8eccSSepherosa Ziehau * but when such padded frames employ the bge IP/TCP checksum 33586c8d8eccSSepherosa Ziehau * offload, the hardware checksum assist gives incorrect results 33596c8d8eccSSepherosa Ziehau * (possibly from incorporating its own padding into the UDP/TCP 33606c8d8eccSSepherosa Ziehau * checksum; who knows). If we pad such runts with zeros, the 33616c8d8eccSSepherosa Ziehau * onboard checksum comes out correct. 33626c8d8eccSSepherosa Ziehau */ 33636c8d8eccSSepherosa Ziehau if ((csum_flags & BGE_TXBDFLAG_TCP_UDP_CSUM) && 33646c8d8eccSSepherosa Ziehau m_head->m_pkthdr.len < BNX_MIN_FRAMELEN) { 33656c8d8eccSSepherosa Ziehau error = m_devpad(m_head, BNX_MIN_FRAMELEN); 33666c8d8eccSSepherosa Ziehau if (error) 33676c8d8eccSSepherosa Ziehau goto back; 33686c8d8eccSSepherosa Ziehau } 33696c8d8eccSSepherosa Ziehau 337079a64343SSepherosa Ziehau if ((txr->bnx_tx_flags & BNX_TX_FLAG_SHORTDMA) && 337133a04907SSepherosa Ziehau m_head->m_next != NULL) { 33726c8d8eccSSepherosa Ziehau m_new = bnx_defrag_shortdma(m_head); 33736c8d8eccSSepherosa Ziehau if (m_new == NULL) { 33746c8d8eccSSepherosa Ziehau error = ENOBUFS; 33756c8d8eccSSepherosa Ziehau goto back; 33766c8d8eccSSepherosa Ziehau } 33776c8d8eccSSepherosa Ziehau *m_head0 = m_head = m_new; 33786c8d8eccSSepherosa Ziehau } 337966deb1c1SSepherosa Ziehau if ((m_head->m_pkthdr.csum_flags & CSUM_TSO) == 0 && 3380aad4de2bSSepherosa Ziehau (txr->bnx_tx_flags & BNX_TX_FLAG_FORCE_DEFRAG) && 3381aad4de2bSSepherosa Ziehau m_head->m_next != NULL) { 33826c8d8eccSSepherosa Ziehau /* 33836c8d8eccSSepherosa Ziehau * Forcefully defragment mbuf chain to overcome hardware 33846c8d8eccSSepherosa Ziehau * limitation which only support a single outstanding 33856c8d8eccSSepherosa Ziehau * DMA read operation. If it fails, keep moving on using 33866c8d8eccSSepherosa Ziehau * the original mbuf chain. 33876c8d8eccSSepherosa Ziehau */ 3388b5523eacSSascha Wildner m_new = m_defrag(m_head, M_NOWAIT); 33896c8d8eccSSepherosa Ziehau if (m_new != NULL) 33906c8d8eccSSepherosa Ziehau *m_head0 = m_head = m_new; 33916c8d8eccSSepherosa Ziehau } 33926c8d8eccSSepherosa Ziehau 339333a04907SSepherosa Ziehau error = bus_dmamap_load_mbuf_defrag(txr->bnx_tx_mtag, map, 33946c8d8eccSSepherosa Ziehau m_head0, segs, maxsegs, &nsegs, BUS_DMA_NOWAIT); 33956c8d8eccSSepherosa Ziehau if (error) 33966c8d8eccSSepherosa Ziehau goto back; 3397c9b7f592SSepherosa Ziehau *segs_used += nsegs; 33986c8d8eccSSepherosa Ziehau 33996c8d8eccSSepherosa Ziehau m_head = *m_head0; 340033a04907SSepherosa Ziehau bus_dmamap_sync(txr->bnx_tx_mtag, map, BUS_DMASYNC_PREWRITE); 34016c8d8eccSSepherosa Ziehau 34026c8d8eccSSepherosa Ziehau for (i = 0; ; i++) { 340333a04907SSepherosa Ziehau d = &txr->bnx_tx_ring[idx]; 34046c8d8eccSSepherosa Ziehau 34056c8d8eccSSepherosa Ziehau d->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[i].ds_addr); 34066c8d8eccSSepherosa Ziehau d->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[i].ds_addr); 34076c8d8eccSSepherosa Ziehau d->bge_len = segs[i].ds_len; 34086c8d8eccSSepherosa Ziehau d->bge_flags = csum_flags; 340966deb1c1SSepherosa Ziehau d->bge_vlan_tag = vlan_tag; 341066deb1c1SSepherosa Ziehau d->bge_mss = mss; 34116c8d8eccSSepherosa Ziehau 34126c8d8eccSSepherosa Ziehau if (i == nsegs - 1) 34136c8d8eccSSepherosa Ziehau break; 34146c8d8eccSSepherosa Ziehau BNX_INC(idx, BGE_TX_RING_CNT); 34156c8d8eccSSepherosa Ziehau } 34166c8d8eccSSepherosa Ziehau /* Mark the last segment as end of packet... */ 34176c8d8eccSSepherosa Ziehau d->bge_flags |= BGE_TXBDFLAG_END; 34186c8d8eccSSepherosa Ziehau 34196c8d8eccSSepherosa Ziehau /* 34206c8d8eccSSepherosa Ziehau * Insure that the map for this transmission is placed at 34216c8d8eccSSepherosa Ziehau * the array index of the last descriptor in this chain. 34226c8d8eccSSepherosa Ziehau */ 3423fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[*txidx].bnx_tx_dmamap = txr->bnx_tx_buf[idx].bnx_tx_dmamap; 3424fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[idx].bnx_tx_dmamap = map; 3425fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[idx].bnx_tx_mbuf = m_head; 3426fa639b88SSepherosa Ziehau txr->bnx_tx_cnt += nsegs; 34276c8d8eccSSepherosa Ziehau 34286c8d8eccSSepherosa Ziehau BNX_INC(idx, BGE_TX_RING_CNT); 34296c8d8eccSSepherosa Ziehau *txidx = idx; 34306c8d8eccSSepherosa Ziehau back: 34316c8d8eccSSepherosa Ziehau if (error) { 34326c8d8eccSSepherosa Ziehau m_freem(*m_head0); 34336c8d8eccSSepherosa Ziehau *m_head0 = NULL; 34346c8d8eccSSepherosa Ziehau } 34356c8d8eccSSepherosa Ziehau return error; 34366c8d8eccSSepherosa Ziehau } 34376c8d8eccSSepherosa Ziehau 34386c8d8eccSSepherosa Ziehau /* 34396c8d8eccSSepherosa Ziehau * Main transmit routine. To avoid having to do mbuf copies, we put pointers 34406c8d8eccSSepherosa Ziehau * to the mbuf data regions directly in the transmit descriptors. 34416c8d8eccSSepherosa Ziehau */ 34426c8d8eccSSepherosa Ziehau static void 3443f0a26983SSepherosa Ziehau bnx_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 34446c8d8eccSSepherosa Ziehau { 34453397dea6SSepherosa Ziehau struct bnx_tx_ring *txr = ifsq_get_priv(ifsq); 34466c8d8eccSSepherosa Ziehau struct mbuf *m_head = NULL; 34476c8d8eccSSepherosa Ziehau uint32_t prodidx; 3448c9b7f592SSepherosa Ziehau int nsegs = 0; 34496c8d8eccSSepherosa Ziehau 34503397dea6SSepherosa Ziehau KKASSERT(txr->bnx_ifsq == ifsq); 3451329f9016SSepherosa Ziehau ASSERT_SERIALIZED(&txr->bnx_tx_serialize); 3452f0a26983SSepherosa Ziehau 34533397dea6SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq)) 34546c8d8eccSSepherosa Ziehau return; 34556c8d8eccSSepherosa Ziehau 345633a04907SSepherosa Ziehau prodidx = txr->bnx_tx_prodidx; 34576c8d8eccSSepherosa Ziehau 3458fa4b1067SSepherosa Ziehau while (txr->bnx_tx_buf[prodidx].bnx_tx_mbuf == NULL) { 34596c8d8eccSSepherosa Ziehau /* 34606c8d8eccSSepherosa Ziehau * Sanity check: avoid coming within BGE_NSEG_RSVD 34616c8d8eccSSepherosa Ziehau * descriptors of the end of the ring. Also make 34626c8d8eccSSepherosa Ziehau * sure there are BGE_NSEG_SPARE descriptors for 3463a1bd58c9SSepherosa Ziehau * jumbo buffers' or TSO segments' defragmentation. 34646c8d8eccSSepherosa Ziehau */ 3465fa639b88SSepherosa Ziehau if ((BGE_TX_RING_CNT - txr->bnx_tx_cnt) < 34666c8d8eccSSepherosa Ziehau (BNX_NSEG_RSVD + BNX_NSEG_SPARE)) { 34673397dea6SSepherosa Ziehau ifsq_set_oactive(ifsq); 34686c8d8eccSSepherosa Ziehau break; 34696c8d8eccSSepherosa Ziehau } 34706c8d8eccSSepherosa Ziehau 3471ac9843a1SSepherosa Ziehau m_head = ifsq_dequeue(ifsq); 3472a1bd58c9SSepherosa Ziehau if (m_head == NULL) 3473a1bd58c9SSepherosa Ziehau break; 3474a1bd58c9SSepherosa Ziehau 34756c8d8eccSSepherosa Ziehau /* 34766c8d8eccSSepherosa Ziehau * Pack the data into the transmit ring. If we 34776c8d8eccSSepherosa Ziehau * don't have room, set the OACTIVE flag and wait 34786c8d8eccSSepherosa Ziehau * for the NIC to drain the ring. 34796c8d8eccSSepherosa Ziehau */ 348033a04907SSepherosa Ziehau if (bnx_encap(txr, &m_head, &prodidx, &nsegs)) { 34813397dea6SSepherosa Ziehau ifsq_set_oactive(ifsq); 3482d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 34836c8d8eccSSepherosa Ziehau break; 34846c8d8eccSSepherosa Ziehau } 34856c8d8eccSSepherosa Ziehau 348633a04907SSepherosa Ziehau if (nsegs >= txr->bnx_tx_wreg) { 34876c8d8eccSSepherosa Ziehau /* Transmit */ 34888bd43d5dSSepherosa Ziehau bnx_writembx(txr->bnx_sc, txr->bnx_tx_mbx, prodidx); 3489c9b7f592SSepherosa Ziehau nsegs = 0; 3490c9b7f592SSepherosa Ziehau } 34916c8d8eccSSepherosa Ziehau 3492c9b7f592SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m_head); 34936c8d8eccSSepherosa Ziehau 34946c8d8eccSSepherosa Ziehau /* 34956c8d8eccSSepherosa Ziehau * Set a timeout in case the chip goes out to lunch. 34966c8d8eccSSepherosa Ziehau */ 34973397dea6SSepherosa Ziehau txr->bnx_tx_watchdog.wd_timer = 5; 34986c8d8eccSSepherosa Ziehau } 34996c8d8eccSSepherosa Ziehau 3500c9b7f592SSepherosa Ziehau if (nsegs > 0) { 3501c9b7f592SSepherosa Ziehau /* Transmit */ 35028bd43d5dSSepherosa Ziehau bnx_writembx(txr->bnx_sc, txr->bnx_tx_mbx, prodidx); 3503c9b7f592SSepherosa Ziehau } 350433a04907SSepherosa Ziehau txr->bnx_tx_prodidx = prodidx; 3505c9b7f592SSepherosa Ziehau } 3506c9b7f592SSepherosa Ziehau 35076c8d8eccSSepherosa Ziehau static void 35086c8d8eccSSepherosa Ziehau bnx_init(void *xsc) 35096c8d8eccSSepherosa Ziehau { 35106c8d8eccSSepherosa Ziehau struct bnx_softc *sc = xsc; 35116c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 35126c8d8eccSSepherosa Ziehau uint16_t *m; 35136c8d8eccSSepherosa Ziehau uint32_t mode; 351433a04907SSepherosa Ziehau int i; 35157dbaa833SSepherosa Ziehau boolean_t polling; 35166c8d8eccSSepherosa Ziehau 3517329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 35186c8d8eccSSepherosa Ziehau 35196c8d8eccSSepherosa Ziehau /* Cancel pending I/O and flush buffers. */ 35206c8d8eccSSepherosa Ziehau bnx_stop(sc); 35214aa71e73SSepherosa Ziehau 35224aa71e73SSepherosa Ziehau bnx_sig_pre_reset(sc, BNX_RESET_START); 35236c8d8eccSSepherosa Ziehau bnx_reset(sc); 35244aa71e73SSepherosa Ziehau bnx_sig_post_reset(sc, BNX_RESET_START); 35254aa71e73SSepherosa Ziehau 35266c8d8eccSSepherosa Ziehau bnx_chipinit(sc); 35276c8d8eccSSepherosa Ziehau 35286c8d8eccSSepherosa Ziehau /* 35296c8d8eccSSepherosa Ziehau * Init the various state machines, ring 35306c8d8eccSSepherosa Ziehau * control blocks and firmware. 35316c8d8eccSSepherosa Ziehau */ 35326c8d8eccSSepherosa Ziehau if (bnx_blockinit(sc)) { 35336c8d8eccSSepherosa Ziehau if_printf(ifp, "initialization failure\n"); 35346c8d8eccSSepherosa Ziehau bnx_stop(sc); 35356c8d8eccSSepherosa Ziehau return; 35366c8d8eccSSepherosa Ziehau } 35376c8d8eccSSepherosa Ziehau 35386c8d8eccSSepherosa Ziehau /* Specify MTU. */ 35396c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_RX_MTU, ifp->if_mtu + 35406c8d8eccSSepherosa Ziehau ETHER_HDR_LEN + ETHER_CRC_LEN + EVL_ENCAPLEN); 35416c8d8eccSSepherosa Ziehau 35426c8d8eccSSepherosa Ziehau /* Load our MAC address. */ 35436c8d8eccSSepherosa Ziehau m = (uint16_t *)&sc->arpcom.ac_enaddr[0]; 35446c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_ADDR1_LO, htons(m[0])); 35456c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_ADDR1_HI, (htons(m[1]) << 16) | htons(m[2])); 35466c8d8eccSSepherosa Ziehau 35476c8d8eccSSepherosa Ziehau /* Enable or disable promiscuous mode as needed. */ 35486c8d8eccSSepherosa Ziehau bnx_setpromisc(sc); 35496c8d8eccSSepherosa Ziehau 35506c8d8eccSSepherosa Ziehau /* Program multicast filter. */ 35516c8d8eccSSepherosa Ziehau bnx_setmulti(sc); 35526c8d8eccSSepherosa Ziehau 35536c8d8eccSSepherosa Ziehau /* Init RX ring. */ 3554beedf5beSSepherosa Ziehau if (bnx_init_rx_ring_std(&sc->bnx_rx_std_ring)) { 35556c8d8eccSSepherosa Ziehau if_printf(ifp, "RX ring initialization failed\n"); 35566c8d8eccSSepherosa Ziehau bnx_stop(sc); 35576c8d8eccSSepherosa Ziehau return; 35586c8d8eccSSepherosa Ziehau } 35596c8d8eccSSepherosa Ziehau 35606c8d8eccSSepherosa Ziehau /* Init jumbo RX ring. */ 35616c8d8eccSSepherosa Ziehau if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN)) { 35626c8d8eccSSepherosa Ziehau if (bnx_init_rx_ring_jumbo(sc)) { 35636c8d8eccSSepherosa Ziehau if_printf(ifp, "Jumbo RX ring initialization failed\n"); 35646c8d8eccSSepherosa Ziehau bnx_stop(sc); 35656c8d8eccSSepherosa Ziehau return; 35666c8d8eccSSepherosa Ziehau } 35676c8d8eccSSepherosa Ziehau } 35686c8d8eccSSepherosa Ziehau 35696c8d8eccSSepherosa Ziehau /* Init our RX return ring index */ 3570841cdf08SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 3571841cdf08SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[i]; 3572841cdf08SSepherosa Ziehau 3573841cdf08SSepherosa Ziehau ret->bnx_rx_saved_considx = 0; 3574841cdf08SSepherosa Ziehau ret->bnx_rx_cnt = 0; 3575841cdf08SSepherosa Ziehau } 35766c8d8eccSSepherosa Ziehau 35776c8d8eccSSepherosa Ziehau /* Init TX ring. */ 357833a04907SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 357933a04907SSepherosa Ziehau bnx_init_tx_ring(&sc->bnx_tx_ring[i]); 35806c8d8eccSSepherosa Ziehau 35816c8d8eccSSepherosa Ziehau /* Enable TX MAC state machine lockup fix. */ 35826c8d8eccSSepherosa Ziehau mode = CSR_READ_4(sc, BGE_TX_MODE); 35836c8d8eccSSepherosa Ziehau mode |= BGE_TXMODE_MBUF_LOCKUP_FIX; 3584b96cbbb6SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5720 || 3585b96cbbb6SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5762) { 35866c8d8eccSSepherosa Ziehau mode &= ~(BGE_TXMODE_JMB_FRM_LEN | BGE_TXMODE_CNT_DN_MODE); 35876c8d8eccSSepherosa Ziehau mode |= CSR_READ_4(sc, BGE_TX_MODE) & 35886c8d8eccSSepherosa Ziehau (BGE_TXMODE_JMB_FRM_LEN | BGE_TXMODE_CNT_DN_MODE); 35896c8d8eccSSepherosa Ziehau } 35906c8d8eccSSepherosa Ziehau /* Turn on transmitter */ 35916c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_TX_MODE, mode | BGE_TXMODE_ENABLE); 35924aa71e73SSepherosa Ziehau DELAY(100); 35936c8d8eccSSepherosa Ziehau 3594695a8586SSepherosa Ziehau /* Initialize RSS */ 35959f5082d5SSepherosa Ziehau mode = BGE_RXMODE_ENABLE | BGE_RXMODE_IPV6_ENABLE; 3596695a8586SSepherosa Ziehau if (BNX_RSS_ENABLED(sc)) { 3597695a8586SSepherosa Ziehau bnx_init_rss(sc); 3598695a8586SSepherosa Ziehau mode |= BGE_RXMODE_RSS_ENABLE | 3599695a8586SSepherosa Ziehau BGE_RXMODE_RSS_HASH_MASK_BITS | 3600695a8586SSepherosa Ziehau BGE_RXMODE_RSS_IPV4_HASH | 3601695a8586SSepherosa Ziehau BGE_RXMODE_RSS_TCP_IPV4_HASH; 3602695a8586SSepherosa Ziehau } 36036c8d8eccSSepherosa Ziehau /* Turn on receiver */ 3604695a8586SSepherosa Ziehau BNX_SETBIT(sc, BGE_RX_MODE, mode); 36054aa71e73SSepherosa Ziehau DELAY(10); 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 ifp->if_flags |= IFF_RUNNING; 36443397dea6SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 36453397dea6SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 36463397dea6SSepherosa Ziehau 36473397dea6SSepherosa Ziehau ifsq_clr_oactive(txr->bnx_ifsq); 36483397dea6SSepherosa Ziehau ifsq_watchdog_start(&txr->bnx_tx_watchdog); 36493397dea6SSepherosa Ziehau } 36506c8d8eccSSepherosa Ziehau 36514aa71e73SSepherosa Ziehau bnx_ifmedia_upd(ifp); 36524aa71e73SSepherosa 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 } 36844aa71e73SSepherosa Ziehau DELAY(40); 36856c8d8eccSSepherosa Ziehau break; 36866c8d8eccSSepherosa Ziehau default: 36876c8d8eccSSepherosa Ziehau return(EINVAL); 36886c8d8eccSSepherosa Ziehau } 36896c8d8eccSSepherosa Ziehau } else { 36906c8d8eccSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->bnx_miibus); 36916c8d8eccSSepherosa Ziehau 36926c8d8eccSSepherosa Ziehau sc->bnx_link_evt++; 36936c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 36946c8d8eccSSepherosa Ziehau if (mii->mii_instance) { 36956c8d8eccSSepherosa Ziehau struct mii_softc *miisc; 36966c8d8eccSSepherosa Ziehau 36976c8d8eccSSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 36986c8d8eccSSepherosa Ziehau mii_phy_reset(miisc); 36996c8d8eccSSepherosa Ziehau } 37006c8d8eccSSepherosa Ziehau mii_mediachg(mii); 37016c8d8eccSSepherosa Ziehau 37026c8d8eccSSepherosa Ziehau /* 37036c8d8eccSSepherosa Ziehau * Force an interrupt so that we will call bnx_link_upd 37046c8d8eccSSepherosa Ziehau * if needed and clear any pending link state attention. 37056c8d8eccSSepherosa Ziehau * Without this we are not getting any further interrupts 37066c8d8eccSSepherosa Ziehau * for link state changes and thus will not UP the link and 37076c8d8eccSSepherosa Ziehau * not be able to send in bnx_start. The only way to get 37086c8d8eccSSepherosa Ziehau * things working was to receive a packet and get an RX 37096c8d8eccSSepherosa Ziehau * intr. 37106c8d8eccSSepherosa Ziehau * 37116c8d8eccSSepherosa Ziehau * bnx_tick should help for fiber cards and we might not 37126c8d8eccSSepherosa Ziehau * need to do this here if BNX_FLAG_TBI is set but as 37136c8d8eccSSepherosa Ziehau * we poll for fiber anyway it should not harm. 37146c8d8eccSSepherosa Ziehau */ 37156c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_HCC_MODE, BGE_HCCMODE_COAL_NOW); 37166c8d8eccSSepherosa Ziehau } 37176c8d8eccSSepherosa Ziehau return(0); 37186c8d8eccSSepherosa Ziehau } 37196c8d8eccSSepherosa Ziehau 37206c8d8eccSSepherosa Ziehau /* 37216c8d8eccSSepherosa Ziehau * Report current media status. 37226c8d8eccSSepherosa Ziehau */ 37236c8d8eccSSepherosa Ziehau static void 37246c8d8eccSSepherosa Ziehau bnx_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 37256c8d8eccSSepherosa Ziehau { 37266c8d8eccSSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 37276c8d8eccSSepherosa Ziehau 37284aa71e73SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0) 37294aa71e73SSepherosa Ziehau return; 37304aa71e73SSepherosa Ziehau 37316c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 37326c8d8eccSSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 37336c8d8eccSSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 37346c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_MAC_STS) & 37356c8d8eccSSepherosa Ziehau BGE_MACSTAT_TBI_PCS_SYNCHED) { 37366c8d8eccSSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 37376c8d8eccSSepherosa Ziehau } else { 37386c8d8eccSSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 37396c8d8eccSSepherosa Ziehau return; 37406c8d8eccSSepherosa Ziehau } 37416c8d8eccSSepherosa Ziehau 37426c8d8eccSSepherosa Ziehau ifmr->ifm_active |= IFM_1000_SX; 37436c8d8eccSSepherosa Ziehau if (CSR_READ_4(sc, BGE_MAC_MODE) & BGE_MACMODE_HALF_DUPLEX) 37446c8d8eccSSepherosa Ziehau ifmr->ifm_active |= IFM_HDX; 37456c8d8eccSSepherosa Ziehau else 37466c8d8eccSSepherosa Ziehau ifmr->ifm_active |= IFM_FDX; 37476c8d8eccSSepherosa Ziehau } else { 37486c8d8eccSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->bnx_miibus); 37496c8d8eccSSepherosa Ziehau 37506c8d8eccSSepherosa Ziehau mii_pollstat(mii); 37516c8d8eccSSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 37526c8d8eccSSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 37536c8d8eccSSepherosa Ziehau } 37546c8d8eccSSepherosa Ziehau } 37556c8d8eccSSepherosa Ziehau 37566c8d8eccSSepherosa Ziehau static int 37576c8d8eccSSepherosa Ziehau bnx_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) 37586c8d8eccSSepherosa Ziehau { 37596c8d8eccSSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 37606c8d8eccSSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 37616c8d8eccSSepherosa Ziehau int mask, error = 0; 37626c8d8eccSSepherosa Ziehau 3763329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 37646c8d8eccSSepherosa Ziehau 37656c8d8eccSSepherosa Ziehau switch (command) { 37666c8d8eccSSepherosa Ziehau case SIOCSIFMTU: 37676c8d8eccSSepherosa Ziehau if ((!BNX_IS_JUMBO_CAPABLE(sc) && ifr->ifr_mtu > ETHERMTU) || 37686c8d8eccSSepherosa Ziehau (BNX_IS_JUMBO_CAPABLE(sc) && 37696c8d8eccSSepherosa Ziehau ifr->ifr_mtu > BNX_JUMBO_MTU)) { 37706c8d8eccSSepherosa Ziehau error = EINVAL; 37716c8d8eccSSepherosa Ziehau } else if (ifp->if_mtu != ifr->ifr_mtu) { 37726c8d8eccSSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 37736c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 37746c8d8eccSSepherosa Ziehau bnx_init(sc); 37756c8d8eccSSepherosa Ziehau } 37766c8d8eccSSepherosa Ziehau break; 37776c8d8eccSSepherosa Ziehau case SIOCSIFFLAGS: 37786c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 37796c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 37806c8d8eccSSepherosa Ziehau mask = ifp->if_flags ^ sc->bnx_if_flags; 37816c8d8eccSSepherosa Ziehau 37826c8d8eccSSepherosa Ziehau /* 37836c8d8eccSSepherosa Ziehau * If only the state of the PROMISC flag 37846c8d8eccSSepherosa Ziehau * changed, then just use the 'set promisc 37856c8d8eccSSepherosa Ziehau * mode' command instead of reinitializing 37866c8d8eccSSepherosa Ziehau * the entire NIC. Doing a full re-init 37876c8d8eccSSepherosa Ziehau * means reloading the firmware and waiting 37886c8d8eccSSepherosa Ziehau * for it to start up, which may take a 37896c8d8eccSSepherosa Ziehau * second or two. Similarly for ALLMULTI. 37906c8d8eccSSepherosa Ziehau */ 37916c8d8eccSSepherosa Ziehau if (mask & IFF_PROMISC) 37926c8d8eccSSepherosa Ziehau bnx_setpromisc(sc); 37936c8d8eccSSepherosa Ziehau if (mask & IFF_ALLMULTI) 37946c8d8eccSSepherosa Ziehau bnx_setmulti(sc); 37956c8d8eccSSepherosa Ziehau } else { 37966c8d8eccSSepherosa Ziehau bnx_init(sc); 37976c8d8eccSSepherosa Ziehau } 37986c8d8eccSSepherosa Ziehau } else if (ifp->if_flags & IFF_RUNNING) { 37996c8d8eccSSepherosa Ziehau bnx_stop(sc); 38006c8d8eccSSepherosa Ziehau } 38016c8d8eccSSepherosa Ziehau sc->bnx_if_flags = ifp->if_flags; 38026c8d8eccSSepherosa Ziehau break; 38036c8d8eccSSepherosa Ziehau case SIOCADDMULTI: 38046c8d8eccSSepherosa Ziehau case SIOCDELMULTI: 38056c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 38066c8d8eccSSepherosa Ziehau bnx_setmulti(sc); 38076c8d8eccSSepherosa Ziehau break; 38086c8d8eccSSepherosa Ziehau case SIOCSIFMEDIA: 38096c8d8eccSSepherosa Ziehau case SIOCGIFMEDIA: 38106c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_TBI) { 38116c8d8eccSSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, 38126c8d8eccSSepherosa Ziehau &sc->bnx_ifmedia, command); 38136c8d8eccSSepherosa Ziehau } else { 38146c8d8eccSSepherosa Ziehau struct mii_data *mii; 38156c8d8eccSSepherosa Ziehau 38166c8d8eccSSepherosa Ziehau mii = device_get_softc(sc->bnx_miibus); 38176c8d8eccSSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, 38186c8d8eccSSepherosa Ziehau &mii->mii_media, command); 38196c8d8eccSSepherosa Ziehau } 38206c8d8eccSSepherosa Ziehau break; 38216c8d8eccSSepherosa Ziehau case SIOCSIFCAP: 38226c8d8eccSSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 38236c8d8eccSSepherosa Ziehau if (mask & IFCAP_HWCSUM) { 38246c8d8eccSSepherosa Ziehau ifp->if_capenable ^= (mask & IFCAP_HWCSUM); 382566deb1c1SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 382666deb1c1SSepherosa Ziehau ifp->if_hwassist |= BNX_CSUM_FEATURES; 38276c8d8eccSSepherosa Ziehau else 382866deb1c1SSepherosa Ziehau ifp->if_hwassist &= ~BNX_CSUM_FEATURES; 382966deb1c1SSepherosa Ziehau } 383066deb1c1SSepherosa Ziehau if (mask & IFCAP_TSO) { 383166deb1c1SSepherosa Ziehau ifp->if_capenable ^= (mask & IFCAP_TSO); 383266deb1c1SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO) 383366deb1c1SSepherosa Ziehau ifp->if_hwassist |= CSUM_TSO; 383466deb1c1SSepherosa Ziehau else 383566deb1c1SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 38366c8d8eccSSepherosa Ziehau } 3837b19ddf7eSSepherosa Ziehau if (mask & IFCAP_RSS) 3838b19ddf7eSSepherosa Ziehau ifp->if_capenable ^= IFCAP_RSS; 38396c8d8eccSSepherosa Ziehau break; 38406c8d8eccSSepherosa Ziehau default: 38416c8d8eccSSepherosa Ziehau error = ether_ioctl(ifp, command, data); 38426c8d8eccSSepherosa Ziehau break; 38436c8d8eccSSepherosa Ziehau } 38446c8d8eccSSepherosa Ziehau return error; 38456c8d8eccSSepherosa Ziehau } 38466c8d8eccSSepherosa Ziehau 38476c8d8eccSSepherosa Ziehau static void 38483397dea6SSepherosa Ziehau bnx_watchdog(struct ifaltq_subque *ifsq) 38496c8d8eccSSepherosa Ziehau { 38503397dea6SSepherosa Ziehau struct ifnet *ifp = ifsq_get_ifp(ifsq); 38516c8d8eccSSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 38523397dea6SSepherosa Ziehau int i; 38533397dea6SSepherosa Ziehau 38543397dea6SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 38556c8d8eccSSepherosa Ziehau 38566c8d8eccSSepherosa Ziehau if_printf(ifp, "watchdog timeout -- resetting\n"); 38576c8d8eccSSepherosa Ziehau 38586c8d8eccSSepherosa Ziehau bnx_init(sc); 38596c8d8eccSSepherosa Ziehau 3860d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 38616c8d8eccSSepherosa Ziehau 38623397dea6SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 38633397dea6SSepherosa Ziehau ifsq_devstart_sched(sc->bnx_tx_ring[i].bnx_ifsq); 38646c8d8eccSSepherosa Ziehau } 38656c8d8eccSSepherosa Ziehau 38666c8d8eccSSepherosa Ziehau /* 38676c8d8eccSSepherosa Ziehau * Stop the adapter and free any mbufs allocated to the 38686c8d8eccSSepherosa Ziehau * RX and TX lists. 38696c8d8eccSSepherosa Ziehau */ 38706c8d8eccSSepherosa Ziehau static void 38716c8d8eccSSepherosa Ziehau bnx_stop(struct bnx_softc *sc) 38726c8d8eccSSepherosa Ziehau { 38736c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 387433a04907SSepherosa Ziehau int i; 38756c8d8eccSSepherosa Ziehau 3876329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 38776c8d8eccSSepherosa Ziehau 38787dbaa833SSepherosa Ziehau callout_stop(&sc->bnx_tick_timer); 38796c8d8eccSSepherosa Ziehau 38804aa71e73SSepherosa Ziehau /* Disable host interrupts. */ 38814aa71e73SSepherosa Ziehau bnx_disable_intr(sc); 38824aa71e73SSepherosa Ziehau 38834aa71e73SSepherosa Ziehau /* 38844aa71e73SSepherosa Ziehau * Tell firmware we're shutting down. 38854aa71e73SSepherosa Ziehau */ 38864aa71e73SSepherosa Ziehau bnx_sig_pre_reset(sc, BNX_RESET_SHUTDOWN); 38874aa71e73SSepherosa Ziehau 38886c8d8eccSSepherosa Ziehau /* 38896c8d8eccSSepherosa Ziehau * Disable all of the receiver blocks 38906c8d8eccSSepherosa Ziehau */ 38916c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE); 38926c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RBDI_MODE, BGE_RBDIMODE_ENABLE); 38936c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RXLP_MODE, BGE_RXLPMODE_ENABLE); 38946c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RDBDI_MODE, BGE_RBDIMODE_ENABLE); 38956c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RDC_MODE, BGE_RDCMODE_ENABLE); 38966c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RBDC_MODE, BGE_RBDCMODE_ENABLE); 38976c8d8eccSSepherosa Ziehau 38986c8d8eccSSepherosa Ziehau /* 38996c8d8eccSSepherosa Ziehau * Disable all of the transmit blocks 39006c8d8eccSSepherosa Ziehau */ 39016c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SRS_MODE, BGE_SRSMODE_ENABLE); 39026c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SBDI_MODE, BGE_SBDIMODE_ENABLE); 39036c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE); 39046c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_RDMA_MODE, BGE_RDMAMODE_ENABLE); 39056c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SDC_MODE, BGE_SDCMODE_ENABLE); 39066c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_SBDC_MODE, BGE_SBDCMODE_ENABLE); 39076c8d8eccSSepherosa Ziehau 39086c8d8eccSSepherosa Ziehau /* 39096c8d8eccSSepherosa Ziehau * Shut down all of the memory managers and related 39106c8d8eccSSepherosa Ziehau * state machines. 39116c8d8eccSSepherosa Ziehau */ 39126c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_HCC_MODE, BGE_HCCMODE_ENABLE); 39136c8d8eccSSepherosa Ziehau bnx_stop_block(sc, BGE_WDMA_MODE, BGE_WDMAMODE_ENABLE); 39146c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_FTQ_RESET, 0xFFFFFFFF); 39156c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_FTQ_RESET, 0); 39166c8d8eccSSepherosa Ziehau 39174aa71e73SSepherosa Ziehau bnx_reset(sc); 39184aa71e73SSepherosa Ziehau bnx_sig_post_reset(sc, BNX_RESET_SHUTDOWN); 39196c8d8eccSSepherosa Ziehau 39206c8d8eccSSepherosa Ziehau /* 39216c8d8eccSSepherosa Ziehau * Tell firmware we're shutting down. 39226c8d8eccSSepherosa Ziehau */ 39236c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP); 39246c8d8eccSSepherosa Ziehau 39256c8d8eccSSepherosa Ziehau /* Free the RX lists. */ 3926beedf5beSSepherosa Ziehau bnx_free_rx_ring_std(&sc->bnx_rx_std_ring); 39276c8d8eccSSepherosa Ziehau 39286c8d8eccSSepherosa Ziehau /* Free jumbo RX list. */ 39296c8d8eccSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) 39306c8d8eccSSepherosa Ziehau bnx_free_rx_ring_jumbo(sc); 39316c8d8eccSSepherosa Ziehau 39326c8d8eccSSepherosa Ziehau /* Free TX buffers. */ 39334fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 39344fa38985SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 39356c8d8eccSSepherosa Ziehau 39364fa38985SSepherosa Ziehau txr->bnx_saved_status_tag = 0; 39374fa38985SSepherosa Ziehau bnx_free_tx_ring(txr); 39384fa38985SSepherosa Ziehau } 39394fa38985SSepherosa Ziehau 39404fa38985SSepherosa Ziehau /* Clear saved status tag */ 39414fa38985SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) 39424fa38985SSepherosa Ziehau sc->bnx_rx_ret_ring[i].bnx_saved_status_tag = 0; 39434fa38985SSepherosa Ziehau 39446c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 39456c8d8eccSSepherosa Ziehau sc->bnx_coal_chg = 0; 39466c8d8eccSSepherosa Ziehau 39479ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 39483397dea6SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 39493397dea6SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 39503397dea6SSepherosa Ziehau 39513397dea6SSepherosa Ziehau ifsq_clr_oactive(txr->bnx_ifsq); 39523397dea6SSepherosa Ziehau ifsq_watchdog_stop(&txr->bnx_tx_watchdog); 39533397dea6SSepherosa Ziehau } 39546c8d8eccSSepherosa Ziehau } 39556c8d8eccSSepherosa Ziehau 39566c8d8eccSSepherosa Ziehau /* 39576c8d8eccSSepherosa Ziehau * Stop all chip I/O so that the kernel's probe routines don't 39586c8d8eccSSepherosa Ziehau * get confused by errant DMAs when rebooting. 39596c8d8eccSSepherosa Ziehau */ 39606c8d8eccSSepherosa Ziehau static void 39616c8d8eccSSepherosa Ziehau bnx_shutdown(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 39716c8d8eccSSepherosa Ziehau static int 39726c8d8eccSSepherosa Ziehau bnx_suspend(device_t dev) 39736c8d8eccSSepherosa Ziehau { 39746c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 39756c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 39766c8d8eccSSepherosa Ziehau 3977329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 39786c8d8eccSSepherosa Ziehau bnx_stop(sc); 3979329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 39806c8d8eccSSepherosa Ziehau 39816c8d8eccSSepherosa Ziehau return 0; 39826c8d8eccSSepherosa Ziehau } 39836c8d8eccSSepherosa Ziehau 39846c8d8eccSSepherosa Ziehau static int 39856c8d8eccSSepherosa Ziehau bnx_resume(device_t dev) 39866c8d8eccSSepherosa Ziehau { 39876c8d8eccSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 39886c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 39896c8d8eccSSepherosa Ziehau 3990329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 39916c8d8eccSSepherosa Ziehau 39926c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 39933397dea6SSepherosa Ziehau int i; 39946c8d8eccSSepherosa Ziehau 39953397dea6SSepherosa Ziehau bnx_init(sc); 39963397dea6SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 39973397dea6SSepherosa Ziehau ifsq_devstart_sched(sc->bnx_tx_ring[i].bnx_ifsq); 39986c8d8eccSSepherosa Ziehau } 39996c8d8eccSSepherosa Ziehau 4000329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 40016c8d8eccSSepherosa Ziehau 40026c8d8eccSSepherosa Ziehau return 0; 40036c8d8eccSSepherosa Ziehau } 40046c8d8eccSSepherosa Ziehau 40056c8d8eccSSepherosa Ziehau static void 40066c8d8eccSSepherosa Ziehau bnx_setpromisc(struct bnx_softc *sc) 40076c8d8eccSSepherosa Ziehau { 40086c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 40096c8d8eccSSepherosa Ziehau 40106c8d8eccSSepherosa Ziehau if (ifp->if_flags & IFF_PROMISC) 40116c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC); 40126c8d8eccSSepherosa Ziehau else 40136c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC); 40146c8d8eccSSepherosa Ziehau } 40156c8d8eccSSepherosa Ziehau 40166c8d8eccSSepherosa Ziehau static void 40176c8d8eccSSepherosa Ziehau bnx_dma_free(struct bnx_softc *sc) 40186c8d8eccSSepherosa Ziehau { 4019beedf5beSSepherosa Ziehau struct bnx_rx_std_ring *std = &sc->bnx_rx_std_ring; 40206c8d8eccSSepherosa Ziehau int i; 40216c8d8eccSSepherosa Ziehau 4022beedf5beSSepherosa Ziehau /* Destroy RX return rings */ 4023beedf5beSSepherosa Ziehau if (sc->bnx_rx_ret_ring != NULL) { 4024beedf5beSSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) 4025beedf5beSSepherosa Ziehau bnx_destroy_rx_ret_ring(&sc->bnx_rx_ret_ring[i]); 4026beedf5beSSepherosa Ziehau kfree(sc->bnx_rx_ret_ring, M_DEVBUF); 4027beedf5beSSepherosa Ziehau } 4028beedf5beSSepherosa Ziehau 40296c8d8eccSSepherosa Ziehau /* Destroy RX mbuf DMA stuffs. */ 4030beedf5beSSepherosa Ziehau if (std->bnx_rx_mtag != NULL) { 40316c8d8eccSSepherosa Ziehau for (i = 0; i < BGE_STD_RX_RING_CNT; i++) { 4032beedf5beSSepherosa Ziehau KKASSERT(std->bnx_rx_std_buf[i].bnx_rx_mbuf == NULL); 4033beedf5beSSepherosa Ziehau bus_dmamap_destroy(std->bnx_rx_mtag, 4034beedf5beSSepherosa Ziehau std->bnx_rx_std_buf[i].bnx_rx_dmamap); 40356c8d8eccSSepherosa Ziehau } 4036beedf5beSSepherosa Ziehau bus_dma_tag_destroy(std->bnx_rx_mtag); 40376c8d8eccSSepherosa Ziehau } 40386c8d8eccSSepherosa Ziehau 4039beedf5beSSepherosa Ziehau /* Destroy standard RX ring */ 4040beedf5beSSepherosa Ziehau bnx_dma_block_free(std->bnx_rx_std_ring_tag, 4041beedf5beSSepherosa Ziehau std->bnx_rx_std_ring_map, std->bnx_rx_std_ring); 4042beedf5beSSepherosa Ziehau 404333a04907SSepherosa Ziehau /* Destroy TX rings */ 404433a04907SSepherosa Ziehau if (sc->bnx_tx_ring != NULL) { 404533a04907SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 404633a04907SSepherosa Ziehau bnx_destroy_tx_ring(&sc->bnx_tx_ring[i]); 404733a04907SSepherosa Ziehau kfree(sc->bnx_tx_ring, M_DEVBUF); 40486c8d8eccSSepherosa Ziehau } 40496c8d8eccSSepherosa Ziehau 40506c8d8eccSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) 40516c8d8eccSSepherosa Ziehau bnx_free_jumbo_mem(sc); 40526c8d8eccSSepherosa Ziehau 40530a806e3aSSepherosa Ziehau /* Destroy status blocks */ 40540a806e3aSSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 40550a806e3aSSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 40560a806e3aSSepherosa Ziehau 40570a806e3aSSepherosa Ziehau bnx_dma_block_free(intr->bnx_status_tag, 40580a806e3aSSepherosa Ziehau intr->bnx_status_map, intr->bnx_status_block); 40590a806e3aSSepherosa Ziehau } 40606c8d8eccSSepherosa Ziehau 40616c8d8eccSSepherosa Ziehau /* Destroy the parent tag */ 40626c8d8eccSSepherosa Ziehau if (sc->bnx_cdata.bnx_parent_tag != NULL) 40636c8d8eccSSepherosa Ziehau bus_dma_tag_destroy(sc->bnx_cdata.bnx_parent_tag); 40646c8d8eccSSepherosa Ziehau } 40656c8d8eccSSepherosa Ziehau 40666c8d8eccSSepherosa Ziehau static int 4067beedf5beSSepherosa Ziehau bnx_dma_alloc(device_t dev) 40686c8d8eccSSepherosa Ziehau { 4069beedf5beSSepherosa Ziehau struct bnx_softc *sc = device_get_softc(dev); 4070beedf5beSSepherosa Ziehau struct bnx_rx_std_ring *std = &sc->bnx_rx_std_ring; 4071ac2936fdSSepherosa Ziehau int i, error, mbx; 40726c8d8eccSSepherosa Ziehau 40736c8d8eccSSepherosa Ziehau /* 40746c8d8eccSSepherosa Ziehau * Allocate the parent bus DMA tag appropriate for PCI. 40756c8d8eccSSepherosa Ziehau * 40766c8d8eccSSepherosa Ziehau * All of the NetExtreme/NetLink controllers have 4GB boundary 40776c8d8eccSSepherosa Ziehau * DMA bug. 40786c8d8eccSSepherosa Ziehau * Whenever an address crosses a multiple of the 4GB boundary 40796c8d8eccSSepherosa Ziehau * (including 4GB, 8Gb, 12Gb, etc.) and makes the transition 40806c8d8eccSSepherosa Ziehau * from 0xX_FFFF_FFFF to 0x(X+1)_0000_0000 an internal DMA 40816c8d8eccSSepherosa Ziehau * state machine will lockup and cause the device to hang. 40826c8d8eccSSepherosa Ziehau */ 40836c8d8eccSSepherosa Ziehau error = bus_dma_tag_create(NULL, 1, BGE_DMA_BOUNDARY_4G, 4084beedf5beSSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 4085beedf5beSSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 40866c8d8eccSSepherosa Ziehau 0, &sc->bnx_cdata.bnx_parent_tag); 40876c8d8eccSSepherosa Ziehau if (error) { 4088beedf5beSSepherosa Ziehau device_printf(dev, "could not create parent DMA tag\n"); 40896c8d8eccSSepherosa Ziehau return error; 40906c8d8eccSSepherosa Ziehau } 40916c8d8eccSSepherosa Ziehau 40926c8d8eccSSepherosa Ziehau /* 40930a806e3aSSepherosa Ziehau * Create DMA stuffs for status blocks. 40946c8d8eccSSepherosa Ziehau */ 40950a806e3aSSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 40960a806e3aSSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 40970a806e3aSSepherosa Ziehau 4098695a8586SSepherosa Ziehau error = bnx_dma_block_alloc(sc, 4099695a8586SSepherosa Ziehau __VM_CACHELINE_ALIGN(BGE_STATUS_BLK_SZ), 41000a806e3aSSepherosa Ziehau &intr->bnx_status_tag, &intr->bnx_status_map, 41010a806e3aSSepherosa Ziehau (void *)&intr->bnx_status_block, 41020a806e3aSSepherosa Ziehau &intr->bnx_status_block_paddr); 41036c8d8eccSSepherosa Ziehau if (error) { 41040a806e3aSSepherosa Ziehau device_printf(dev, 41050a806e3aSSepherosa Ziehau "could not create %dth status block\n", i); 41066c8d8eccSSepherosa Ziehau return error; 41076c8d8eccSSepherosa Ziehau } 41080a806e3aSSepherosa Ziehau } 4109695a8586SSepherosa Ziehau sc->bnx_hw_status = &sc->bnx_intr_data[0].bnx_status_block->bge_status; 4110695a8586SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_STATUS_HASTAG) { 4111695a8586SSepherosa Ziehau sc->bnx_hw_status_tag = 4112695a8586SSepherosa Ziehau &sc->bnx_intr_data[0].bnx_status_block->bge_status_tag; 4113695a8586SSepherosa Ziehau } 41146c8d8eccSSepherosa Ziehau 4115beedf5beSSepherosa Ziehau /* 4116beedf5beSSepherosa Ziehau * Create DMA tag and maps for RX mbufs. 4117beedf5beSSepherosa Ziehau */ 4118beedf5beSSepherosa Ziehau std->bnx_sc = sc; 4119329f9016SSepherosa Ziehau lwkt_serialize_init(&std->bnx_rx_std_serialize); 4120beedf5beSSepherosa Ziehau error = bus_dma_tag_create(sc->bnx_cdata.bnx_parent_tag, 1, 0, 4121beedf5beSSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 4122beedf5beSSepherosa Ziehau NULL, NULL, MCLBYTES, 1, MCLBYTES, 4123beedf5beSSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK, &std->bnx_rx_mtag); 4124beedf5beSSepherosa Ziehau if (error) { 4125beedf5beSSepherosa Ziehau device_printf(dev, "could not create RX mbuf DMA tag\n"); 4126beedf5beSSepherosa Ziehau return error; 4127beedf5beSSepherosa Ziehau } 4128beedf5beSSepherosa Ziehau 4129beedf5beSSepherosa Ziehau for (i = 0; i < BGE_STD_RX_RING_CNT; ++i) { 4130beedf5beSSepherosa Ziehau error = bus_dmamap_create(std->bnx_rx_mtag, BUS_DMA_WAITOK, 4131beedf5beSSepherosa Ziehau &std->bnx_rx_std_buf[i].bnx_rx_dmamap); 4132beedf5beSSepherosa Ziehau if (error) { 4133beedf5beSSepherosa Ziehau int j; 4134beedf5beSSepherosa Ziehau 4135beedf5beSSepherosa Ziehau for (j = 0; j < i; ++j) { 4136beedf5beSSepherosa Ziehau bus_dmamap_destroy(std->bnx_rx_mtag, 4137beedf5beSSepherosa Ziehau std->bnx_rx_std_buf[j].bnx_rx_dmamap); 4138beedf5beSSepherosa Ziehau } 4139beedf5beSSepherosa Ziehau bus_dma_tag_destroy(std->bnx_rx_mtag); 4140beedf5beSSepherosa Ziehau std->bnx_rx_mtag = NULL; 4141beedf5beSSepherosa Ziehau 4142beedf5beSSepherosa Ziehau device_printf(dev, 4143beedf5beSSepherosa Ziehau "could not create %dth RX mbuf DMA map\n", i); 4144beedf5beSSepherosa Ziehau return error; 4145beedf5beSSepherosa Ziehau } 4146beedf5beSSepherosa Ziehau } 4147beedf5beSSepherosa Ziehau 4148beedf5beSSepherosa Ziehau /* 4149beedf5beSSepherosa Ziehau * Create DMA stuffs for standard RX ring. 4150beedf5beSSepherosa Ziehau */ 4151beedf5beSSepherosa Ziehau error = bnx_dma_block_alloc(sc, BGE_STD_RX_RING_SZ, 4152beedf5beSSepherosa Ziehau &std->bnx_rx_std_ring_tag, 4153beedf5beSSepherosa Ziehau &std->bnx_rx_std_ring_map, 4154beedf5beSSepherosa Ziehau (void *)&std->bnx_rx_std_ring, 4155beedf5beSSepherosa Ziehau &std->bnx_rx_std_ring_paddr); 4156beedf5beSSepherosa Ziehau if (error) { 4157beedf5beSSepherosa Ziehau device_printf(dev, "could not create std RX ring\n"); 4158beedf5beSSepherosa Ziehau return error; 4159beedf5beSSepherosa Ziehau } 4160beedf5beSSepherosa Ziehau 4161beedf5beSSepherosa Ziehau /* 4162beedf5beSSepherosa Ziehau * Create RX return rings 4163beedf5beSSepherosa Ziehau */ 4164ac2936fdSSepherosa Ziehau mbx = BGE_MBX_RX_CONS0_LO; 4165beedf5beSSepherosa Ziehau sc->bnx_rx_ret_ring = kmalloc_cachealign( 4166beedf5beSSepherosa Ziehau sizeof(struct bnx_rx_ret_ring) * sc->bnx_rx_retcnt, M_DEVBUF, 4167beedf5beSSepherosa Ziehau M_WAITOK | M_ZERO); 4168beedf5beSSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 4169beedf5beSSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[i]; 41700a806e3aSSepherosa Ziehau struct bnx_intr_data *intr; 4171beedf5beSSepherosa Ziehau 4172beedf5beSSepherosa Ziehau ret->bnx_sc = sc; 4173beedf5beSSepherosa Ziehau ret->bnx_std = std; 4174ac2936fdSSepherosa Ziehau ret->bnx_rx_mbx = mbx; 4175841cdf08SSepherosa Ziehau ret->bnx_rx_cntmax = (BGE_STD_RX_RING_CNT / 4) / 4176841cdf08SSepherosa Ziehau sc->bnx_rx_retcnt; 4177841cdf08SSepherosa Ziehau ret->bnx_rx_mask = 1 << i; 41783a16b7b8SSepherosa Ziehau 4179695a8586SSepherosa Ziehau if (!BNX_RSS_ENABLED(sc)) { 41800a806e3aSSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 41810a806e3aSSepherosa Ziehau } else { 41820a806e3aSSepherosa Ziehau KKASSERT(i + 1 < sc->bnx_intr_cnt); 41830a806e3aSSepherosa Ziehau intr = &sc->bnx_intr_data[i + 1]; 41840a806e3aSSepherosa Ziehau } 41850a806e3aSSepherosa Ziehau 4186695a8586SSepherosa Ziehau if (i == 0) { 41873a16b7b8SSepherosa Ziehau ret->bnx_rx_considx = 41880a806e3aSSepherosa Ziehau &intr->bnx_status_block->bge_idx[0].bge_rx_prod_idx; 4189695a8586SSepherosa Ziehau } else if (i == 1) { 4190695a8586SSepherosa Ziehau ret->bnx_rx_considx = 4191695a8586SSepherosa Ziehau &intr->bnx_status_block->bge_rx_jumbo_cons_idx; 4192695a8586SSepherosa Ziehau } else if (i == 2) { 4193695a8586SSepherosa Ziehau ret->bnx_rx_considx = 4194695a8586SSepherosa Ziehau &intr->bnx_status_block->bge_rsvd1; 4195695a8586SSepherosa Ziehau } else if (i == 3) { 4196695a8586SSepherosa Ziehau ret->bnx_rx_considx = 4197695a8586SSepherosa Ziehau &intr->bnx_status_block->bge_rx_mini_cons_idx; 4198695a8586SSepherosa Ziehau } else { 4199695a8586SSepherosa Ziehau panic("unknown RX return ring %d\n", i); 4200695a8586SSepherosa Ziehau } 42014fa38985SSepherosa Ziehau ret->bnx_hw_status_tag = 42020a806e3aSSepherosa Ziehau &intr->bnx_status_block->bge_status_tag; 42033a16b7b8SSepherosa Ziehau 4204beedf5beSSepherosa Ziehau error = bnx_create_rx_ret_ring(ret); 4205beedf5beSSepherosa Ziehau if (error) { 4206beedf5beSSepherosa Ziehau device_printf(dev, 4207beedf5beSSepherosa Ziehau "could not create %dth RX ret ring\n", i); 4208beedf5beSSepherosa Ziehau return error; 4209beedf5beSSepherosa Ziehau } 4210ac2936fdSSepherosa Ziehau mbx += 8; 4211beedf5beSSepherosa Ziehau } 4212beedf5beSSepherosa Ziehau 4213beedf5beSSepherosa Ziehau /* 4214beedf5beSSepherosa Ziehau * Create TX rings 4215beedf5beSSepherosa Ziehau */ 421633a04907SSepherosa Ziehau sc->bnx_tx_ring = kmalloc_cachealign( 421733a04907SSepherosa Ziehau sizeof(struct bnx_tx_ring) * sc->bnx_tx_ringcnt, M_DEVBUF, 421833a04907SSepherosa Ziehau M_WAITOK | M_ZERO); 421933a04907SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 422033a04907SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[i]; 42210a806e3aSSepherosa Ziehau struct bnx_intr_data *intr; 422233a04907SSepherosa Ziehau 422333a04907SSepherosa Ziehau txr->bnx_sc = sc; 42241c9d03f6SSepherosa Ziehau txr->bnx_tx_mbx = bnx_tx_mailbox[i]; 42258bd43d5dSSepherosa Ziehau 42260a806e3aSSepherosa Ziehau if (sc->bnx_tx_ringcnt == 1) { 42270a806e3aSSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 42280a806e3aSSepherosa Ziehau } else { 42290a806e3aSSepherosa Ziehau KKASSERT(i + 1 < sc->bnx_intr_cnt); 42300a806e3aSSepherosa Ziehau intr = &sc->bnx_intr_data[i + 1]; 42310a806e3aSSepherosa Ziehau } 42320a806e3aSSepherosa Ziehau 4233695a8586SSepherosa Ziehau if ((sc->bnx_flags & BNX_FLAG_RXTX_BUNDLE) == 0) { 4234695a8586SSepherosa Ziehau txr->bnx_hw_status_tag = 4235695a8586SSepherosa Ziehau &intr->bnx_status_block->bge_status_tag; 4236695a8586SSepherosa Ziehau } 42373a16b7b8SSepherosa Ziehau txr->bnx_tx_considx = 42380a806e3aSSepherosa Ziehau &intr->bnx_status_block->bge_idx[0].bge_tx_cons_idx; 42393a16b7b8SSepherosa Ziehau 424033a04907SSepherosa Ziehau error = bnx_create_tx_ring(txr); 424133a04907SSepherosa Ziehau if (error) { 4242beedf5beSSepherosa Ziehau device_printf(dev, 4243beedf5beSSepherosa Ziehau "could not create %dth TX ring\n", i); 4244beedf5beSSepherosa Ziehau return error; 4245beedf5beSSepherosa Ziehau } 4246beedf5beSSepherosa Ziehau } 4247beedf5beSSepherosa Ziehau 4248beedf5beSSepherosa Ziehau /* 4249beedf5beSSepherosa Ziehau * Create jumbo buffer pool. 4250beedf5beSSepherosa Ziehau */ 4251beedf5beSSepherosa Ziehau if (BNX_IS_JUMBO_CAPABLE(sc)) { 4252beedf5beSSepherosa Ziehau error = bnx_alloc_jumbo_mem(sc); 4253beedf5beSSepherosa Ziehau if (error) { 4254beedf5beSSepherosa Ziehau device_printf(dev, 4255beedf5beSSepherosa Ziehau "could not create jumbo buffer pool\n"); 425633a04907SSepherosa Ziehau return error; 425733a04907SSepherosa Ziehau } 425833a04907SSepherosa Ziehau } 425933a04907SSepherosa Ziehau 42606c8d8eccSSepherosa Ziehau return 0; 42616c8d8eccSSepherosa Ziehau } 42626c8d8eccSSepherosa Ziehau 42636c8d8eccSSepherosa Ziehau static int 42646c8d8eccSSepherosa Ziehau bnx_dma_block_alloc(struct bnx_softc *sc, bus_size_t size, bus_dma_tag_t *tag, 42656c8d8eccSSepherosa Ziehau bus_dmamap_t *map, void **addr, bus_addr_t *paddr) 42666c8d8eccSSepherosa Ziehau { 42676c8d8eccSSepherosa Ziehau bus_dmamem_t dmem; 42686c8d8eccSSepherosa Ziehau int error; 42696c8d8eccSSepherosa Ziehau 42706c8d8eccSSepherosa Ziehau error = bus_dmamem_coherent(sc->bnx_cdata.bnx_parent_tag, PAGE_SIZE, 0, 42716c8d8eccSSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 42726c8d8eccSSepherosa Ziehau size, BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmem); 42736c8d8eccSSepherosa Ziehau if (error) 42746c8d8eccSSepherosa Ziehau return error; 42756c8d8eccSSepherosa Ziehau 42766c8d8eccSSepherosa Ziehau *tag = dmem.dmem_tag; 42776c8d8eccSSepherosa Ziehau *map = dmem.dmem_map; 42786c8d8eccSSepherosa Ziehau *addr = dmem.dmem_addr; 42796c8d8eccSSepherosa Ziehau *paddr = dmem.dmem_busaddr; 42806c8d8eccSSepherosa Ziehau 42816c8d8eccSSepherosa Ziehau return 0; 42826c8d8eccSSepherosa Ziehau } 42836c8d8eccSSepherosa Ziehau 42846c8d8eccSSepherosa Ziehau static void 42856c8d8eccSSepherosa Ziehau bnx_dma_block_free(bus_dma_tag_t tag, bus_dmamap_t map, void *addr) 42866c8d8eccSSepherosa Ziehau { 42876c8d8eccSSepherosa Ziehau if (tag != NULL) { 42886c8d8eccSSepherosa Ziehau bus_dmamap_unload(tag, map); 42896c8d8eccSSepherosa Ziehau bus_dmamem_free(tag, addr, map); 42906c8d8eccSSepherosa Ziehau bus_dma_tag_destroy(tag); 42916c8d8eccSSepherosa Ziehau } 42926c8d8eccSSepherosa Ziehau } 42936c8d8eccSSepherosa Ziehau 42946c8d8eccSSepherosa Ziehau static void 42956c8d8eccSSepherosa Ziehau bnx_tbi_link_upd(struct bnx_softc *sc, uint32_t status) 42966c8d8eccSSepherosa Ziehau { 42976c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 42986c8d8eccSSepherosa Ziehau 42996c8d8eccSSepherosa Ziehau #define PCS_ENCODE_ERR (BGE_MACSTAT_PORT_DECODE_ERROR|BGE_MACSTAT_MI_COMPLETE) 43006c8d8eccSSepherosa Ziehau 43016c8d8eccSSepherosa Ziehau /* 43026c8d8eccSSepherosa Ziehau * Sometimes PCS encoding errors are detected in 43036c8d8eccSSepherosa Ziehau * TBI mode (on fiber NICs), and for some reason 43046c8d8eccSSepherosa Ziehau * the chip will signal them as link changes. 43056c8d8eccSSepherosa Ziehau * If we get a link change event, but the 'PCS 43066c8d8eccSSepherosa Ziehau * encoding error' bit in the MAC status register 43076c8d8eccSSepherosa Ziehau * is set, don't bother doing a link check. 43086c8d8eccSSepherosa Ziehau * This avoids spurious "gigabit link up" messages 43096c8d8eccSSepherosa Ziehau * that sometimes appear on fiber NICs during 43106c8d8eccSSepherosa Ziehau * periods of heavy traffic. 43116c8d8eccSSepherosa Ziehau */ 43126c8d8eccSSepherosa Ziehau if (status & BGE_MACSTAT_TBI_PCS_SYNCHED) { 43136c8d8eccSSepherosa Ziehau if (!sc->bnx_link) { 43146c8d8eccSSepherosa Ziehau sc->bnx_link++; 43156c8d8eccSSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5704) { 43166c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, BGE_MAC_MODE, 43176c8d8eccSSepherosa Ziehau BGE_MACMODE_TBI_SEND_CFGS); 43184aa71e73SSepherosa Ziehau DELAY(40); 43196c8d8eccSSepherosa Ziehau } 43206c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, 0xFFFFFFFF); 43216c8d8eccSSepherosa Ziehau 43226c8d8eccSSepherosa Ziehau if (bootverbose) 43236c8d8eccSSepherosa Ziehau if_printf(ifp, "link UP\n"); 43246c8d8eccSSepherosa Ziehau 43256c8d8eccSSepherosa Ziehau ifp->if_link_state = LINK_STATE_UP; 43266c8d8eccSSepherosa Ziehau if_link_state_change(ifp); 43276c8d8eccSSepherosa Ziehau } 43286c8d8eccSSepherosa Ziehau } else if ((status & PCS_ENCODE_ERR) != PCS_ENCODE_ERR) { 43296c8d8eccSSepherosa Ziehau if (sc->bnx_link) { 43306c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 43316c8d8eccSSepherosa Ziehau 43326c8d8eccSSepherosa Ziehau if (bootverbose) 43336c8d8eccSSepherosa Ziehau if_printf(ifp, "link DOWN\n"); 43346c8d8eccSSepherosa Ziehau 43356c8d8eccSSepherosa Ziehau ifp->if_link_state = LINK_STATE_DOWN; 43366c8d8eccSSepherosa Ziehau if_link_state_change(ifp); 43376c8d8eccSSepherosa Ziehau } 43386c8d8eccSSepherosa Ziehau } 43396c8d8eccSSepherosa Ziehau 43406c8d8eccSSepherosa Ziehau #undef PCS_ENCODE_ERR 43416c8d8eccSSepherosa Ziehau 43426c8d8eccSSepherosa Ziehau /* Clear the attention. */ 43436c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED | 43446c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED | BGE_MACSTAT_MI_COMPLETE | 43456c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 43466c8d8eccSSepherosa Ziehau } 43476c8d8eccSSepherosa Ziehau 43486c8d8eccSSepherosa Ziehau static void 43496c8d8eccSSepherosa Ziehau bnx_copper_link_upd(struct bnx_softc *sc, uint32_t status __unused) 43506c8d8eccSSepherosa Ziehau { 43516c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 43526c8d8eccSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->bnx_miibus); 43536c8d8eccSSepherosa Ziehau 43546c8d8eccSSepherosa Ziehau mii_pollstat(mii); 43556c8d8eccSSepherosa Ziehau bnx_miibus_statchg(sc->bnx_dev); 43566c8d8eccSSepherosa Ziehau 43576c8d8eccSSepherosa Ziehau if (bootverbose) { 43586c8d8eccSSepherosa Ziehau if (sc->bnx_link) 43596c8d8eccSSepherosa Ziehau if_printf(ifp, "link UP\n"); 43606c8d8eccSSepherosa Ziehau else 43616c8d8eccSSepherosa Ziehau if_printf(ifp, "link DOWN\n"); 43626c8d8eccSSepherosa Ziehau } 43636c8d8eccSSepherosa Ziehau 43646c8d8eccSSepherosa Ziehau /* Clear the attention. */ 43656c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED | 43666c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED | BGE_MACSTAT_MI_COMPLETE | 43676c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 43686c8d8eccSSepherosa Ziehau } 43696c8d8eccSSepherosa Ziehau 43706c8d8eccSSepherosa Ziehau static void 43716c8d8eccSSepherosa Ziehau bnx_autopoll_link_upd(struct bnx_softc *sc, uint32_t status __unused) 43726c8d8eccSSepherosa Ziehau { 43736c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 43746c8d8eccSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->bnx_miibus); 43756c8d8eccSSepherosa Ziehau 43766c8d8eccSSepherosa Ziehau mii_pollstat(mii); 43776c8d8eccSSepherosa Ziehau 43786c8d8eccSSepherosa Ziehau if (!sc->bnx_link && 43796c8d8eccSSepherosa Ziehau (mii->mii_media_status & IFM_ACTIVE) && 43806c8d8eccSSepherosa Ziehau IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 43816c8d8eccSSepherosa Ziehau sc->bnx_link++; 43826c8d8eccSSepherosa Ziehau if (bootverbose) 43836c8d8eccSSepherosa Ziehau if_printf(ifp, "link UP\n"); 43846c8d8eccSSepherosa Ziehau } else if (sc->bnx_link && 43856c8d8eccSSepherosa Ziehau (!(mii->mii_media_status & IFM_ACTIVE) || 43866c8d8eccSSepherosa Ziehau IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE)) { 43876c8d8eccSSepherosa Ziehau sc->bnx_link = 0; 43886c8d8eccSSepherosa Ziehau if (bootverbose) 43896c8d8eccSSepherosa Ziehau if_printf(ifp, "link DOWN\n"); 43906c8d8eccSSepherosa Ziehau } 43916c8d8eccSSepherosa Ziehau 43926c8d8eccSSepherosa Ziehau /* Clear the attention. */ 43936c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED | 43946c8d8eccSSepherosa Ziehau BGE_MACSTAT_CFG_CHANGED | BGE_MACSTAT_MI_COMPLETE | 43956c8d8eccSSepherosa Ziehau BGE_MACSTAT_LINK_CHANGED); 43966c8d8eccSSepherosa Ziehau } 43976c8d8eccSSepherosa Ziehau 43986c8d8eccSSepherosa Ziehau static int 43996c8d8eccSSepherosa Ziehau bnx_sysctl_rx_coal_ticks(SYSCTL_HANDLER_ARGS) 44006c8d8eccSSepherosa Ziehau { 44016c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44026c8d8eccSSepherosa Ziehau 44036c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44046c8d8eccSSepherosa Ziehau &sc->bnx_rx_coal_ticks, 44056c8d8eccSSepherosa Ziehau BNX_RX_COAL_TICKS_MIN, BNX_RX_COAL_TICKS_MAX, 44066c8d8eccSSepherosa Ziehau BNX_RX_COAL_TICKS_CHG); 44076c8d8eccSSepherosa Ziehau } 44086c8d8eccSSepherosa Ziehau 44096c8d8eccSSepherosa Ziehau static int 44106c8d8eccSSepherosa Ziehau bnx_sysctl_tx_coal_ticks(SYSCTL_HANDLER_ARGS) 44116c8d8eccSSepherosa Ziehau { 44126c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44136c8d8eccSSepherosa Ziehau 44146c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44156c8d8eccSSepherosa Ziehau &sc->bnx_tx_coal_ticks, 44166c8d8eccSSepherosa Ziehau BNX_TX_COAL_TICKS_MIN, BNX_TX_COAL_TICKS_MAX, 44176c8d8eccSSepherosa Ziehau BNX_TX_COAL_TICKS_CHG); 44186c8d8eccSSepherosa Ziehau } 44196c8d8eccSSepherosa Ziehau 44206c8d8eccSSepherosa Ziehau static int 44216c8d8eccSSepherosa Ziehau bnx_sysctl_rx_coal_bds(SYSCTL_HANDLER_ARGS) 44226c8d8eccSSepherosa Ziehau { 44236c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44246c8d8eccSSepherosa Ziehau 44256c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44266c8d8eccSSepherosa Ziehau &sc->bnx_rx_coal_bds, 44276c8d8eccSSepherosa Ziehau BNX_RX_COAL_BDS_MIN, BNX_RX_COAL_BDS_MAX, 44286c8d8eccSSepherosa Ziehau BNX_RX_COAL_BDS_CHG); 44296c8d8eccSSepherosa Ziehau } 44306c8d8eccSSepherosa Ziehau 44316c8d8eccSSepherosa Ziehau static int 4432a86cc105SSepherosa Ziehau bnx_sysctl_rx_coal_bds_poll(SYSCTL_HANDLER_ARGS) 4433a86cc105SSepherosa Ziehau { 4434a86cc105SSepherosa Ziehau struct bnx_softc *sc = arg1; 4435a86cc105SSepherosa Ziehau 4436a86cc105SSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 4437a86cc105SSepherosa Ziehau &sc->bnx_rx_coal_bds_poll, 4438a86cc105SSepherosa Ziehau BNX_RX_COAL_BDS_MIN, BNX_RX_COAL_BDS_MAX, 4439a86cc105SSepherosa Ziehau BNX_RX_COAL_BDS_CHG); 4440a86cc105SSepherosa Ziehau } 4441a86cc105SSepherosa Ziehau 4442a86cc105SSepherosa Ziehau static int 44436c8d8eccSSepherosa Ziehau bnx_sysctl_tx_coal_bds(SYSCTL_HANDLER_ARGS) 44446c8d8eccSSepherosa Ziehau { 44456c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44466c8d8eccSSepherosa Ziehau 44476c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44486c8d8eccSSepherosa Ziehau &sc->bnx_tx_coal_bds, 44496c8d8eccSSepherosa Ziehau BNX_TX_COAL_BDS_MIN, BNX_TX_COAL_BDS_MAX, 44506c8d8eccSSepherosa Ziehau BNX_TX_COAL_BDS_CHG); 44516c8d8eccSSepherosa Ziehau } 44526c8d8eccSSepherosa Ziehau 44536c8d8eccSSepherosa Ziehau static int 445427357d84SSepherosa Ziehau bnx_sysctl_tx_coal_bds_poll(SYSCTL_HANDLER_ARGS) 445527357d84SSepherosa Ziehau { 445627357d84SSepherosa Ziehau struct bnx_softc *sc = arg1; 445727357d84SSepherosa Ziehau 445827357d84SSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 445927357d84SSepherosa Ziehau &sc->bnx_tx_coal_bds_poll, 446027357d84SSepherosa Ziehau BNX_TX_COAL_BDS_MIN, BNX_TX_COAL_BDS_MAX, 446127357d84SSepherosa Ziehau BNX_TX_COAL_BDS_CHG); 446227357d84SSepherosa Ziehau } 446327357d84SSepherosa Ziehau 446427357d84SSepherosa Ziehau static int 44656c8d8eccSSepherosa Ziehau bnx_sysctl_rx_coal_bds_int(SYSCTL_HANDLER_ARGS) 44666c8d8eccSSepherosa Ziehau { 44676c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44686c8d8eccSSepherosa Ziehau 44696c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44706c8d8eccSSepherosa Ziehau &sc->bnx_rx_coal_bds_int, 44716c8d8eccSSepherosa Ziehau BNX_RX_COAL_BDS_MIN, BNX_RX_COAL_BDS_MAX, 44726c8d8eccSSepherosa Ziehau BNX_RX_COAL_BDS_INT_CHG); 44736c8d8eccSSepherosa Ziehau } 44746c8d8eccSSepherosa Ziehau 44756c8d8eccSSepherosa Ziehau static int 44766c8d8eccSSepherosa Ziehau bnx_sysctl_tx_coal_bds_int(SYSCTL_HANDLER_ARGS) 44776c8d8eccSSepherosa Ziehau { 44786c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44796c8d8eccSSepherosa Ziehau 44806c8d8eccSSepherosa Ziehau return bnx_sysctl_coal_chg(oidp, arg1, arg2, req, 44816c8d8eccSSepherosa Ziehau &sc->bnx_tx_coal_bds_int, 44826c8d8eccSSepherosa Ziehau BNX_TX_COAL_BDS_MIN, BNX_TX_COAL_BDS_MAX, 44836c8d8eccSSepherosa Ziehau BNX_TX_COAL_BDS_INT_CHG); 44846c8d8eccSSepherosa Ziehau } 44856c8d8eccSSepherosa Ziehau 44866c8d8eccSSepherosa Ziehau static int 44876c8d8eccSSepherosa Ziehau bnx_sysctl_coal_chg(SYSCTL_HANDLER_ARGS, uint32_t *coal, 44886c8d8eccSSepherosa Ziehau int coal_min, int coal_max, uint32_t coal_chg_mask) 44896c8d8eccSSepherosa Ziehau { 44906c8d8eccSSepherosa Ziehau struct bnx_softc *sc = arg1; 44916c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 44926c8d8eccSSepherosa Ziehau int error = 0, v; 44936c8d8eccSSepherosa Ziehau 4494329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 44956c8d8eccSSepherosa Ziehau 44966c8d8eccSSepherosa Ziehau v = *coal; 44976c8d8eccSSepherosa Ziehau error = sysctl_handle_int(oidp, &v, 0, req); 44986c8d8eccSSepherosa Ziehau if (!error && req->newptr != NULL) { 44996c8d8eccSSepherosa Ziehau if (v < coal_min || v > coal_max) { 45006c8d8eccSSepherosa Ziehau error = EINVAL; 45016c8d8eccSSepherosa Ziehau } else { 45026c8d8eccSSepherosa Ziehau *coal = v; 45036c8d8eccSSepherosa Ziehau sc->bnx_coal_chg |= coal_chg_mask; 4504f5014362SSepherosa Ziehau 4505f5014362SSepherosa Ziehau /* Commit changes */ 4506f5014362SSepherosa Ziehau bnx_coal_change(sc); 45076c8d8eccSSepherosa Ziehau } 45086c8d8eccSSepherosa Ziehau } 45096c8d8eccSSepherosa Ziehau 4510329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 45116c8d8eccSSepherosa Ziehau return error; 45126c8d8eccSSepherosa Ziehau } 45136c8d8eccSSepherosa Ziehau 45146c8d8eccSSepherosa Ziehau static void 45156c8d8eccSSepherosa Ziehau bnx_coal_change(struct bnx_softc *sc) 45166c8d8eccSSepherosa Ziehau { 45176c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 4518695a8586SSepherosa Ziehau int i; 45196c8d8eccSSepherosa Ziehau 4520329f9016SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 45216c8d8eccSSepherosa Ziehau 45226c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_RX_COAL_TICKS_CHG) { 4523695a8586SSepherosa Ziehau if (sc->bnx_rx_retcnt == 1) { 45246c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, 45256c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_ticks); 4526695a8586SSepherosa Ziehau i = 0; 4527695a8586SSepherosa Ziehau } else { 4528695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, 0); 4529695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 4530695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_COAL_TICKS + 4531695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 4532695a8586SSepherosa Ziehau sc->bnx_rx_coal_ticks); 4533695a8586SSepherosa Ziehau } 4534695a8586SSepherosa Ziehau } 4535695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4536695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_COAL_TICKS + 4537695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4538695a8586SSepherosa Ziehau } 45396c8d8eccSSepherosa Ziehau if (bootverbose) { 45406c8d8eccSSepherosa Ziehau if_printf(ifp, "rx_coal_ticks -> %u\n", 45416c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_ticks); 45426c8d8eccSSepherosa Ziehau } 45436c8d8eccSSepherosa Ziehau } 45446c8d8eccSSepherosa Ziehau 45456c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_TX_COAL_TICKS_CHG) { 4546695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt == 1) { 45476c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS, 45486c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_ticks); 4549695a8586SSepherosa Ziehau i = 0; 4550695a8586SSepherosa Ziehau } else { 4551695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS, 0); 4552695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 4553695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_COAL_TICKS + 4554695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 4555695a8586SSepherosa Ziehau sc->bnx_tx_coal_ticks); 4556695a8586SSepherosa Ziehau } 4557695a8586SSepherosa Ziehau } 4558695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4559695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_COAL_TICKS + 4560695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4561695a8586SSepherosa Ziehau } 45626c8d8eccSSepherosa Ziehau if (bootverbose) { 45636c8d8eccSSepherosa Ziehau if_printf(ifp, "tx_coal_ticks -> %u\n", 45646c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_ticks); 45656c8d8eccSSepherosa Ziehau } 45666c8d8eccSSepherosa Ziehau } 45676c8d8eccSSepherosa Ziehau 45686c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_RX_COAL_BDS_CHG) { 4569a86cc105SSepherosa Ziehau uint32_t rx_coal_bds; 4570a86cc105SSepherosa Ziehau 4571a86cc105SSepherosa Ziehau if (ifp->if_flags & IFF_NPOLLING) 4572a86cc105SSepherosa Ziehau rx_coal_bds = sc->bnx_rx_coal_bds_poll; 4573a86cc105SSepherosa Ziehau else 4574a86cc105SSepherosa Ziehau rx_coal_bds = sc->bnx_rx_coal_bds; 4575a86cc105SSepherosa Ziehau 4576695a8586SSepherosa Ziehau if (sc->bnx_rx_retcnt == 1) { 4577a86cc105SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, rx_coal_bds); 4578695a8586SSepherosa Ziehau i = 0; 4579695a8586SSepherosa Ziehau } else { 4580695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, 0); 4581695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 4582695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_MAX_COAL_BDS + 4583a86cc105SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), rx_coal_bds); 4584695a8586SSepherosa Ziehau } 4585695a8586SSepherosa Ziehau } 4586695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4587695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_MAX_COAL_BDS + 4588695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4589695a8586SSepherosa Ziehau } 45906c8d8eccSSepherosa Ziehau if (bootverbose) { 4591a86cc105SSepherosa Ziehau if_printf(ifp, "%srx_coal_bds -> %u\n", 4592a86cc105SSepherosa Ziehau (ifp->if_flags & IFF_NPOLLING) ? "polling " : "", 4593a86cc105SSepherosa Ziehau rx_coal_bds); 45946c8d8eccSSepherosa Ziehau } 45956c8d8eccSSepherosa Ziehau } 45966c8d8eccSSepherosa Ziehau 45976c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_TX_COAL_BDS_CHG) { 459827357d84SSepherosa Ziehau uint32_t tx_coal_bds; 459927357d84SSepherosa Ziehau 460027357d84SSepherosa Ziehau if (ifp->if_flags & IFF_NPOLLING) 460127357d84SSepherosa Ziehau tx_coal_bds = sc->bnx_tx_coal_bds_poll; 460227357d84SSepherosa Ziehau else 460327357d84SSepherosa Ziehau tx_coal_bds = sc->bnx_tx_coal_bds; 460427357d84SSepherosa Ziehau 4605695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt == 1) { 460627357d84SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS, tx_coal_bds); 4607695a8586SSepherosa Ziehau i = 0; 4608695a8586SSepherosa Ziehau } else { 4609695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS, 0); 4610695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 4611695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_MAX_COAL_BDS + 461227357d84SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), tx_coal_bds); 4613695a8586SSepherosa Ziehau } 4614695a8586SSepherosa Ziehau } 4615695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4616695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_MAX_COAL_BDS + 4617695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4618695a8586SSepherosa Ziehau } 46196c8d8eccSSepherosa Ziehau if (bootverbose) { 462027357d84SSepherosa Ziehau if_printf(ifp, "%stx_coal_bds -> %u\n", 462127357d84SSepherosa Ziehau (ifp->if_flags & IFF_NPOLLING) ? "polling " : "", 462227357d84SSepherosa Ziehau tx_coal_bds); 46236c8d8eccSSepherosa Ziehau } 46246c8d8eccSSepherosa Ziehau } 46256c8d8eccSSepherosa Ziehau 46266c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_RX_COAL_BDS_INT_CHG) { 4627695a8586SSepherosa Ziehau if (sc->bnx_rx_retcnt == 1) { 46286c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 46296c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_bds_int); 4630695a8586SSepherosa Ziehau i = 0; 4631695a8586SSepherosa Ziehau } else { 4632695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 0); 4633695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_rx_retcnt; ++i) { 4634695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_MAX_COAL_BDS_INT + 4635695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 4636695a8586SSepherosa Ziehau sc->bnx_rx_coal_bds_int); 4637695a8586SSepherosa Ziehau } 4638695a8586SSepherosa Ziehau } 4639695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4640695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_RX_MAX_COAL_BDS_INT + 4641695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4642695a8586SSepherosa Ziehau } 46436c8d8eccSSepherosa Ziehau if (bootverbose) { 46446c8d8eccSSepherosa Ziehau if_printf(ifp, "rx_coal_bds_int -> %u\n", 46456c8d8eccSSepherosa Ziehau sc->bnx_rx_coal_bds_int); 46466c8d8eccSSepherosa Ziehau } 46476c8d8eccSSepherosa Ziehau } 46486c8d8eccSSepherosa Ziehau 46496c8d8eccSSepherosa Ziehau if (sc->bnx_coal_chg & BNX_TX_COAL_BDS_INT_CHG) { 4650695a8586SSepherosa Ziehau if (sc->bnx_tx_ringcnt == 1) { 46516c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 46526c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_bds_int); 4653695a8586SSepherosa Ziehau i = 0; 4654695a8586SSepherosa Ziehau } else { 4655695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 0); 4656695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 4657695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_MAX_COAL_BDS_INT + 4658695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 4659695a8586SSepherosa Ziehau sc->bnx_tx_coal_bds_int); 4660695a8586SSepherosa Ziehau } 4661695a8586SSepherosa Ziehau } 4662695a8586SSepherosa Ziehau for (; i < BNX_INTR_MAX - 1; ++i) { 4663695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_VEC1_TX_MAX_COAL_BDS_INT + 4664695a8586SSepherosa Ziehau (i * BGE_VEC_COALSET_SIZE), 0); 4665695a8586SSepherosa Ziehau } 46666c8d8eccSSepherosa Ziehau if (bootverbose) { 46676c8d8eccSSepherosa Ziehau if_printf(ifp, "tx_coal_bds_int -> %u\n", 46686c8d8eccSSepherosa Ziehau sc->bnx_tx_coal_bds_int); 46696c8d8eccSSepherosa Ziehau } 46706c8d8eccSSepherosa Ziehau } 46716c8d8eccSSepherosa Ziehau 46726c8d8eccSSepherosa Ziehau sc->bnx_coal_chg = 0; 46736c8d8eccSSepherosa Ziehau } 46746c8d8eccSSepherosa Ziehau 46756c8d8eccSSepherosa Ziehau static void 4676695a8586SSepherosa Ziehau bnx_check_intr_rxtx(void *xintr) 4677df9ccc98SSepherosa Ziehau { 4678f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr = xintr; 4679f33ac8a4SSepherosa Ziehau struct bnx_rx_ret_ring *ret; 4680f33ac8a4SSepherosa Ziehau struct bnx_tx_ring *txr; 4681f33ac8a4SSepherosa Ziehau struct ifnet *ifp; 4682df9ccc98SSepherosa Ziehau 4683f33ac8a4SSepherosa Ziehau lwkt_serialize_enter(intr->bnx_intr_serialize); 4684df9ccc98SSepherosa Ziehau 4685f33ac8a4SSepherosa Ziehau KKASSERT(mycpuid == intr->bnx_intr_cpuid); 4686df9ccc98SSepherosa Ziehau 4687f33ac8a4SSepherosa Ziehau ifp = &intr->bnx_sc->arpcom.ac_if; 468839a8d43aSSepherosa Ziehau if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) != IFF_RUNNING) { 4689f33ac8a4SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4690df9ccc98SSepherosa Ziehau return; 4691df9ccc98SSepherosa Ziehau } 4692df9ccc98SSepherosa Ziehau 4693f33ac8a4SSepherosa Ziehau txr = intr->bnx_txr; 4694f33ac8a4SSepherosa Ziehau ret = intr->bnx_ret; 4695f33ac8a4SSepherosa Ziehau 46963a16b7b8SSepherosa Ziehau if (*ret->bnx_rx_considx != ret->bnx_rx_saved_considx || 46973a16b7b8SSepherosa Ziehau *txr->bnx_tx_considx != txr->bnx_tx_saved_considx) { 4698f33ac8a4SSepherosa Ziehau if (intr->bnx_rx_check_considx == ret->bnx_rx_saved_considx && 4699f33ac8a4SSepherosa Ziehau intr->bnx_tx_check_considx == txr->bnx_tx_saved_considx) { 4700f33ac8a4SSepherosa Ziehau if (!intr->bnx_intr_maylose) { 4701f33ac8a4SSepherosa Ziehau intr->bnx_intr_maylose = TRUE; 4702df9ccc98SSepherosa Ziehau goto done; 4703df9ccc98SSepherosa Ziehau } 4704df9ccc98SSepherosa Ziehau if (bootverbose) 4705df9ccc98SSepherosa Ziehau if_printf(ifp, "lost interrupt\n"); 4706f33ac8a4SSepherosa Ziehau intr->bnx_intr_func(intr->bnx_intr_arg); 4707df9ccc98SSepherosa Ziehau } 4708df9ccc98SSepherosa Ziehau } 4709f33ac8a4SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4710f33ac8a4SSepherosa Ziehau intr->bnx_rx_check_considx = ret->bnx_rx_saved_considx; 4711f33ac8a4SSepherosa Ziehau intr->bnx_tx_check_considx = txr->bnx_tx_saved_considx; 4712df9ccc98SSepherosa Ziehau 4713df9ccc98SSepherosa Ziehau done: 4714f33ac8a4SSepherosa Ziehau callout_reset(&intr->bnx_intr_timer, BNX_INTR_CKINTVL, 4715f33ac8a4SSepherosa Ziehau intr->bnx_intr_check, intr); 4716f33ac8a4SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4717df9ccc98SSepherosa Ziehau } 4718df9ccc98SSepherosa Ziehau 4719df9ccc98SSepherosa Ziehau static void 4720695a8586SSepherosa Ziehau bnx_check_intr_tx(void *xintr) 4721695a8586SSepherosa Ziehau { 4722695a8586SSepherosa Ziehau struct bnx_intr_data *intr = xintr; 4723695a8586SSepherosa Ziehau struct bnx_tx_ring *txr; 4724695a8586SSepherosa Ziehau struct ifnet *ifp; 4725695a8586SSepherosa Ziehau 4726695a8586SSepherosa Ziehau lwkt_serialize_enter(intr->bnx_intr_serialize); 4727695a8586SSepherosa Ziehau 4728695a8586SSepherosa Ziehau KKASSERT(mycpuid == intr->bnx_intr_cpuid); 4729695a8586SSepherosa Ziehau 4730695a8586SSepherosa Ziehau ifp = &intr->bnx_sc->arpcom.ac_if; 4731695a8586SSepherosa Ziehau if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) != IFF_RUNNING) { 4732695a8586SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4733695a8586SSepherosa Ziehau return; 4734695a8586SSepherosa Ziehau } 4735695a8586SSepherosa Ziehau 4736695a8586SSepherosa Ziehau txr = intr->bnx_txr; 4737695a8586SSepherosa Ziehau 4738695a8586SSepherosa Ziehau if (*txr->bnx_tx_considx != txr->bnx_tx_saved_considx) { 4739695a8586SSepherosa Ziehau if (intr->bnx_tx_check_considx == txr->bnx_tx_saved_considx) { 4740695a8586SSepherosa Ziehau if (!intr->bnx_intr_maylose) { 4741695a8586SSepherosa Ziehau intr->bnx_intr_maylose = TRUE; 4742695a8586SSepherosa Ziehau goto done; 4743695a8586SSepherosa Ziehau } 4744695a8586SSepherosa Ziehau if (bootverbose) 4745695a8586SSepherosa Ziehau if_printf(ifp, "lost interrupt\n"); 4746695a8586SSepherosa Ziehau intr->bnx_intr_func(intr->bnx_intr_arg); 4747695a8586SSepherosa Ziehau } 4748695a8586SSepherosa Ziehau } 4749695a8586SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4750695a8586SSepherosa Ziehau intr->bnx_tx_check_considx = txr->bnx_tx_saved_considx; 4751695a8586SSepherosa Ziehau 4752695a8586SSepherosa Ziehau done: 4753695a8586SSepherosa Ziehau callout_reset(&intr->bnx_intr_timer, BNX_INTR_CKINTVL, 4754695a8586SSepherosa Ziehau intr->bnx_intr_check, intr); 4755695a8586SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4756695a8586SSepherosa Ziehau } 4757695a8586SSepherosa Ziehau 4758695a8586SSepherosa Ziehau static void 4759695a8586SSepherosa Ziehau bnx_check_intr_rx(void *xintr) 4760695a8586SSepherosa Ziehau { 4761695a8586SSepherosa Ziehau struct bnx_intr_data *intr = xintr; 4762695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret; 4763695a8586SSepherosa Ziehau struct ifnet *ifp; 4764695a8586SSepherosa Ziehau 4765695a8586SSepherosa Ziehau lwkt_serialize_enter(intr->bnx_intr_serialize); 4766695a8586SSepherosa Ziehau 4767695a8586SSepherosa Ziehau KKASSERT(mycpuid == intr->bnx_intr_cpuid); 4768695a8586SSepherosa Ziehau 4769695a8586SSepherosa Ziehau ifp = &intr->bnx_sc->arpcom.ac_if; 4770695a8586SSepherosa Ziehau if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) != IFF_RUNNING) { 4771695a8586SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4772695a8586SSepherosa Ziehau return; 4773695a8586SSepherosa Ziehau } 4774695a8586SSepherosa Ziehau 4775695a8586SSepherosa Ziehau ret = intr->bnx_ret; 4776695a8586SSepherosa Ziehau 4777695a8586SSepherosa Ziehau if (*ret->bnx_rx_considx != ret->bnx_rx_saved_considx) { 4778695a8586SSepherosa Ziehau if (intr->bnx_rx_check_considx == ret->bnx_rx_saved_considx) { 4779695a8586SSepherosa Ziehau if (!intr->bnx_intr_maylose) { 4780695a8586SSepherosa Ziehau intr->bnx_intr_maylose = TRUE; 4781695a8586SSepherosa Ziehau goto done; 4782695a8586SSepherosa Ziehau } 4783695a8586SSepherosa Ziehau if (bootverbose) 4784695a8586SSepherosa Ziehau if_printf(ifp, "lost interrupt\n"); 4785695a8586SSepherosa Ziehau intr->bnx_intr_func(intr->bnx_intr_arg); 4786695a8586SSepherosa Ziehau } 4787695a8586SSepherosa Ziehau } 4788695a8586SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4789695a8586SSepherosa Ziehau intr->bnx_rx_check_considx = ret->bnx_rx_saved_considx; 4790695a8586SSepherosa Ziehau 4791695a8586SSepherosa Ziehau done: 4792695a8586SSepherosa Ziehau callout_reset(&intr->bnx_intr_timer, BNX_INTR_CKINTVL, 4793695a8586SSepherosa Ziehau intr->bnx_intr_check, intr); 4794695a8586SSepherosa Ziehau lwkt_serialize_exit(intr->bnx_intr_serialize); 4795695a8586SSepherosa Ziehau } 4796695a8586SSepherosa Ziehau 4797695a8586SSepherosa Ziehau static void 47986c8d8eccSSepherosa Ziehau bnx_enable_intr(struct bnx_softc *sc) 47996c8d8eccSSepherosa Ziehau { 48006c8d8eccSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 4801f33ac8a4SSepherosa Ziehau int i; 48026c8d8eccSSepherosa Ziehau 4803f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 4804f33ac8a4SSepherosa Ziehau lwkt_serialize_handler_enable( 4805f33ac8a4SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_serialize); 4806f33ac8a4SSepherosa Ziehau } 48076c8d8eccSSepherosa Ziehau 48086c8d8eccSSepherosa Ziehau /* 48096c8d8eccSSepherosa Ziehau * Enable interrupt. 48106c8d8eccSSepherosa Ziehau */ 481197ba8fc5SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 481297ba8fc5SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 481397ba8fc5SSepherosa Ziehau 481497ba8fc5SSepherosa Ziehau bnx_writembx(sc, intr->bnx_intr_mbx, 481597ba8fc5SSepherosa Ziehau (*intr->bnx_saved_status_tag) << 24); 48166c8d8eccSSepherosa Ziehau /* XXX Linux driver */ 481797ba8fc5SSepherosa Ziehau bnx_writembx(sc, intr->bnx_intr_mbx, 481897ba8fc5SSepherosa Ziehau (*intr->bnx_saved_status_tag) << 24); 481997ba8fc5SSepherosa Ziehau } 48206c8d8eccSSepherosa Ziehau 48216c8d8eccSSepherosa Ziehau /* 48226c8d8eccSSepherosa Ziehau * Unmask the interrupt when we stop polling. 48236c8d8eccSSepherosa Ziehau */ 48246c8d8eccSSepherosa Ziehau PCI_CLRBIT(sc->bnx_dev, BGE_PCI_MISC_CTL, 48256c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_MASK_PCI_INTR, 4); 48266c8d8eccSSepherosa Ziehau 48276c8d8eccSSepherosa Ziehau /* 48286c8d8eccSSepherosa Ziehau * Trigger another interrupt, since above writing 48296c8d8eccSSepherosa Ziehau * to interrupt mailbox0 may acknowledge pending 48306c8d8eccSSepherosa Ziehau * interrupt. 48316c8d8eccSSepherosa Ziehau */ 48326c8d8eccSSepherosa Ziehau BNX_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_SET); 4833df9ccc98SSepherosa Ziehau 4834df9ccc98SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_STATUSTAG_BUG) { 4835df9ccc98SSepherosa Ziehau if (bootverbose) 4836df9ccc98SSepherosa Ziehau if_printf(ifp, "status tag bug workaround\n"); 4837df9ccc98SSepherosa Ziehau 4838f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 483997ba8fc5SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 484097ba8fc5SSepherosa Ziehau 4841695a8586SSepherosa Ziehau if (intr->bnx_intr_check == NULL) 4842695a8586SSepherosa Ziehau continue; 4843f33ac8a4SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4844f33ac8a4SSepherosa Ziehau intr->bnx_rx_check_considx = 0; 4845f33ac8a4SSepherosa Ziehau intr->bnx_tx_check_considx = 0; 4846f33ac8a4SSepherosa Ziehau callout_reset_bycpu(&intr->bnx_intr_timer, 4847f33ac8a4SSepherosa Ziehau BNX_INTR_CKINTVL, intr->bnx_intr_check, intr, 4848f33ac8a4SSepherosa Ziehau intr->bnx_intr_cpuid); 4849f33ac8a4SSepherosa Ziehau } 4850df9ccc98SSepherosa Ziehau } 48516c8d8eccSSepherosa Ziehau } 48526c8d8eccSSepherosa Ziehau 48536c8d8eccSSepherosa Ziehau static void 48546c8d8eccSSepherosa Ziehau bnx_disable_intr(struct bnx_softc *sc) 48556c8d8eccSSepherosa Ziehau { 4856f33ac8a4SSepherosa Ziehau int i; 4857f33ac8a4SSepherosa Ziehau 4858f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 4859f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 4860f33ac8a4SSepherosa Ziehau 4861f33ac8a4SSepherosa Ziehau callout_stop(&intr->bnx_intr_timer); 4862f33ac8a4SSepherosa Ziehau intr->bnx_intr_maylose = FALSE; 4863f33ac8a4SSepherosa Ziehau intr->bnx_rx_check_considx = 0; 4864f33ac8a4SSepherosa Ziehau intr->bnx_tx_check_considx = 0; 4865f33ac8a4SSepherosa Ziehau } 48666c8d8eccSSepherosa Ziehau 48676c8d8eccSSepherosa Ziehau /* 48686c8d8eccSSepherosa Ziehau * Mask the interrupt when we start polling. 48696c8d8eccSSepherosa Ziehau */ 48706c8d8eccSSepherosa Ziehau PCI_SETBIT(sc->bnx_dev, BGE_PCI_MISC_CTL, 48716c8d8eccSSepherosa Ziehau BGE_PCIMISCCTL_MASK_PCI_INTR, 4); 48726c8d8eccSSepherosa Ziehau 48736c8d8eccSSepherosa Ziehau /* 48746c8d8eccSSepherosa Ziehau * Acknowledge possible asserted interrupt. 48756c8d8eccSSepherosa Ziehau */ 4876695a8586SSepherosa Ziehau for (i = 0; i < BNX_INTR_MAX; ++i) 487797ba8fc5SSepherosa Ziehau bnx_writembx(sc, sc->bnx_intr_data[i].bnx_intr_mbx, 1); 48786c8d8eccSSepherosa Ziehau 4879f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 4880f33ac8a4SSepherosa Ziehau lwkt_serialize_handler_disable( 4881f33ac8a4SSepherosa Ziehau sc->bnx_intr_data[i].bnx_intr_serialize); 4882f33ac8a4SSepherosa Ziehau } 48836c8d8eccSSepherosa Ziehau } 48846c8d8eccSSepherosa Ziehau 48856c8d8eccSSepherosa Ziehau static int 48866c8d8eccSSepherosa Ziehau bnx_get_eaddr_mem(struct bnx_softc *sc, uint8_t ether_addr[]) 48876c8d8eccSSepherosa Ziehau { 48886c8d8eccSSepherosa Ziehau uint32_t mac_addr; 48896c8d8eccSSepherosa Ziehau int ret = 1; 48906c8d8eccSSepherosa Ziehau 48916c8d8eccSSepherosa Ziehau mac_addr = bnx_readmem_ind(sc, 0x0c14); 48926c8d8eccSSepherosa Ziehau if ((mac_addr >> 16) == 0x484b) { 48936c8d8eccSSepherosa Ziehau ether_addr[0] = (uint8_t)(mac_addr >> 8); 48946c8d8eccSSepherosa Ziehau ether_addr[1] = (uint8_t)mac_addr; 48956c8d8eccSSepherosa Ziehau mac_addr = bnx_readmem_ind(sc, 0x0c18); 48966c8d8eccSSepherosa Ziehau ether_addr[2] = (uint8_t)(mac_addr >> 24); 48976c8d8eccSSepherosa Ziehau ether_addr[3] = (uint8_t)(mac_addr >> 16); 48986c8d8eccSSepherosa Ziehau ether_addr[4] = (uint8_t)(mac_addr >> 8); 48996c8d8eccSSepherosa Ziehau ether_addr[5] = (uint8_t)mac_addr; 49006c8d8eccSSepherosa Ziehau ret = 0; 49016c8d8eccSSepherosa Ziehau } 49026c8d8eccSSepherosa Ziehau return ret; 49036c8d8eccSSepherosa Ziehau } 49046c8d8eccSSepherosa Ziehau 49056c8d8eccSSepherosa Ziehau static int 49066c8d8eccSSepherosa Ziehau bnx_get_eaddr_nvram(struct bnx_softc *sc, uint8_t ether_addr[]) 49076c8d8eccSSepherosa Ziehau { 49086c8d8eccSSepherosa Ziehau int mac_offset = BGE_EE_MAC_OFFSET; 49096c8d8eccSSepherosa Ziehau 491080969639SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) { 491180969639SSepherosa Ziehau int f; 491280969639SSepherosa Ziehau 491380969639SSepherosa Ziehau f = pci_get_function(sc->bnx_dev); 491480969639SSepherosa Ziehau if (f & 1) 491580969639SSepherosa Ziehau mac_offset = BGE_EE_MAC_OFFSET_5717; 491680969639SSepherosa Ziehau if (f > 1) 491780969639SSepherosa Ziehau mac_offset += BGE_EE_MAC_OFFSET_5717_OFF; 491880969639SSepherosa Ziehau } 49196c8d8eccSSepherosa Ziehau 49206c8d8eccSSepherosa Ziehau return bnx_read_nvram(sc, ether_addr, mac_offset + 2, ETHER_ADDR_LEN); 49216c8d8eccSSepherosa Ziehau } 49226c8d8eccSSepherosa Ziehau 49236c8d8eccSSepherosa Ziehau static int 49246c8d8eccSSepherosa Ziehau bnx_get_eaddr_eeprom(struct bnx_softc *sc, uint8_t ether_addr[]) 49256c8d8eccSSepherosa Ziehau { 49266c8d8eccSSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_NO_EEPROM) 49276c8d8eccSSepherosa Ziehau return 1; 49286c8d8eccSSepherosa Ziehau 49296c8d8eccSSepherosa Ziehau return bnx_read_eeprom(sc, ether_addr, BGE_EE_MAC_OFFSET + 2, 49306c8d8eccSSepherosa Ziehau ETHER_ADDR_LEN); 49316c8d8eccSSepherosa Ziehau } 49326c8d8eccSSepherosa Ziehau 49336c8d8eccSSepherosa Ziehau static int 49346c8d8eccSSepherosa Ziehau bnx_get_eaddr(struct bnx_softc *sc, uint8_t eaddr[]) 49356c8d8eccSSepherosa Ziehau { 49366c8d8eccSSepherosa Ziehau static const bnx_eaddr_fcn_t bnx_eaddr_funcs[] = { 49376c8d8eccSSepherosa Ziehau /* NOTE: Order is critical */ 49386c8d8eccSSepherosa Ziehau bnx_get_eaddr_mem, 49396c8d8eccSSepherosa Ziehau bnx_get_eaddr_nvram, 49406c8d8eccSSepherosa Ziehau bnx_get_eaddr_eeprom, 49416c8d8eccSSepherosa Ziehau NULL 49426c8d8eccSSepherosa Ziehau }; 49436c8d8eccSSepherosa Ziehau const bnx_eaddr_fcn_t *func; 49446c8d8eccSSepherosa Ziehau 49456c8d8eccSSepherosa Ziehau for (func = bnx_eaddr_funcs; *func != NULL; ++func) { 49466c8d8eccSSepherosa Ziehau if ((*func)(sc, eaddr) == 0) 49476c8d8eccSSepherosa Ziehau break; 49486c8d8eccSSepherosa Ziehau } 49496c8d8eccSSepherosa Ziehau return (*func == NULL ? ENXIO : 0); 49506c8d8eccSSepherosa Ziehau } 49516c8d8eccSSepherosa Ziehau 49526c8d8eccSSepherosa Ziehau /* 49536c8d8eccSSepherosa Ziehau * NOTE: 'm' is not freed upon failure 49546c8d8eccSSepherosa Ziehau */ 49556c8d8eccSSepherosa Ziehau struct mbuf * 49566c8d8eccSSepherosa Ziehau bnx_defrag_shortdma(struct mbuf *m) 49576c8d8eccSSepherosa Ziehau { 49586c8d8eccSSepherosa Ziehau struct mbuf *n; 49596c8d8eccSSepherosa Ziehau int found; 49606c8d8eccSSepherosa Ziehau 49616c8d8eccSSepherosa Ziehau /* 49626c8d8eccSSepherosa Ziehau * If device receive two back-to-back send BDs with less than 49636c8d8eccSSepherosa Ziehau * or equal to 8 total bytes then the device may hang. The two 49646c8d8eccSSepherosa Ziehau * back-to-back send BDs must in the same frame for this failure 49656c8d8eccSSepherosa Ziehau * to occur. Scan mbuf chains and see whether two back-to-back 49666c8d8eccSSepherosa Ziehau * send BDs are there. If this is the case, allocate new mbuf 49676c8d8eccSSepherosa Ziehau * and copy the frame to workaround the silicon bug. 49686c8d8eccSSepherosa Ziehau */ 49696c8d8eccSSepherosa Ziehau for (n = m, found = 0; n != NULL; n = n->m_next) { 49706c8d8eccSSepherosa Ziehau if (n->m_len < 8) { 49716c8d8eccSSepherosa Ziehau found++; 49726c8d8eccSSepherosa Ziehau if (found > 1) 49736c8d8eccSSepherosa Ziehau break; 49746c8d8eccSSepherosa Ziehau continue; 49756c8d8eccSSepherosa Ziehau } 49766c8d8eccSSepherosa Ziehau found = 0; 49776c8d8eccSSepherosa Ziehau } 49786c8d8eccSSepherosa Ziehau 49796c8d8eccSSepherosa Ziehau if (found > 1) 4980b5523eacSSascha Wildner n = m_defrag(m, M_NOWAIT); 49816c8d8eccSSepherosa Ziehau else 49826c8d8eccSSepherosa Ziehau n = m; 49836c8d8eccSSepherosa Ziehau return n; 49846c8d8eccSSepherosa Ziehau } 49856c8d8eccSSepherosa Ziehau 49866c8d8eccSSepherosa Ziehau static void 49876c8d8eccSSepherosa Ziehau bnx_stop_block(struct bnx_softc *sc, bus_size_t reg, uint32_t bit) 49886c8d8eccSSepherosa Ziehau { 49896c8d8eccSSepherosa Ziehau int i; 49906c8d8eccSSepherosa Ziehau 49916c8d8eccSSepherosa Ziehau BNX_CLRBIT(sc, reg, bit); 49926c8d8eccSSepherosa Ziehau for (i = 0; i < BNX_TIMEOUT; i++) { 49936c8d8eccSSepherosa Ziehau if ((CSR_READ_4(sc, reg) & bit) == 0) 49946c8d8eccSSepherosa Ziehau return; 49956c8d8eccSSepherosa Ziehau DELAY(100); 49966c8d8eccSSepherosa Ziehau } 49976c8d8eccSSepherosa Ziehau } 49986c8d8eccSSepherosa Ziehau 49996c8d8eccSSepherosa Ziehau static void 50006c8d8eccSSepherosa Ziehau bnx_link_poll(struct bnx_softc *sc) 50016c8d8eccSSepherosa Ziehau { 50026c8d8eccSSepherosa Ziehau uint32_t status; 50036c8d8eccSSepherosa Ziehau 50046c8d8eccSSepherosa Ziehau status = CSR_READ_4(sc, BGE_MAC_STS); 50056c8d8eccSSepherosa Ziehau if ((status & sc->bnx_link_chg) || sc->bnx_link_evt) { 50066c8d8eccSSepherosa Ziehau sc->bnx_link_evt = 0; 50076c8d8eccSSepherosa Ziehau sc->bnx_link_upd(sc, status); 50086c8d8eccSSepherosa Ziehau } 50096c8d8eccSSepherosa Ziehau } 50106c8d8eccSSepherosa Ziehau 50116c8d8eccSSepherosa Ziehau static void 5012695a8586SSepherosa Ziehau bnx_enable_msi(struct bnx_softc *sc, boolean_t is_msix) 50136c8d8eccSSepherosa Ziehau { 50146c8d8eccSSepherosa Ziehau uint32_t msi_mode; 50156c8d8eccSSepherosa Ziehau 50166c8d8eccSSepherosa Ziehau msi_mode = CSR_READ_4(sc, BGE_MSI_MODE); 50176c8d8eccSSepherosa Ziehau msi_mode |= BGE_MSIMODE_ENABLE; 50186c8d8eccSSepherosa Ziehau /* 50196c8d8eccSSepherosa Ziehau * NOTE: 50200b4feeacSSepherosa Ziehau * 5718-PG105-R says that "one shot" mode does not work 50210b4feeacSSepherosa Ziehau * if MSI is used, however, it obviously works. 50226c8d8eccSSepherosa Ziehau */ 50236c8d8eccSSepherosa Ziehau msi_mode &= ~BGE_MSIMODE_ONESHOT_DISABLE; 5024695a8586SSepherosa Ziehau if (is_msix) 5025695a8586SSepherosa Ziehau msi_mode |= BGE_MSIMODE_MSIX_MULTIMODE; 5026695a8586SSepherosa Ziehau else 5027695a8586SSepherosa Ziehau msi_mode &= ~BGE_MSIMODE_MSIX_MULTIMODE; 50286c8d8eccSSepherosa Ziehau CSR_WRITE_4(sc, BGE_MSI_MODE, msi_mode); 50296c8d8eccSSepherosa Ziehau } 50306c8d8eccSSepherosa Ziehau 50316c8d8eccSSepherosa Ziehau static uint32_t 50326c8d8eccSSepherosa Ziehau bnx_dma_swap_options(struct bnx_softc *sc) 50336c8d8eccSSepherosa Ziehau { 50346c8d8eccSSepherosa Ziehau uint32_t dma_options; 50356c8d8eccSSepherosa Ziehau 50366c8d8eccSSepherosa Ziehau dma_options = BGE_MODECTL_WORDSWAP_NONFRAME | 50376c8d8eccSSepherosa Ziehau BGE_MODECTL_BYTESWAP_DATA | BGE_MODECTL_WORDSWAP_DATA; 50386c8d8eccSSepherosa Ziehau #if BYTE_ORDER == BIG_ENDIAN 50396c8d8eccSSepherosa Ziehau dma_options |= BGE_MODECTL_BYTESWAP_NONFRAME; 50406c8d8eccSSepherosa Ziehau #endif 50416c8d8eccSSepherosa Ziehau return dma_options; 50426c8d8eccSSepherosa Ziehau } 504366deb1c1SSepherosa Ziehau 504466deb1c1SSepherosa Ziehau static int 504533a04907SSepherosa Ziehau bnx_setup_tso(struct bnx_tx_ring *txr, struct mbuf **mp, 504666deb1c1SSepherosa Ziehau uint16_t *mss0, uint16_t *flags0) 504766deb1c1SSepherosa Ziehau { 504866deb1c1SSepherosa Ziehau struct mbuf *m; 504966deb1c1SSepherosa Ziehau struct ip *ip; 505066deb1c1SSepherosa Ziehau struct tcphdr *th; 505166deb1c1SSepherosa Ziehau int thoff, iphlen, hoff, hlen; 505266deb1c1SSepherosa Ziehau uint16_t flags, mss; 505366deb1c1SSepherosa Ziehau 5054f7a2269aSSepherosa Ziehau m = *mp; 5055f7a2269aSSepherosa Ziehau KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); 5056f7a2269aSSepherosa Ziehau 5057f7a2269aSSepherosa Ziehau hoff = m->m_pkthdr.csum_lhlen; 5058f7a2269aSSepherosa Ziehau iphlen = m->m_pkthdr.csum_iphlen; 5059f7a2269aSSepherosa Ziehau thoff = m->m_pkthdr.csum_thlen; 5060f7a2269aSSepherosa Ziehau 5061f7a2269aSSepherosa Ziehau KASSERT(hoff > 0, ("invalid ether header len")); 5062f7a2269aSSepherosa Ziehau KASSERT(iphlen > 0, ("invalid ip header len")); 5063f7a2269aSSepherosa Ziehau KASSERT(thoff > 0, ("invalid tcp header len")); 5064f7a2269aSSepherosa Ziehau 5065f7a2269aSSepherosa Ziehau if (__predict_false(m->m_len < hoff + iphlen + thoff)) { 5066f7a2269aSSepherosa Ziehau m = m_pullup(m, hoff + iphlen + thoff); 5067f7a2269aSSepherosa Ziehau if (m == NULL) { 5068f7a2269aSSepherosa Ziehau *mp = NULL; 5069f7a2269aSSepherosa Ziehau return ENOBUFS; 5070f7a2269aSSepherosa Ziehau } 5071f7a2269aSSepherosa Ziehau *mp = m; 5072f7a2269aSSepherosa Ziehau } 5073f7a2269aSSepherosa Ziehau ip = mtodoff(m, struct ip *, hoff); 5074f7a2269aSSepherosa Ziehau th = mtodoff(m, struct tcphdr *, hoff + iphlen); 5075f7a2269aSSepherosa Ziehau 5076f0336d39SSepherosa Ziehau mss = m->m_pkthdr.tso_segsz; 507766deb1c1SSepherosa Ziehau flags = BGE_TXBDFLAG_CPU_PRE_DMA | BGE_TXBDFLAG_CPU_POST_DMA; 507866deb1c1SSepherosa Ziehau 507966deb1c1SSepherosa Ziehau ip->ip_len = htons(mss + iphlen + thoff); 508066deb1c1SSepherosa Ziehau th->th_sum = 0; 508166deb1c1SSepherosa Ziehau 508266deb1c1SSepherosa Ziehau hlen = (iphlen + thoff) >> 2; 508366deb1c1SSepherosa Ziehau mss |= ((hlen & 0x3) << 14); 508466deb1c1SSepherosa Ziehau flags |= ((hlen & 0xf8) << 7) | ((hlen & 0x4) << 2); 508566deb1c1SSepherosa Ziehau 508666deb1c1SSepherosa Ziehau *mss0 = mss; 508766deb1c1SSepherosa Ziehau *flags0 = flags; 508866deb1c1SSepherosa Ziehau 508966deb1c1SSepherosa Ziehau return 0; 509066deb1c1SSepherosa Ziehau } 509133a04907SSepherosa Ziehau 509233a04907SSepherosa Ziehau static int 509333a04907SSepherosa Ziehau bnx_create_tx_ring(struct bnx_tx_ring *txr) 509433a04907SSepherosa Ziehau { 509533a04907SSepherosa Ziehau bus_size_t txmaxsz, txmaxsegsz; 509633a04907SSepherosa Ziehau int i, error; 509733a04907SSepherosa Ziehau 5098329f9016SSepherosa Ziehau lwkt_serialize_init(&txr->bnx_tx_serialize); 5099329f9016SSepherosa Ziehau 510033a04907SSepherosa Ziehau /* 510133a04907SSepherosa Ziehau * Create DMA tag and maps for TX mbufs. 510233a04907SSepherosa Ziehau */ 510333a04907SSepherosa Ziehau if (txr->bnx_sc->bnx_flags & BNX_FLAG_TSO) 510433a04907SSepherosa Ziehau txmaxsz = IP_MAXPACKET + sizeof(struct ether_vlan_header); 510533a04907SSepherosa Ziehau else 510633a04907SSepherosa Ziehau txmaxsz = BNX_JUMBO_FRAMELEN; 510733a04907SSepherosa Ziehau if (txr->bnx_sc->bnx_asicrev == BGE_ASICREV_BCM57766) 510833a04907SSepherosa Ziehau txmaxsegsz = MCLBYTES; 510933a04907SSepherosa Ziehau else 511033a04907SSepherosa Ziehau txmaxsegsz = PAGE_SIZE; 511133a04907SSepherosa Ziehau error = bus_dma_tag_create(txr->bnx_sc->bnx_cdata.bnx_parent_tag, 511233a04907SSepherosa Ziehau 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 511333a04907SSepherosa Ziehau txmaxsz, BNX_NSEG_NEW, txmaxsegsz, 511433a04907SSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 511533a04907SSepherosa Ziehau &txr->bnx_tx_mtag); 511633a04907SSepherosa Ziehau if (error) { 511733a04907SSepherosa Ziehau device_printf(txr->bnx_sc->bnx_dev, 5118beedf5beSSepherosa Ziehau "could not create TX mbuf DMA tag\n"); 511933a04907SSepherosa Ziehau return error; 512033a04907SSepherosa Ziehau } 512133a04907SSepherosa Ziehau 512233a04907SSepherosa Ziehau for (i = 0; i < BGE_TX_RING_CNT; i++) { 512333a04907SSepherosa Ziehau error = bus_dmamap_create(txr->bnx_tx_mtag, 512433a04907SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 5125fa4b1067SSepherosa Ziehau &txr->bnx_tx_buf[i].bnx_tx_dmamap); 512633a04907SSepherosa Ziehau if (error) { 512733a04907SSepherosa Ziehau int j; 512833a04907SSepherosa Ziehau 512933a04907SSepherosa Ziehau for (j = 0; j < i; ++j) { 513033a04907SSepherosa Ziehau bus_dmamap_destroy(txr->bnx_tx_mtag, 5131fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[j].bnx_tx_dmamap); 513233a04907SSepherosa Ziehau } 513333a04907SSepherosa Ziehau bus_dma_tag_destroy(txr->bnx_tx_mtag); 513433a04907SSepherosa Ziehau txr->bnx_tx_mtag = NULL; 513533a04907SSepherosa Ziehau 513633a04907SSepherosa Ziehau device_printf(txr->bnx_sc->bnx_dev, 5137beedf5beSSepherosa Ziehau "could not create TX mbuf DMA map\n"); 513833a04907SSepherosa Ziehau return error; 513933a04907SSepherosa Ziehau } 514033a04907SSepherosa Ziehau } 514133a04907SSepherosa Ziehau 514233a04907SSepherosa Ziehau /* 514333a04907SSepherosa Ziehau * Create DMA stuffs for TX ring. 514433a04907SSepherosa Ziehau */ 514533a04907SSepherosa Ziehau error = bnx_dma_block_alloc(txr->bnx_sc, BGE_TX_RING_SZ, 5146beedf5beSSepherosa Ziehau &txr->bnx_tx_ring_tag, 5147beedf5beSSepherosa Ziehau &txr->bnx_tx_ring_map, 5148beedf5beSSepherosa Ziehau (void *)&txr->bnx_tx_ring, 5149beedf5beSSepherosa Ziehau &txr->bnx_tx_ring_paddr); 515033a04907SSepherosa Ziehau if (error) { 515133a04907SSepherosa Ziehau device_printf(txr->bnx_sc->bnx_dev, 515233a04907SSepherosa Ziehau "could not create TX ring\n"); 515333a04907SSepherosa Ziehau return error; 515433a04907SSepherosa Ziehau } 515533a04907SSepherosa Ziehau 515679a64343SSepherosa Ziehau txr->bnx_tx_flags |= BNX_TX_FLAG_SHORTDMA; 515733a04907SSepherosa Ziehau txr->bnx_tx_wreg = BNX_TX_WREG_NSEGS; 515833a04907SSepherosa Ziehau 515933a04907SSepherosa Ziehau return 0; 516033a04907SSepherosa Ziehau } 516133a04907SSepherosa Ziehau 516233a04907SSepherosa Ziehau static void 516333a04907SSepherosa Ziehau bnx_destroy_tx_ring(struct bnx_tx_ring *txr) 516433a04907SSepherosa Ziehau { 516533a04907SSepherosa Ziehau /* Destroy TX mbuf DMA stuffs. */ 516633a04907SSepherosa Ziehau if (txr->bnx_tx_mtag != NULL) { 516733a04907SSepherosa Ziehau int i; 516833a04907SSepherosa Ziehau 516933a04907SSepherosa Ziehau for (i = 0; i < BGE_TX_RING_CNT; i++) { 5170fa4b1067SSepherosa Ziehau KKASSERT(txr->bnx_tx_buf[i].bnx_tx_mbuf == NULL); 517133a04907SSepherosa Ziehau bus_dmamap_destroy(txr->bnx_tx_mtag, 5172fa4b1067SSepherosa Ziehau txr->bnx_tx_buf[i].bnx_tx_dmamap); 517333a04907SSepherosa Ziehau } 517433a04907SSepherosa Ziehau bus_dma_tag_destroy(txr->bnx_tx_mtag); 517533a04907SSepherosa Ziehau } 517633a04907SSepherosa Ziehau 517733a04907SSepherosa Ziehau /* Destroy TX ring */ 517833a04907SSepherosa Ziehau bnx_dma_block_free(txr->bnx_tx_ring_tag, 517933a04907SSepherosa Ziehau txr->bnx_tx_ring_map, txr->bnx_tx_ring); 518033a04907SSepherosa Ziehau } 5181aad4de2bSSepherosa Ziehau 5182aad4de2bSSepherosa Ziehau static int 5183aad4de2bSSepherosa Ziehau bnx_sysctl_force_defrag(SYSCTL_HANDLER_ARGS) 5184aad4de2bSSepherosa Ziehau { 5185aad4de2bSSepherosa Ziehau struct bnx_softc *sc = (void *)arg1; 5186aad4de2bSSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 5187aad4de2bSSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[0]; 5188aad4de2bSSepherosa Ziehau int error, defrag, i; 5189aad4de2bSSepherosa Ziehau 5190aad4de2bSSepherosa Ziehau if (txr->bnx_tx_flags & BNX_TX_FLAG_FORCE_DEFRAG) 5191aad4de2bSSepherosa Ziehau defrag = 1; 5192aad4de2bSSepherosa Ziehau else 5193aad4de2bSSepherosa Ziehau defrag = 0; 5194aad4de2bSSepherosa Ziehau 5195aad4de2bSSepherosa Ziehau error = sysctl_handle_int(oidp, &defrag, 0, req); 5196aad4de2bSSepherosa Ziehau if (error || req->newptr == NULL) 5197aad4de2bSSepherosa Ziehau return error; 5198aad4de2bSSepherosa Ziehau 5199329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 5200aad4de2bSSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) { 5201aad4de2bSSepherosa Ziehau txr = &sc->bnx_tx_ring[i]; 5202aad4de2bSSepherosa Ziehau if (defrag) 5203aad4de2bSSepherosa Ziehau txr->bnx_tx_flags |= BNX_TX_FLAG_FORCE_DEFRAG; 5204aad4de2bSSepherosa Ziehau else 5205aad4de2bSSepherosa Ziehau txr->bnx_tx_flags &= ~BNX_TX_FLAG_FORCE_DEFRAG; 5206aad4de2bSSepherosa Ziehau } 5207329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 5208aad4de2bSSepherosa Ziehau 5209aad4de2bSSepherosa Ziehau return 0; 5210aad4de2bSSepherosa Ziehau } 5211472c99c8SSepherosa Ziehau 5212472c99c8SSepherosa Ziehau static int 5213472c99c8SSepherosa Ziehau bnx_sysctl_tx_wreg(SYSCTL_HANDLER_ARGS) 5214472c99c8SSepherosa Ziehau { 5215472c99c8SSepherosa Ziehau struct bnx_softc *sc = (void *)arg1; 5216472c99c8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 5217472c99c8SSepherosa Ziehau struct bnx_tx_ring *txr = &sc->bnx_tx_ring[0]; 5218472c99c8SSepherosa Ziehau int error, tx_wreg, i; 5219472c99c8SSepherosa Ziehau 5220472c99c8SSepherosa Ziehau tx_wreg = txr->bnx_tx_wreg; 5221472c99c8SSepherosa Ziehau error = sysctl_handle_int(oidp, &tx_wreg, 0, req); 5222472c99c8SSepherosa Ziehau if (error || req->newptr == NULL) 5223472c99c8SSepherosa Ziehau return error; 5224472c99c8SSepherosa Ziehau 5225329f9016SSepherosa Ziehau ifnet_serialize_all(ifp); 5226472c99c8SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 5227472c99c8SSepherosa Ziehau sc->bnx_tx_ring[i].bnx_tx_wreg = tx_wreg; 5228329f9016SSepherosa Ziehau ifnet_deserialize_all(ifp); 5229472c99c8SSepherosa Ziehau 5230472c99c8SSepherosa Ziehau return 0; 5231472c99c8SSepherosa Ziehau } 5232beedf5beSSepherosa Ziehau 5233beedf5beSSepherosa Ziehau static int 5234beedf5beSSepherosa Ziehau bnx_create_rx_ret_ring(struct bnx_rx_ret_ring *ret) 5235beedf5beSSepherosa Ziehau { 5236beedf5beSSepherosa Ziehau int error; 5237beedf5beSSepherosa Ziehau 5238329f9016SSepherosa Ziehau lwkt_serialize_init(&ret->bnx_rx_ret_serialize); 5239329f9016SSepherosa Ziehau 5240beedf5beSSepherosa Ziehau /* 5241beedf5beSSepherosa Ziehau * Create DMA stuffs for RX return ring. 5242beedf5beSSepherosa Ziehau */ 5243beedf5beSSepherosa Ziehau error = bnx_dma_block_alloc(ret->bnx_sc, 5244beedf5beSSepherosa Ziehau BGE_RX_RTN_RING_SZ(BNX_RETURN_RING_CNT), 5245beedf5beSSepherosa Ziehau &ret->bnx_rx_ret_ring_tag, 5246beedf5beSSepherosa Ziehau &ret->bnx_rx_ret_ring_map, 5247beedf5beSSepherosa Ziehau (void *)&ret->bnx_rx_ret_ring, 5248beedf5beSSepherosa Ziehau &ret->bnx_rx_ret_ring_paddr); 5249beedf5beSSepherosa Ziehau if (error) { 5250beedf5beSSepherosa Ziehau device_printf(ret->bnx_sc->bnx_dev, 5251beedf5beSSepherosa Ziehau "could not create RX ret ring\n"); 5252beedf5beSSepherosa Ziehau return error; 5253beedf5beSSepherosa Ziehau } 5254beedf5beSSepherosa Ziehau 5255beedf5beSSepherosa Ziehau /* Shadow standard ring's RX mbuf DMA tag */ 5256beedf5beSSepherosa Ziehau ret->bnx_rx_mtag = ret->bnx_std->bnx_rx_mtag; 5257beedf5beSSepherosa Ziehau 5258beedf5beSSepherosa Ziehau /* 5259beedf5beSSepherosa Ziehau * Create tmp DMA map for RX mbufs. 5260beedf5beSSepherosa Ziehau */ 5261beedf5beSSepherosa Ziehau error = bus_dmamap_create(ret->bnx_rx_mtag, BUS_DMA_WAITOK, 5262beedf5beSSepherosa Ziehau &ret->bnx_rx_tmpmap); 5263beedf5beSSepherosa Ziehau if (error) { 5264beedf5beSSepherosa Ziehau device_printf(ret->bnx_sc->bnx_dev, 5265beedf5beSSepherosa Ziehau "could not create tmp RX mbuf DMA map\n"); 5266beedf5beSSepherosa Ziehau ret->bnx_rx_mtag = NULL; 5267beedf5beSSepherosa Ziehau return error; 5268beedf5beSSepherosa Ziehau } 5269beedf5beSSepherosa Ziehau return 0; 5270beedf5beSSepherosa Ziehau } 5271beedf5beSSepherosa Ziehau 5272beedf5beSSepherosa Ziehau static void 5273beedf5beSSepherosa Ziehau bnx_destroy_rx_ret_ring(struct bnx_rx_ret_ring *ret) 5274beedf5beSSepherosa Ziehau { 5275beedf5beSSepherosa Ziehau /* Destroy tmp RX mbuf DMA map */ 5276beedf5beSSepherosa Ziehau if (ret->bnx_rx_mtag != NULL) 5277beedf5beSSepherosa Ziehau bus_dmamap_destroy(ret->bnx_rx_mtag, ret->bnx_rx_tmpmap); 5278beedf5beSSepherosa Ziehau 5279beedf5beSSepherosa Ziehau /* Destroy RX return ring */ 5280beedf5beSSepherosa Ziehau bnx_dma_block_free(ret->bnx_rx_ret_ring_tag, 5281beedf5beSSepherosa Ziehau ret->bnx_rx_ret_ring_map, ret->bnx_rx_ret_ring); 5282beedf5beSSepherosa Ziehau } 52830c7da01dSSepherosa Ziehau 52840c7da01dSSepherosa Ziehau static int 52850c7da01dSSepherosa Ziehau bnx_alloc_intr(struct bnx_softc *sc) 52860c7da01dSSepherosa Ziehau { 5287f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr; 52880c7da01dSSepherosa Ziehau u_int intr_flags; 5289695a8586SSepherosa Ziehau int error; 5290695a8586SSepherosa Ziehau 5291695a8586SSepherosa Ziehau if (sc->bnx_intr_cnt > 1) { 5292695a8586SSepherosa Ziehau error = bnx_alloc_msix(sc); 5293695a8586SSepherosa Ziehau if (error) 5294695a8586SSepherosa Ziehau return error; 5295695a8586SSepherosa Ziehau KKASSERT(sc->bnx_intr_type == PCI_INTR_TYPE_MSIX); 5296695a8586SSepherosa Ziehau return 0; 5297695a8586SSepherosa Ziehau } 52980c7da01dSSepherosa Ziehau 52990a806e3aSSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt == 1); 53000c7da01dSSepherosa Ziehau 5301f33ac8a4SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 5302f33ac8a4SSepherosa Ziehau intr->bnx_ret = &sc->bnx_rx_ret_ring[0]; 5303f33ac8a4SSepherosa Ziehau intr->bnx_txr = &sc->bnx_tx_ring[0]; 5304f33ac8a4SSepherosa Ziehau intr->bnx_intr_serialize = &sc->bnx_main_serialize; 5305695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_rxtx; 53064fa38985SSepherosa Ziehau intr->bnx_saved_status_tag = &intr->bnx_ret->bnx_saved_status_tag; 5307f33ac8a4SSepherosa Ziehau 5308f33ac8a4SSepherosa Ziehau sc->bnx_intr_type = pci_alloc_1intr(sc->bnx_dev, bnx_msi_enable, 5309f33ac8a4SSepherosa Ziehau &intr->bnx_intr_rid, &intr_flags); 5310f33ac8a4SSepherosa Ziehau 5311f33ac8a4SSepherosa Ziehau intr->bnx_intr_res = bus_alloc_resource_any(sc->bnx_dev, SYS_RES_IRQ, 5312f33ac8a4SSepherosa Ziehau &intr->bnx_intr_rid, intr_flags); 5313f33ac8a4SSepherosa Ziehau if (intr->bnx_intr_res == NULL) { 53140c7da01dSSepherosa Ziehau device_printf(sc->bnx_dev, "could not alloc interrupt\n"); 53150c7da01dSSepherosa Ziehau return ENXIO; 53160c7da01dSSepherosa Ziehau } 53170c7da01dSSepherosa Ziehau 5318f33ac8a4SSepherosa Ziehau if (sc->bnx_intr_type == PCI_INTR_TYPE_MSI) { 5319695a8586SSepherosa Ziehau bnx_enable_msi(sc, FALSE); 532003cc99fdSSepherosa Ziehau intr->bnx_intr_func = bnx_msi; 5321f33ac8a4SSepherosa Ziehau if (bootverbose) 5322f33ac8a4SSepherosa Ziehau device_printf(sc->bnx_dev, "oneshot MSI\n"); 5323f33ac8a4SSepherosa Ziehau } else { 5324f33ac8a4SSepherosa Ziehau intr->bnx_intr_func = bnx_intr_legacy; 5325f33ac8a4SSepherosa Ziehau } 5326f33ac8a4SSepherosa Ziehau intr->bnx_intr_arg = sc; 5327f33ac8a4SSepherosa Ziehau intr->bnx_intr_cpuid = rman_get_cpuid(intr->bnx_intr_res); 5328f33ac8a4SSepherosa Ziehau 5329f33ac8a4SSepherosa Ziehau intr->bnx_txr->bnx_tx_cpuid = intr->bnx_intr_cpuid; 5330f33ac8a4SSepherosa Ziehau 53310c7da01dSSepherosa Ziehau return 0; 53320c7da01dSSepherosa Ziehau } 53330c7da01dSSepherosa Ziehau 53340c7da01dSSepherosa Ziehau static int 53350c7da01dSSepherosa Ziehau bnx_setup_intr(struct bnx_softc *sc) 53360c7da01dSSepherosa Ziehau { 5337f33ac8a4SSepherosa Ziehau int error, i; 53380c7da01dSSepherosa Ziehau 5339f33ac8a4SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 5340f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 5341f33ac8a4SSepherosa Ziehau 5342f33ac8a4SSepherosa Ziehau error = bus_setup_intr_descr(sc->bnx_dev, intr->bnx_intr_res, 5343f33ac8a4SSepherosa Ziehau INTR_MPSAFE, intr->bnx_intr_func, intr->bnx_intr_arg, 5344f33ac8a4SSepherosa Ziehau &intr->bnx_intr_hand, intr->bnx_intr_serialize, 5345f33ac8a4SSepherosa Ziehau intr->bnx_intr_desc); 53460c7da01dSSepherosa Ziehau if (error) { 5347f33ac8a4SSepherosa Ziehau device_printf(sc->bnx_dev, 5348f33ac8a4SSepherosa Ziehau "could not set up %dth intr\n", i); 5349f33ac8a4SSepherosa Ziehau bnx_teardown_intr(sc, i); 53500c7da01dSSepherosa Ziehau return error; 53510c7da01dSSepherosa Ziehau } 5352f33ac8a4SSepherosa Ziehau } 53530c7da01dSSepherosa Ziehau return 0; 53540c7da01dSSepherosa Ziehau } 53550c7da01dSSepherosa Ziehau 53560c7da01dSSepherosa Ziehau static void 5357f33ac8a4SSepherosa Ziehau bnx_teardown_intr(struct bnx_softc *sc, int cnt) 5358f33ac8a4SSepherosa Ziehau { 5359f33ac8a4SSepherosa Ziehau int i; 5360f33ac8a4SSepherosa Ziehau 5361f33ac8a4SSepherosa Ziehau for (i = 0; i < cnt; ++i) { 5362f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 5363f33ac8a4SSepherosa Ziehau 5364f33ac8a4SSepherosa Ziehau bus_teardown_intr(sc->bnx_dev, intr->bnx_intr_res, 5365f33ac8a4SSepherosa Ziehau intr->bnx_intr_hand); 5366f33ac8a4SSepherosa Ziehau } 5367f33ac8a4SSepherosa Ziehau } 5368f33ac8a4SSepherosa Ziehau 5369f33ac8a4SSepherosa Ziehau static void 53700c7da01dSSepherosa Ziehau bnx_free_intr(struct bnx_softc *sc) 53710c7da01dSSepherosa Ziehau { 5372695a8586SSepherosa Ziehau if (sc->bnx_intr_type != PCI_INTR_TYPE_MSIX) { 5373f33ac8a4SSepherosa Ziehau struct bnx_intr_data *intr; 5374f33ac8a4SSepherosa Ziehau 5375f33ac8a4SSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt <= 1); 5376f33ac8a4SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 5377f33ac8a4SSepherosa Ziehau 5378f33ac8a4SSepherosa Ziehau if (intr->bnx_intr_res != NULL) { 53790c7da01dSSepherosa Ziehau bus_release_resource(sc->bnx_dev, SYS_RES_IRQ, 5380f33ac8a4SSepherosa Ziehau intr->bnx_intr_rid, intr->bnx_intr_res); 53810c7da01dSSepherosa Ziehau } 5382f33ac8a4SSepherosa Ziehau if (sc->bnx_intr_type == PCI_INTR_TYPE_MSI) 53830c7da01dSSepherosa Ziehau pci_release_msi(sc->bnx_dev); 5384695a8586SSepherosa Ziehau } else { 5385695a8586SSepherosa Ziehau bnx_free_msix(sc, TRUE); 5386695a8586SSepherosa Ziehau } 53870c7da01dSSepherosa Ziehau } 5388329f9016SSepherosa Ziehau 5389329f9016SSepherosa Ziehau static void 5390329f9016SSepherosa Ziehau bnx_setup_serialize(struct bnx_softc *sc) 5391329f9016SSepherosa Ziehau { 5392329f9016SSepherosa Ziehau int i, j; 5393329f9016SSepherosa Ziehau 5394329f9016SSepherosa Ziehau /* 5395329f9016SSepherosa Ziehau * Allocate serializer array 5396329f9016SSepherosa Ziehau */ 5397329f9016SSepherosa Ziehau 5398329f9016SSepherosa Ziehau /* Main + RX STD + TX + RX RET */ 5399329f9016SSepherosa Ziehau sc->bnx_serialize_cnt = 1 + 1 + sc->bnx_tx_ringcnt + sc->bnx_rx_retcnt; 5400329f9016SSepherosa Ziehau 5401329f9016SSepherosa Ziehau sc->bnx_serialize = 5402329f9016SSepherosa Ziehau kmalloc(sc->bnx_serialize_cnt * sizeof(struct lwkt_serialize *), 5403329f9016SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 5404329f9016SSepherosa Ziehau 5405329f9016SSepherosa Ziehau /* 5406329f9016SSepherosa Ziehau * Setup serializers 5407329f9016SSepherosa Ziehau * 5408329f9016SSepherosa Ziehau * NOTE: Order is critical 5409329f9016SSepherosa Ziehau */ 5410329f9016SSepherosa Ziehau 5411329f9016SSepherosa Ziehau i = 0; 5412329f9016SSepherosa Ziehau 5413329f9016SSepherosa Ziehau KKASSERT(i < sc->bnx_serialize_cnt); 5414329f9016SSepherosa Ziehau sc->bnx_serialize[i++] = &sc->bnx_main_serialize; 5415329f9016SSepherosa Ziehau 5416329f9016SSepherosa Ziehau KKASSERT(i < sc->bnx_serialize_cnt); 5417329f9016SSepherosa Ziehau sc->bnx_serialize[i++] = &sc->bnx_rx_std_ring.bnx_rx_std_serialize; 5418329f9016SSepherosa Ziehau 5419329f9016SSepherosa Ziehau for (j = 0; j < sc->bnx_rx_retcnt; ++j) { 5420329f9016SSepherosa Ziehau KKASSERT(i < sc->bnx_serialize_cnt); 5421329f9016SSepherosa Ziehau sc->bnx_serialize[i++] = 5422329f9016SSepherosa Ziehau &sc->bnx_rx_ret_ring[j].bnx_rx_ret_serialize; 5423329f9016SSepherosa Ziehau } 5424329f9016SSepherosa Ziehau 5425329f9016SSepherosa Ziehau for (j = 0; j < sc->bnx_tx_ringcnt; ++j) { 5426329f9016SSepherosa Ziehau KKASSERT(i < sc->bnx_serialize_cnt); 5427329f9016SSepherosa Ziehau sc->bnx_serialize[i++] = 5428329f9016SSepherosa Ziehau &sc->bnx_tx_ring[j].bnx_tx_serialize; 5429329f9016SSepherosa Ziehau } 5430329f9016SSepherosa Ziehau 5431329f9016SSepherosa Ziehau KKASSERT(i == sc->bnx_serialize_cnt); 5432329f9016SSepherosa Ziehau } 5433329f9016SSepherosa Ziehau 5434329f9016SSepherosa Ziehau static void 5435329f9016SSepherosa Ziehau bnx_serialize(struct ifnet *ifp, enum ifnet_serialize slz) 5436329f9016SSepherosa Ziehau { 5437329f9016SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 5438329f9016SSepherosa Ziehau 5439329f9016SSepherosa Ziehau ifnet_serialize_array_enter(sc->bnx_serialize, 5440329f9016SSepherosa Ziehau sc->bnx_serialize_cnt, slz); 5441329f9016SSepherosa Ziehau } 5442329f9016SSepherosa Ziehau 5443329f9016SSepherosa Ziehau static void 5444329f9016SSepherosa Ziehau bnx_deserialize(struct ifnet *ifp, enum ifnet_serialize slz) 5445329f9016SSepherosa Ziehau { 5446329f9016SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 5447329f9016SSepherosa Ziehau 5448329f9016SSepherosa Ziehau ifnet_serialize_array_exit(sc->bnx_serialize, 5449329f9016SSepherosa Ziehau sc->bnx_serialize_cnt, slz); 5450329f9016SSepherosa Ziehau } 5451329f9016SSepherosa Ziehau 5452329f9016SSepherosa Ziehau static int 5453329f9016SSepherosa Ziehau bnx_tryserialize(struct ifnet *ifp, enum ifnet_serialize slz) 5454329f9016SSepherosa Ziehau { 5455329f9016SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 5456329f9016SSepherosa Ziehau 5457329f9016SSepherosa Ziehau return ifnet_serialize_array_try(sc->bnx_serialize, 5458329f9016SSepherosa Ziehau sc->bnx_serialize_cnt, slz); 5459329f9016SSepherosa Ziehau } 5460329f9016SSepherosa Ziehau 5461329f9016SSepherosa Ziehau #ifdef INVARIANTS 5462329f9016SSepherosa Ziehau 5463329f9016SSepherosa Ziehau static void 5464329f9016SSepherosa Ziehau bnx_serialize_assert(struct ifnet *ifp, enum ifnet_serialize slz, 5465329f9016SSepherosa Ziehau boolean_t serialized) 5466329f9016SSepherosa Ziehau { 5467329f9016SSepherosa Ziehau struct bnx_softc *sc = ifp->if_softc; 5468329f9016SSepherosa Ziehau 5469329f9016SSepherosa Ziehau ifnet_serialize_array_assert(sc->bnx_serialize, sc->bnx_serialize_cnt, 5470329f9016SSepherosa Ziehau slz, serialized); 5471329f9016SSepherosa Ziehau } 5472329f9016SSepherosa Ziehau 5473329f9016SSepherosa Ziehau #endif /* INVARIANTS */ 54744fa38985SSepherosa Ziehau 54757dbaa833SSepherosa Ziehau static void 54767dbaa833SSepherosa Ziehau bnx_set_tick_cpuid(struct bnx_softc *sc, boolean_t polling) 54777dbaa833SSepherosa Ziehau { 54787dbaa833SSepherosa Ziehau if (polling) 54797dbaa833SSepherosa Ziehau sc->bnx_tick_cpuid = 0; /* XXX */ 54807dbaa833SSepherosa Ziehau else 54817dbaa833SSepherosa Ziehau sc->bnx_tick_cpuid = sc->bnx_intr_data[0].bnx_intr_cpuid; 54827dbaa833SSepherosa Ziehau } 5483841cdf08SSepherosa Ziehau 5484841cdf08SSepherosa Ziehau static void 5485841cdf08SSepherosa Ziehau bnx_rx_std_refill_ithread(void *xstd) 5486841cdf08SSepherosa Ziehau { 5487841cdf08SSepherosa Ziehau struct bnx_rx_std_ring *std = xstd; 5488841cdf08SSepherosa Ziehau struct globaldata *gd = mycpu; 5489841cdf08SSepherosa Ziehau 5490841cdf08SSepherosa Ziehau crit_enter_gd(gd); 5491841cdf08SSepherosa Ziehau 5492841cdf08SSepherosa Ziehau while (!std->bnx_rx_std_stop) { 5493841cdf08SSepherosa Ziehau if (std->bnx_rx_std_refill) { 5494841cdf08SSepherosa Ziehau lwkt_serialize_handler_call( 5495841cdf08SSepherosa Ziehau &std->bnx_rx_std_serialize, 5496841cdf08SSepherosa Ziehau bnx_rx_std_refill, std, NULL); 5497841cdf08SSepherosa Ziehau } 5498841cdf08SSepherosa Ziehau 5499841cdf08SSepherosa Ziehau crit_exit_gd(gd); 5500841cdf08SSepherosa Ziehau crit_enter_gd(gd); 5501841cdf08SSepherosa Ziehau 5502695a8586SSepherosa Ziehau atomic_poll_release_int(&std->bnx_rx_std_running); 5503695a8586SSepherosa Ziehau cpu_mfence(); 5504695a8586SSepherosa Ziehau 5505841cdf08SSepherosa Ziehau if (!std->bnx_rx_std_refill && !std->bnx_rx_std_stop) { 5506841cdf08SSepherosa Ziehau lwkt_deschedule_self(gd->gd_curthread); 5507841cdf08SSepherosa Ziehau lwkt_switch(); 5508841cdf08SSepherosa Ziehau } 5509841cdf08SSepherosa Ziehau } 5510841cdf08SSepherosa Ziehau 5511841cdf08SSepherosa Ziehau crit_exit_gd(gd); 5512841cdf08SSepherosa Ziehau 5513841cdf08SSepherosa Ziehau wakeup(std); 5514841cdf08SSepherosa Ziehau 5515841cdf08SSepherosa Ziehau lwkt_exit(); 5516841cdf08SSepherosa Ziehau } 5517841cdf08SSepherosa Ziehau 5518841cdf08SSepherosa Ziehau static void 5519841cdf08SSepherosa Ziehau bnx_rx_std_refill(void *xstd, void *frame __unused) 5520841cdf08SSepherosa Ziehau { 5521841cdf08SSepherosa Ziehau struct bnx_rx_std_ring *std = xstd; 5522695a8586SSepherosa Ziehau int cnt, refill_mask; 5523841cdf08SSepherosa Ziehau 5524841cdf08SSepherosa Ziehau again: 5525841cdf08SSepherosa Ziehau cnt = 0; 5526841cdf08SSepherosa Ziehau 5527841cdf08SSepherosa Ziehau cpu_lfence(); 5528695a8586SSepherosa Ziehau refill_mask = std->bnx_rx_std_refill; 5529695a8586SSepherosa Ziehau atomic_clear_int(&std->bnx_rx_std_refill, refill_mask); 5530841cdf08SSepherosa Ziehau 5531695a8586SSepherosa Ziehau while (refill_mask) { 5532695a8586SSepherosa Ziehau uint16_t check_idx = std->bnx_rx_std; 5533695a8586SSepherosa Ziehau int ret_idx; 5534695a8586SSepherosa Ziehau 5535695a8586SSepherosa Ziehau ret_idx = bsfl(refill_mask); 5536841cdf08SSepherosa Ziehau for (;;) { 5537841cdf08SSepherosa Ziehau struct bnx_rx_buf *rb; 5538695a8586SSepherosa Ziehau int refilled; 5539841cdf08SSepherosa Ziehau 5540841cdf08SSepherosa Ziehau BNX_INC(check_idx, BGE_STD_RX_RING_CNT); 5541841cdf08SSepherosa Ziehau rb = &std->bnx_rx_std_buf[check_idx]; 5542695a8586SSepherosa Ziehau refilled = rb->bnx_rx_refilled; 5543841cdf08SSepherosa Ziehau cpu_lfence(); 5544695a8586SSepherosa Ziehau if (refilled) { 5545841cdf08SSepherosa Ziehau bnx_setup_rxdesc_std(std, check_idx); 5546841cdf08SSepherosa Ziehau std->bnx_rx_std = check_idx; 5547841cdf08SSepherosa Ziehau ++cnt; 5548695a8586SSepherosa Ziehau if (cnt >= 8) { 5549625c3ba3SSepherosa Ziehau atomic_subtract_int( 5550625c3ba3SSepherosa Ziehau &std->bnx_rx_std_used, cnt); 5551695a8586SSepherosa Ziehau bnx_writembx(std->bnx_sc, 5552695a8586SSepherosa Ziehau BGE_MBX_RX_STD_PROD_LO, 5553695a8586SSepherosa Ziehau std->bnx_rx_std); 5554695a8586SSepherosa Ziehau cnt = 0; 5555695a8586SSepherosa Ziehau } 5556841cdf08SSepherosa Ziehau } else { 5557841cdf08SSepherosa Ziehau break; 5558841cdf08SSepherosa Ziehau } 5559841cdf08SSepherosa Ziehau } 5560695a8586SSepherosa Ziehau refill_mask &= ~(1 << ret_idx); 5561695a8586SSepherosa Ziehau } 5562841cdf08SSepherosa Ziehau 5563841cdf08SSepherosa Ziehau if (cnt) { 5564625c3ba3SSepherosa Ziehau atomic_subtract_int(&std->bnx_rx_std_used, cnt); 5565841cdf08SSepherosa Ziehau bnx_writembx(std->bnx_sc, BGE_MBX_RX_STD_PROD_LO, 5566841cdf08SSepherosa Ziehau std->bnx_rx_std); 5567841cdf08SSepherosa Ziehau } 5568841cdf08SSepherosa Ziehau 5569841cdf08SSepherosa Ziehau if (std->bnx_rx_std_refill) 5570841cdf08SSepherosa Ziehau goto again; 5571841cdf08SSepherosa Ziehau 5572841cdf08SSepherosa Ziehau atomic_poll_release_int(&std->bnx_rx_std_running); 5573841cdf08SSepherosa Ziehau cpu_mfence(); 5574841cdf08SSepherosa Ziehau 5575841cdf08SSepherosa Ziehau if (std->bnx_rx_std_refill) 5576841cdf08SSepherosa Ziehau goto again; 5577841cdf08SSepherosa Ziehau } 5578841cdf08SSepherosa Ziehau 5579841cdf08SSepherosa Ziehau static int 5580841cdf08SSepherosa Ziehau bnx_sysctl_std_refill(SYSCTL_HANDLER_ARGS) 5581841cdf08SSepherosa Ziehau { 5582841cdf08SSepherosa Ziehau struct bnx_softc *sc = (void *)arg1; 5583841cdf08SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 5584841cdf08SSepherosa Ziehau struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[0]; 5585841cdf08SSepherosa Ziehau int error, cntmax, i; 5586841cdf08SSepherosa Ziehau 5587841cdf08SSepherosa Ziehau cntmax = ret->bnx_rx_cntmax; 5588841cdf08SSepherosa Ziehau error = sysctl_handle_int(oidp, &cntmax, 0, req); 5589841cdf08SSepherosa Ziehau if (error || req->newptr == NULL) 5590841cdf08SSepherosa Ziehau return error; 5591841cdf08SSepherosa Ziehau 5592841cdf08SSepherosa Ziehau ifnet_serialize_all(ifp); 5593841cdf08SSepherosa Ziehau 5594625c3ba3SSepherosa Ziehau if ((cntmax * sc->bnx_rx_retcnt) >= BGE_STD_RX_RING_CNT / 2) { 5595841cdf08SSepherosa Ziehau error = EINVAL; 5596841cdf08SSepherosa Ziehau goto back; 5597841cdf08SSepherosa Ziehau } 5598841cdf08SSepherosa Ziehau 5599841cdf08SSepherosa Ziehau for (i = 0; i < sc->bnx_tx_ringcnt; ++i) 5600841cdf08SSepherosa Ziehau sc->bnx_rx_ret_ring[i].bnx_rx_cntmax = cntmax; 5601841cdf08SSepherosa Ziehau error = 0; 5602841cdf08SSepherosa Ziehau 5603841cdf08SSepherosa Ziehau back: 5604841cdf08SSepherosa Ziehau ifnet_deserialize_all(ifp); 5605841cdf08SSepherosa Ziehau 5606841cdf08SSepherosa Ziehau return error; 5607841cdf08SSepherosa Ziehau } 5608695a8586SSepherosa Ziehau 5609695a8586SSepherosa Ziehau static void 5610695a8586SSepherosa Ziehau bnx_init_rss(struct bnx_softc *sc) 5611695a8586SSepherosa Ziehau { 5612695a8586SSepherosa Ziehau uint8_t key[BGE_RSS_KEYREG_CNT * BGE_RSS_KEYREG_SIZE]; 5613695a8586SSepherosa Ziehau int i, j, r; 5614695a8586SSepherosa Ziehau 5615695a8586SSepherosa Ziehau KKASSERT(BNX_RSS_ENABLED(sc)); 5616695a8586SSepherosa Ziehau 56170f02bb87SSepherosa Ziehau /* 561802596bedSSepherosa Ziehau * Configure RSS redirect table. 56190f02bb87SSepherosa Ziehau */ 562002596bedSSepherosa Ziehau if_ringmap_rdrtable(sc->bnx_rx_rmap, sc->bnx_rdr_table, 562102596bedSSepherosa Ziehau BNX_RDRTABLE_SIZE); 5622695a8586SSepherosa Ziehau r = 0; 5623695a8586SSepherosa Ziehau for (j = 0; j < BGE_RSS_INDIR_TBL_CNT; ++j) { 5624695a8586SSepherosa Ziehau uint32_t tbl = 0; 5625695a8586SSepherosa Ziehau 5626695a8586SSepherosa Ziehau for (i = 0; i < BGE_RSS_INDIR_TBLENT_CNT; ++i) { 5627695a8586SSepherosa Ziehau uint32_t q; 5628695a8586SSepherosa Ziehau 562902596bedSSepherosa Ziehau q = sc->bnx_rdr_table[r]; 5630695a8586SSepherosa Ziehau tbl |= q << (BGE_RSS_INDIR_TBLENT_SHIFT * 5631695a8586SSepherosa Ziehau (BGE_RSS_INDIR_TBLENT_CNT - i - 1)); 5632695a8586SSepherosa Ziehau ++r; 5633695a8586SSepherosa Ziehau } 5634695a8586SSepherosa Ziehau 5635695a8586SSepherosa Ziehau BNX_RSS_DPRINTF(sc, 1, "tbl%d %08x\n", j, tbl); 5636695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_RSS_INDIR_TBL(j), tbl); 5637695a8586SSepherosa Ziehau } 5638695a8586SSepherosa Ziehau 5639695a8586SSepherosa Ziehau toeplitz_get_key(key, sizeof(key)); 5640695a8586SSepherosa Ziehau for (i = 0; i < BGE_RSS_KEYREG_CNT; ++i) { 5641695a8586SSepherosa Ziehau uint32_t keyreg; 5642695a8586SSepherosa Ziehau 5643695a8586SSepherosa Ziehau keyreg = BGE_RSS_KEYREG_VAL(key, i); 5644695a8586SSepherosa Ziehau 5645695a8586SSepherosa Ziehau BNX_RSS_DPRINTF(sc, 1, "key%d %08x\n", i, keyreg); 5646695a8586SSepherosa Ziehau CSR_WRITE_4(sc, BGE_RSS_KEYREG(i), keyreg); 5647695a8586SSepherosa Ziehau } 5648695a8586SSepherosa Ziehau } 5649695a8586SSepherosa Ziehau 5650695a8586SSepherosa Ziehau static void 5651695a8586SSepherosa Ziehau bnx_setup_ring_cnt(struct bnx_softc *sc) 5652695a8586SSepherosa Ziehau { 565302596bedSSepherosa Ziehau int msix_enable, msix_cnt, msix_ring, ring_max, ring_cnt; 5654695a8586SSepherosa Ziehau 565502596bedSSepherosa Ziehau /* One RX ring. */ 565602596bedSSepherosa Ziehau sc->bnx_rx_rmap = if_ringmap_alloc(sc->bnx_dev, 1, 1); 565702596bedSSepherosa Ziehau 565802596bedSSepherosa Ziehau if (netisr_ncpus == 1) 565902596bedSSepherosa Ziehau goto skip_rx; 5660695a8586SSepherosa Ziehau 5661695a8586SSepherosa Ziehau msix_enable = device_getenv_int(sc->bnx_dev, "msix.enable", 5662695a8586SSepherosa Ziehau bnx_msix_enable); 5663695a8586SSepherosa Ziehau if (!msix_enable) 566402596bedSSepherosa Ziehau goto skip_rx; 5665695a8586SSepherosa Ziehau 5666695a8586SSepherosa Ziehau /* 5667695a8586SSepherosa Ziehau * One MSI-X vector is dedicated to status or single TX queue, 5668695a8586SSepherosa Ziehau * so make sure that there are enough MSI-X vectors. 5669695a8586SSepherosa Ziehau */ 567002596bedSSepherosa Ziehau msix_cnt = pci_msix_count(sc->bnx_dev); 567102596bedSSepherosa Ziehau if (msix_cnt <= 1) 567202596bedSSepherosa Ziehau goto skip_rx; 567302596bedSSepherosa Ziehau if (bootverbose) 567402596bedSSepherosa Ziehau device_printf(sc->bnx_dev, "MSI-X count %d\n", msix_cnt); 567502596bedSSepherosa Ziehau msix_ring = msix_cnt - 1; 5676695a8586SSepherosa Ziehau 5677695a8586SSepherosa Ziehau /* 5678695a8586SSepherosa Ziehau * Setup RX ring count 5679695a8586SSepherosa Ziehau */ 5680695a8586SSepherosa Ziehau ring_max = BNX_RX_RING_MAX; 568102596bedSSepherosa Ziehau if (ring_max > msix_ring) 568202596bedSSepherosa Ziehau ring_max = msix_ring; 568302596bedSSepherosa Ziehau ring_cnt = device_getenv_int(sc->bnx_dev, "rx_rings", bnx_rx_rings); 5684695a8586SSepherosa Ziehau 568502596bedSSepherosa Ziehau if_ringmap_free(sc->bnx_rx_rmap); 568602596bedSSepherosa Ziehau sc->bnx_rx_rmap = if_ringmap_alloc(sc->bnx_dev, ring_cnt, ring_max); 5687695a8586SSepherosa Ziehau 568802596bedSSepherosa Ziehau skip_rx: 568902596bedSSepherosa Ziehau sc->bnx_rx_retcnt = if_ringmap_count(sc->bnx_rx_rmap); 5690695a8586SSepherosa Ziehau 5691695a8586SSepherosa Ziehau /* 5692695a8586SSepherosa Ziehau * Setup TX ring count 5693695a8586SSepherosa Ziehau * 5694695a8586SSepherosa Ziehau * Currently only BCM5719 and BCM5720 support multiple TX rings 5695695a8586SSepherosa Ziehau * and the TX ring count must be less than the RX ring count. 5696695a8586SSepherosa Ziehau */ 5697695a8586SSepherosa Ziehau if (sc->bnx_asicrev == BGE_ASICREV_BCM5719 || 5698695a8586SSepherosa Ziehau sc->bnx_asicrev == BGE_ASICREV_BCM5720) { 5699695a8586SSepherosa Ziehau ring_max = BNX_TX_RING_MAX; 5700695a8586SSepherosa Ziehau if (ring_max > sc->bnx_rx_retcnt) 5701695a8586SSepherosa Ziehau ring_max = sc->bnx_rx_retcnt; 570202596bedSSepherosa Ziehau ring_cnt = device_getenv_int(sc->bnx_dev, "tx_rings", 5703695a8586SSepherosa Ziehau bnx_tx_rings); 570402596bedSSepherosa Ziehau } else { 570502596bedSSepherosa Ziehau ring_max = 1; 570602596bedSSepherosa Ziehau ring_cnt = 1; 570702596bedSSepherosa Ziehau } 570802596bedSSepherosa Ziehau sc->bnx_tx_rmap = if_ringmap_alloc(sc->bnx_dev, ring_cnt, ring_max); 570902596bedSSepherosa Ziehau if_ringmap_align(sc->bnx_dev, sc->bnx_rx_rmap, sc->bnx_tx_rmap); 571002596bedSSepherosa Ziehau 571102596bedSSepherosa Ziehau sc->bnx_tx_ringcnt = if_ringmap_count(sc->bnx_tx_rmap); 571202596bedSSepherosa Ziehau KASSERT(sc->bnx_tx_ringcnt <= sc->bnx_rx_retcnt, 571302596bedSSepherosa Ziehau ("invalid TX ring count %d and RX ring count %d", 571402596bedSSepherosa Ziehau sc->bnx_tx_ringcnt, sc->bnx_rx_retcnt)); 571502596bedSSepherosa Ziehau 571602596bedSSepherosa Ziehau /* 571702596bedSSepherosa Ziehau * Setup interrupt count. 571802596bedSSepherosa Ziehau */ 571902596bedSSepherosa Ziehau if (sc->bnx_rx_retcnt == 1) { 572002596bedSSepherosa Ziehau sc->bnx_intr_cnt = 1; 572102596bedSSepherosa Ziehau } else { 572202596bedSSepherosa Ziehau /* 572302596bedSSepherosa Ziehau * We need one extra MSI-X vector for link status or 572402596bedSSepherosa Ziehau * TX ring (if only one TX ring is enabled). 572502596bedSSepherosa Ziehau */ 572602596bedSSepherosa Ziehau sc->bnx_intr_cnt = sc->bnx_rx_retcnt + 1; 572702596bedSSepherosa Ziehau } 572802596bedSSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt <= BNX_INTR_MAX); 572902596bedSSepherosa Ziehau 573002596bedSSepherosa Ziehau if (bootverbose) { 573102596bedSSepherosa Ziehau device_printf(sc->bnx_dev, "intr count %d, " 573202596bedSSepherosa Ziehau "RX ring %d, TX ring %d\n", sc->bnx_intr_cnt, 573302596bedSSepherosa Ziehau sc->bnx_rx_retcnt, sc->bnx_tx_ringcnt); 5734695a8586SSepherosa Ziehau } 5735695a8586SSepherosa Ziehau } 5736695a8586SSepherosa Ziehau 5737695a8586SSepherosa Ziehau static int 5738695a8586SSepherosa Ziehau bnx_alloc_msix(struct bnx_softc *sc) 5739695a8586SSepherosa Ziehau { 5740695a8586SSepherosa Ziehau struct bnx_intr_data *intr; 5741695a8586SSepherosa Ziehau boolean_t setup = FALSE; 574202596bedSSepherosa Ziehau int error, i; 5743695a8586SSepherosa Ziehau 5744695a8586SSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt > 1); 5745695a8586SSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt == sc->bnx_rx_retcnt + 1); 5746695a8586SSepherosa Ziehau 5747695a8586SSepherosa Ziehau if (sc->bnx_flags & BNX_FLAG_RXTX_BUNDLE) { 5748695a8586SSepherosa Ziehau /* 5749695a8586SSepherosa Ziehau * Link status 5750695a8586SSepherosa Ziehau */ 5751695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 5752695a8586SSepherosa Ziehau 5753695a8586SSepherosa Ziehau intr->bnx_intr_serialize = &sc->bnx_main_serialize; 5754695a8586SSepherosa Ziehau intr->bnx_saved_status_tag = &sc->bnx_saved_status_tag; 5755695a8586SSepherosa Ziehau 5756695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_status; 5757695a8586SSepherosa Ziehau intr->bnx_intr_arg = sc; 5758695a8586SSepherosa Ziehau intr->bnx_intr_cpuid = 0; /* XXX */ 5759695a8586SSepherosa Ziehau 5760695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, sizeof(intr->bnx_intr_desc0), 5761695a8586SSepherosa Ziehau "%s sts", device_get_nameunit(sc->bnx_dev)); 5762695a8586SSepherosa Ziehau intr->bnx_intr_desc = intr->bnx_intr_desc0; 5763695a8586SSepherosa Ziehau 5764695a8586SSepherosa Ziehau /* 5765695a8586SSepherosa Ziehau * RX/TX rings 5766695a8586SSepherosa Ziehau */ 5767695a8586SSepherosa Ziehau for (i = 1; i < sc->bnx_intr_cnt; ++i) { 5768695a8586SSepherosa Ziehau int idx = i - 1; 5769695a8586SSepherosa Ziehau 5770695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[i]; 5771695a8586SSepherosa Ziehau 5772695a8586SSepherosa Ziehau KKASSERT(idx < sc->bnx_rx_retcnt); 5773695a8586SSepherosa Ziehau intr->bnx_ret = &sc->bnx_rx_ret_ring[idx]; 5774695a8586SSepherosa Ziehau if (idx < sc->bnx_tx_ringcnt) { 5775695a8586SSepherosa Ziehau intr->bnx_txr = &sc->bnx_tx_ring[idx]; 5776695a8586SSepherosa Ziehau intr->bnx_ret->bnx_txr = intr->bnx_txr; 5777695a8586SSepherosa Ziehau } 5778695a8586SSepherosa Ziehau 5779695a8586SSepherosa Ziehau intr->bnx_intr_serialize = 5780695a8586SSepherosa Ziehau &intr->bnx_ret->bnx_rx_ret_serialize; 5781695a8586SSepherosa Ziehau intr->bnx_saved_status_tag = 5782695a8586SSepherosa Ziehau &intr->bnx_ret->bnx_saved_status_tag; 5783695a8586SSepherosa Ziehau 5784695a8586SSepherosa Ziehau intr->bnx_intr_arg = intr->bnx_ret; 578502596bedSSepherosa Ziehau intr->bnx_intr_cpuid = 578602596bedSSepherosa Ziehau if_ringmap_cpumap(sc->bnx_rx_rmap, idx); 578702596bedSSepherosa Ziehau KKASSERT(intr->bnx_intr_cpuid < netisr_ncpus); 5788695a8586SSepherosa Ziehau 5789695a8586SSepherosa Ziehau if (intr->bnx_txr == NULL) { 5790695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_rx; 5791695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_rx; 5792695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, 5793695a8586SSepherosa Ziehau sizeof(intr->bnx_intr_desc0), "%s rx%d", 5794695a8586SSepherosa Ziehau device_get_nameunit(sc->bnx_dev), idx); 5795695a8586SSepherosa Ziehau } else { 579602596bedSSepherosa Ziehau #ifdef INVARIANTS 579702596bedSSepherosa Ziehau int tx_cpuid; 579802596bedSSepherosa Ziehau #endif 579902596bedSSepherosa Ziehau 5800695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_rxtx; 5801695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_rxtx; 5802695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, 5803695a8586SSepherosa Ziehau sizeof(intr->bnx_intr_desc0), "%s rxtx%d", 5804695a8586SSepherosa Ziehau device_get_nameunit(sc->bnx_dev), idx); 5805695a8586SSepherosa Ziehau 580602596bedSSepherosa Ziehau #ifdef INVARIANTS 580702596bedSSepherosa Ziehau tx_cpuid = if_ringmap_cpumap(sc->bnx_tx_rmap, 580802596bedSSepherosa Ziehau idx); 580902596bedSSepherosa Ziehau KASSERT(intr->bnx_intr_cpuid == tx_cpuid, 581002596bedSSepherosa Ziehau ("RX intr cpu%d, TX intr cpu%d, mismatch", 581102596bedSSepherosa Ziehau intr->bnx_intr_cpuid, tx_cpuid)); 581202596bedSSepherosa Ziehau #endif 5813695a8586SSepherosa Ziehau intr->bnx_txr->bnx_tx_cpuid = 5814695a8586SSepherosa Ziehau intr->bnx_intr_cpuid; 5815695a8586SSepherosa Ziehau } 5816695a8586SSepherosa Ziehau intr->bnx_intr_desc = intr->bnx_intr_desc0; 5817695a8586SSepherosa Ziehau 5818695a8586SSepherosa Ziehau intr->bnx_ret->bnx_msix_mbx = intr->bnx_intr_mbx; 5819695a8586SSepherosa Ziehau } 5820695a8586SSepherosa Ziehau } else { 5821695a8586SSepherosa Ziehau /* 582202596bedSSepherosa Ziehau * TX ring0 and link status 5823695a8586SSepherosa Ziehau */ 5824695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[0]; 5825695a8586SSepherosa Ziehau 5826695a8586SSepherosa Ziehau intr->bnx_txr = &sc->bnx_tx_ring[0]; 5827695a8586SSepherosa Ziehau intr->bnx_intr_serialize = &sc->bnx_main_serialize; 5828695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_tx; 5829695a8586SSepherosa Ziehau intr->bnx_saved_status_tag = 5830695a8586SSepherosa Ziehau &intr->bnx_txr->bnx_saved_status_tag; 5831695a8586SSepherosa Ziehau 5832695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_tx_status; 5833695a8586SSepherosa Ziehau intr->bnx_intr_arg = intr->bnx_txr; 583402596bedSSepherosa Ziehau intr->bnx_intr_cpuid = if_ringmap_cpumap(sc->bnx_tx_rmap, 0); 583502596bedSSepherosa Ziehau KKASSERT(intr->bnx_intr_cpuid < netisr_ncpus); 5836695a8586SSepherosa Ziehau 5837695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, sizeof(intr->bnx_intr_desc0), 5838695a8586SSepherosa Ziehau "%s ststx", device_get_nameunit(sc->bnx_dev)); 5839695a8586SSepherosa Ziehau intr->bnx_intr_desc = intr->bnx_intr_desc0; 5840695a8586SSepherosa Ziehau 5841695a8586SSepherosa Ziehau intr->bnx_txr->bnx_tx_cpuid = intr->bnx_intr_cpuid; 5842695a8586SSepherosa Ziehau 5843695a8586SSepherosa Ziehau /* 5844695a8586SSepherosa Ziehau * RX rings 5845695a8586SSepherosa Ziehau */ 5846695a8586SSepherosa Ziehau for (i = 1; i < sc->bnx_intr_cnt; ++i) { 5847695a8586SSepherosa Ziehau int idx = i - 1; 5848695a8586SSepherosa Ziehau 5849695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[i]; 5850695a8586SSepherosa Ziehau 5851695a8586SSepherosa Ziehau KKASSERT(idx < sc->bnx_rx_retcnt); 5852695a8586SSepherosa Ziehau intr->bnx_ret = &sc->bnx_rx_ret_ring[idx]; 5853695a8586SSepherosa Ziehau intr->bnx_intr_serialize = 5854695a8586SSepherosa Ziehau &intr->bnx_ret->bnx_rx_ret_serialize; 5855695a8586SSepherosa Ziehau intr->bnx_intr_check = bnx_check_intr_rx; 5856695a8586SSepherosa Ziehau intr->bnx_saved_status_tag = 5857695a8586SSepherosa Ziehau &intr->bnx_ret->bnx_saved_status_tag; 5858695a8586SSepherosa Ziehau 5859695a8586SSepherosa Ziehau intr->bnx_intr_func = bnx_msix_rx; 5860695a8586SSepherosa Ziehau intr->bnx_intr_arg = intr->bnx_ret; 586102596bedSSepherosa Ziehau intr->bnx_intr_cpuid = 586202596bedSSepherosa Ziehau if_ringmap_cpumap(sc->bnx_rx_rmap, idx); 586302596bedSSepherosa Ziehau KKASSERT(intr->bnx_intr_cpuid < netisr_ncpus); 5864695a8586SSepherosa Ziehau 5865695a8586SSepherosa Ziehau ksnprintf(intr->bnx_intr_desc0, 5866695a8586SSepherosa Ziehau sizeof(intr->bnx_intr_desc0), "%s rx%d", 5867695a8586SSepherosa Ziehau device_get_nameunit(sc->bnx_dev), idx); 5868695a8586SSepherosa Ziehau intr->bnx_intr_desc = intr->bnx_intr_desc0; 5869695a8586SSepherosa Ziehau 5870695a8586SSepherosa Ziehau intr->bnx_ret->bnx_msix_mbx = intr->bnx_intr_mbx; 5871695a8586SSepherosa Ziehau } 5872695a8586SSepherosa Ziehau } 5873695a8586SSepherosa Ziehau 58749f5082d5SSepherosa Ziehau if (BNX_IS_5717_PLUS(sc)) { 5875695a8586SSepherosa Ziehau sc->bnx_msix_mem_rid = PCIR_BAR(4); 58769f5082d5SSepherosa Ziehau } else { 58779f5082d5SSepherosa Ziehau if (sc->bnx_res2 == NULL) 5878715109c2SSepherosa Ziehau sc->bnx_msix_mem_rid = PCIR_BAR(2); 58799f5082d5SSepherosa Ziehau } 58809f5082d5SSepherosa Ziehau if (sc->bnx_msix_mem_rid != 0) { 5881695a8586SSepherosa Ziehau sc->bnx_msix_mem_res = bus_alloc_resource_any(sc->bnx_dev, 5882695a8586SSepherosa Ziehau SYS_RES_MEMORY, &sc->bnx_msix_mem_rid, RF_ACTIVE); 5883695a8586SSepherosa Ziehau if (sc->bnx_msix_mem_res == NULL) { 58849f5082d5SSepherosa Ziehau device_printf(sc->bnx_dev, 58859f5082d5SSepherosa Ziehau "could not alloc MSI-X table\n"); 5886695a8586SSepherosa Ziehau return ENXIO; 5887695a8586SSepherosa Ziehau } 58889f5082d5SSepherosa Ziehau } 5889695a8586SSepherosa Ziehau 5890695a8586SSepherosa Ziehau bnx_enable_msi(sc, TRUE); 5891695a8586SSepherosa Ziehau 5892695a8586SSepherosa Ziehau error = pci_setup_msix(sc->bnx_dev); 5893695a8586SSepherosa Ziehau if (error) { 5894695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, "could not setup MSI-X\n"); 5895695a8586SSepherosa Ziehau goto back; 5896695a8586SSepherosa Ziehau } 5897695a8586SSepherosa Ziehau setup = TRUE; 5898695a8586SSepherosa Ziehau 5899695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 5900695a8586SSepherosa Ziehau intr = &sc->bnx_intr_data[i]; 5901695a8586SSepherosa Ziehau 5902695a8586SSepherosa Ziehau error = pci_alloc_msix_vector(sc->bnx_dev, i, 5903695a8586SSepherosa Ziehau &intr->bnx_intr_rid, intr->bnx_intr_cpuid); 5904695a8586SSepherosa Ziehau if (error) { 5905695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, 5906695a8586SSepherosa Ziehau "could not alloc MSI-X %d on cpu%d\n", 5907695a8586SSepherosa Ziehau i, intr->bnx_intr_cpuid); 5908695a8586SSepherosa Ziehau goto back; 5909695a8586SSepherosa Ziehau } 5910695a8586SSepherosa Ziehau 5911695a8586SSepherosa Ziehau intr->bnx_intr_res = bus_alloc_resource_any(sc->bnx_dev, 5912695a8586SSepherosa Ziehau SYS_RES_IRQ, &intr->bnx_intr_rid, RF_ACTIVE); 5913695a8586SSepherosa Ziehau if (intr->bnx_intr_res == NULL) { 5914695a8586SSepherosa Ziehau device_printf(sc->bnx_dev, 5915695a8586SSepherosa Ziehau "could not alloc MSI-X %d resource\n", i); 5916695a8586SSepherosa Ziehau error = ENXIO; 5917695a8586SSepherosa Ziehau goto back; 5918695a8586SSepherosa Ziehau } 5919695a8586SSepherosa Ziehau } 5920695a8586SSepherosa Ziehau 5921695a8586SSepherosa Ziehau pci_enable_msix(sc->bnx_dev); 5922695a8586SSepherosa Ziehau sc->bnx_intr_type = PCI_INTR_TYPE_MSIX; 5923695a8586SSepherosa Ziehau back: 5924695a8586SSepherosa Ziehau if (error) 5925695a8586SSepherosa Ziehau bnx_free_msix(sc, setup); 5926695a8586SSepherosa Ziehau return error; 5927695a8586SSepherosa Ziehau } 5928695a8586SSepherosa Ziehau 5929695a8586SSepherosa Ziehau static void 5930695a8586SSepherosa Ziehau bnx_free_msix(struct bnx_softc *sc, boolean_t setup) 5931695a8586SSepherosa Ziehau { 5932695a8586SSepherosa Ziehau int i; 5933695a8586SSepherosa Ziehau 5934695a8586SSepherosa Ziehau KKASSERT(sc->bnx_intr_cnt > 1); 5935695a8586SSepherosa Ziehau 5936695a8586SSepherosa Ziehau for (i = 0; i < sc->bnx_intr_cnt; ++i) { 5937695a8586SSepherosa Ziehau struct bnx_intr_data *intr = &sc->bnx_intr_data[i]; 5938695a8586SSepherosa Ziehau 5939695a8586SSepherosa Ziehau if (intr->bnx_intr_res != NULL) { 5940695a8586SSepherosa Ziehau bus_release_resource(sc->bnx_dev, SYS_RES_IRQ, 5941695a8586SSepherosa Ziehau intr->bnx_intr_rid, intr->bnx_intr_res); 5942695a8586SSepherosa Ziehau } 5943695a8586SSepherosa Ziehau if (intr->bnx_intr_rid >= 0) { 5944695a8586SSepherosa Ziehau pci_release_msix_vector(sc->bnx_dev, 5945695a8586SSepherosa Ziehau intr->bnx_intr_rid); 5946695a8586SSepherosa Ziehau } 5947695a8586SSepherosa Ziehau } 5948695a8586SSepherosa Ziehau if (setup) 5949695a8586SSepherosa Ziehau pci_teardown_msix(sc->bnx_dev); 5950695a8586SSepherosa Ziehau } 5951695a8586SSepherosa Ziehau 5952695a8586SSepherosa Ziehau static void 5953695a8586SSepherosa Ziehau bnx_rx_std_refill_sched_ipi(void *xret) 5954695a8586SSepherosa Ziehau { 5955695a8586SSepherosa Ziehau struct bnx_rx_ret_ring *ret = xret; 5956695a8586SSepherosa Ziehau struct bnx_rx_std_ring *std = ret->bnx_std; 5957695a8586SSepherosa Ziehau struct globaldata *gd = mycpu; 5958695a8586SSepherosa Ziehau 5959695a8586SSepherosa Ziehau crit_enter_gd(gd); 5960695a8586SSepherosa Ziehau 5961695a8586SSepherosa Ziehau atomic_set_int(&std->bnx_rx_std_refill, ret->bnx_rx_mask); 5962695a8586SSepherosa Ziehau cpu_sfence(); 5963695a8586SSepherosa Ziehau 5964c450d4d8SSepherosa Ziehau KKASSERT(std->bnx_rx_std_ithread->td_gd == gd); 5965c450d4d8SSepherosa Ziehau lwkt_schedule(std->bnx_rx_std_ithread); 5966695a8586SSepherosa Ziehau 5967695a8586SSepherosa Ziehau crit_exit_gd(gd); 5968695a8586SSepherosa Ziehau } 5969695a8586SSepherosa Ziehau 5970695a8586SSepherosa Ziehau static void 5971695a8586SSepherosa Ziehau bnx_rx_std_refill_stop(void *xstd) 5972695a8586SSepherosa Ziehau { 5973695a8586SSepherosa Ziehau struct bnx_rx_std_ring *std = xstd; 5974695a8586SSepherosa Ziehau struct globaldata *gd = mycpu; 5975695a8586SSepherosa Ziehau 5976695a8586SSepherosa Ziehau crit_enter_gd(gd); 5977695a8586SSepherosa Ziehau 5978695a8586SSepherosa Ziehau std->bnx_rx_std_stop = 1; 5979695a8586SSepherosa Ziehau cpu_sfence(); 5980695a8586SSepherosa Ziehau 5981c450d4d8SSepherosa Ziehau KKASSERT(std->bnx_rx_std_ithread->td_gd == gd); 5982c450d4d8SSepherosa Ziehau lwkt_schedule(std->bnx_rx_std_ithread); 5983695a8586SSepherosa Ziehau 5984695a8586SSepherosa Ziehau crit_exit_gd(gd); 5985695a8586SSepherosa Ziehau } 5986695a8586SSepherosa Ziehau 5987695a8586SSepherosa Ziehau static void 5988695a8586SSepherosa Ziehau bnx_serialize_skipmain(struct bnx_softc *sc) 5989695a8586SSepherosa Ziehau { 5990695a8586SSepherosa Ziehau lwkt_serialize_array_enter(sc->bnx_serialize, 5991695a8586SSepherosa Ziehau sc->bnx_serialize_cnt, 1); 5992695a8586SSepherosa Ziehau } 5993695a8586SSepherosa Ziehau 5994695a8586SSepherosa Ziehau static void 5995695a8586SSepherosa Ziehau bnx_deserialize_skipmain(struct bnx_softc *sc) 5996695a8586SSepherosa Ziehau { 5997695a8586SSepherosa Ziehau lwkt_serialize_array_exit(sc->bnx_serialize, 5998695a8586SSepherosa Ziehau sc->bnx_serialize_cnt, 1); 5999695a8586SSepherosa Ziehau } 6000695a8586SSepherosa Ziehau 6001695a8586SSepherosa Ziehau static void 6002695a8586SSepherosa Ziehau bnx_rx_std_refill_sched(struct bnx_rx_ret_ring *ret, 6003695a8586SSepherosa Ziehau struct bnx_rx_std_ring *std) 6004695a8586SSepherosa Ziehau { 6005695a8586SSepherosa Ziehau struct globaldata *gd = mycpu; 6006695a8586SSepherosa Ziehau 6007695a8586SSepherosa Ziehau ret->bnx_rx_cnt = 0; 6008695a8586SSepherosa Ziehau cpu_sfence(); 6009695a8586SSepherosa Ziehau 6010695a8586SSepherosa Ziehau crit_enter_gd(gd); 6011695a8586SSepherosa Ziehau 6012695a8586SSepherosa Ziehau atomic_set_int(&std->bnx_rx_std_refill, ret->bnx_rx_mask); 6013695a8586SSepherosa Ziehau cpu_sfence(); 6014695a8586SSepherosa Ziehau if (atomic_poll_acquire_int(&std->bnx_rx_std_running)) { 6015c450d4d8SSepherosa Ziehau if (std->bnx_rx_std_ithread->td_gd == gd) { 6016c450d4d8SSepherosa Ziehau lwkt_schedule(std->bnx_rx_std_ithread); 6017695a8586SSepherosa Ziehau } else { 6018c450d4d8SSepherosa Ziehau lwkt_send_ipiq(std->bnx_rx_std_ithread->td_gd, 6019695a8586SSepherosa Ziehau bnx_rx_std_refill_sched_ipi, ret); 6020695a8586SSepherosa Ziehau } 6021695a8586SSepherosa Ziehau } 6022695a8586SSepherosa Ziehau 6023695a8586SSepherosa Ziehau crit_exit_gd(gd); 6024695a8586SSepherosa Ziehau } 6025b19ddf7eSSepherosa Ziehau 6026b19ddf7eSSepherosa Ziehau static struct pktinfo * 6027b19ddf7eSSepherosa Ziehau bnx_rss_info(struct pktinfo *pi, const struct bge_rx_bd *cur_rx) 6028b19ddf7eSSepherosa Ziehau { 6029b19ddf7eSSepherosa Ziehau /* Don't pick up IPv6 packet */ 6030b19ddf7eSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_IPV6) 6031b19ddf7eSSepherosa Ziehau return NULL; 6032b19ddf7eSSepherosa Ziehau 6033b19ddf7eSSepherosa Ziehau /* Don't pick up IP packet w/o IP checksum */ 6034b19ddf7eSSepherosa Ziehau if ((cur_rx->bge_flags & BGE_RXBDFLAG_IP_CSUM) == 0 || 6035b19ddf7eSSepherosa Ziehau (cur_rx->bge_error_flag & BGE_RXERRFLAG_IP_CSUM_NOK)) 6036b19ddf7eSSepherosa Ziehau return NULL; 6037b19ddf7eSSepherosa Ziehau 6038b19ddf7eSSepherosa Ziehau /* Don't pick up IP packet w/o TCP/UDP checksum */ 6039b19ddf7eSSepherosa Ziehau if ((cur_rx->bge_flags & BGE_RXBDFLAG_TCP_UDP_CSUM) == 0) 6040b19ddf7eSSepherosa Ziehau return NULL; 6041b19ddf7eSSepherosa Ziehau 6042b19ddf7eSSepherosa Ziehau /* May be IP fragment */ 6043b19ddf7eSSepherosa Ziehau if (cur_rx->bge_tcp_udp_csum != 0xffff) 6044b19ddf7eSSepherosa Ziehau return NULL; 6045b19ddf7eSSepherosa Ziehau 6046b19ddf7eSSepherosa Ziehau if (cur_rx->bge_flags & BGE_RXBDFLAG_TCP_UDP_IS_TCP) 6047b19ddf7eSSepherosa Ziehau pi->pi_l3proto = IPPROTO_TCP; 6048b19ddf7eSSepherosa Ziehau else 6049b19ddf7eSSepherosa Ziehau pi->pi_l3proto = IPPROTO_UDP; 6050b19ddf7eSSepherosa Ziehau pi->pi_netisr = NETISR_IP; 6051b19ddf7eSSepherosa Ziehau pi->pi_flags = 0; 6052b19ddf7eSSepherosa Ziehau 6053b19ddf7eSSepherosa Ziehau return pi; 6054b19ddf7eSSepherosa Ziehau } 60554aa71e73SSepherosa Ziehau 60564aa71e73SSepherosa Ziehau static void 60574aa71e73SSepherosa Ziehau bnx_sig_pre_reset(struct bnx_softc *sc, int type) 60584aa71e73SSepherosa Ziehau { 60594aa71e73SSepherosa Ziehau if (type == BNX_RESET_START || type == BNX_RESET_SUSPEND) 60604aa71e73SSepherosa Ziehau bnx_ape_driver_state_change(sc, type); 60614aa71e73SSepherosa Ziehau } 60624aa71e73SSepherosa Ziehau 60634aa71e73SSepherosa Ziehau static void 60644aa71e73SSepherosa Ziehau bnx_sig_post_reset(struct bnx_softc *sc, int type) 60654aa71e73SSepherosa Ziehau { 60664aa71e73SSepherosa Ziehau if (type == BNX_RESET_SHUTDOWN) 60674aa71e73SSepherosa Ziehau bnx_ape_driver_state_change(sc, type); 60689f5082d5SSepherosa Ziehau } 60699f5082d5SSepherosa Ziehau 60709f5082d5SSepherosa Ziehau /* 60719f5082d5SSepherosa Ziehau * Clear all stale locks and select the lock for this driver instance. 60729f5082d5SSepherosa Ziehau */ 60739f5082d5SSepherosa Ziehau static void 60749f5082d5SSepherosa Ziehau bnx_ape_lock_init(struct bnx_softc *sc) 60759f5082d5SSepherosa Ziehau { 60769f5082d5SSepherosa Ziehau uint32_t bit, regbase; 60779f5082d5SSepherosa Ziehau int i; 60789f5082d5SSepherosa Ziehau 60799f5082d5SSepherosa Ziehau regbase = BGE_APE_PER_LOCK_GRANT; 60809f5082d5SSepherosa Ziehau 60819f5082d5SSepherosa Ziehau /* Clear any stale locks. */ 60829f5082d5SSepherosa Ziehau for (i = BGE_APE_LOCK_PHY0; i <= BGE_APE_LOCK_GPIO; i++) { 60839f5082d5SSepherosa Ziehau switch (i) { 60849f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY0: 60859f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY1: 60869f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY2: 60879f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY3: 60889f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_GRANT_DRIVER0; 60899f5082d5SSepherosa Ziehau break; 60909f5082d5SSepherosa Ziehau 60919f5082d5SSepherosa Ziehau default: 60929f5082d5SSepherosa Ziehau if (sc->bnx_func_addr == 0) 60939f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_GRANT_DRIVER0; 60949f5082d5SSepherosa Ziehau else 60959f5082d5SSepherosa Ziehau bit = 1 << sc->bnx_func_addr; 60969f5082d5SSepherosa Ziehau break; 60979f5082d5SSepherosa Ziehau } 60989f5082d5SSepherosa Ziehau APE_WRITE_4(sc, regbase + 4 * i, bit); 60999f5082d5SSepherosa Ziehau } 61009f5082d5SSepherosa Ziehau 61019f5082d5SSepherosa Ziehau /* Select the PHY lock based on the device's function number. */ 61029f5082d5SSepherosa Ziehau switch (sc->bnx_func_addr) { 61039f5082d5SSepherosa Ziehau case 0: 61049f5082d5SSepherosa Ziehau sc->bnx_phy_ape_lock = BGE_APE_LOCK_PHY0; 61059f5082d5SSepherosa Ziehau break; 61069f5082d5SSepherosa Ziehau 61079f5082d5SSepherosa Ziehau case 1: 61089f5082d5SSepherosa Ziehau sc->bnx_phy_ape_lock = BGE_APE_LOCK_PHY1; 61099f5082d5SSepherosa Ziehau break; 61109f5082d5SSepherosa Ziehau 61119f5082d5SSepherosa Ziehau case 2: 61129f5082d5SSepherosa Ziehau sc->bnx_phy_ape_lock = BGE_APE_LOCK_PHY2; 61139f5082d5SSepherosa Ziehau break; 61149f5082d5SSepherosa Ziehau 61159f5082d5SSepherosa Ziehau case 3: 61169f5082d5SSepherosa Ziehau sc->bnx_phy_ape_lock = BGE_APE_LOCK_PHY3; 61179f5082d5SSepherosa Ziehau break; 61189f5082d5SSepherosa Ziehau 61199f5082d5SSepherosa Ziehau default: 61209f5082d5SSepherosa Ziehau device_printf(sc->bnx_dev, 61219f5082d5SSepherosa Ziehau "PHY lock not supported on this function\n"); 61229f5082d5SSepherosa Ziehau break; 61239f5082d5SSepherosa Ziehau } 61249f5082d5SSepherosa Ziehau } 61259f5082d5SSepherosa Ziehau 61269f5082d5SSepherosa Ziehau /* 61279f5082d5SSepherosa Ziehau * Check for APE firmware, set flags, and print version info. 61289f5082d5SSepherosa Ziehau */ 61299f5082d5SSepherosa Ziehau static void 61309f5082d5SSepherosa Ziehau bnx_ape_read_fw_ver(struct bnx_softc *sc) 61319f5082d5SSepherosa Ziehau { 61329f5082d5SSepherosa Ziehau const char *fwtype; 61339f5082d5SSepherosa Ziehau uint32_t apedata, features; 61349f5082d5SSepherosa Ziehau 61359f5082d5SSepherosa Ziehau /* Check for a valid APE signature in shared memory. */ 61369f5082d5SSepherosa Ziehau apedata = APE_READ_4(sc, BGE_APE_SEG_SIG); 61379f5082d5SSepherosa Ziehau if (apedata != BGE_APE_SEG_SIG_MAGIC) { 61389f5082d5SSepherosa Ziehau device_printf(sc->bnx_dev, "no APE signature\n"); 61399f5082d5SSepherosa Ziehau sc->bnx_mfw_flags &= ~BNX_MFW_ON_APE; 61409f5082d5SSepherosa Ziehau return; 61419f5082d5SSepherosa Ziehau } 61429f5082d5SSepherosa Ziehau 61439f5082d5SSepherosa Ziehau /* Check if APE firmware is running. */ 61449f5082d5SSepherosa Ziehau apedata = APE_READ_4(sc, BGE_APE_FW_STATUS); 61459f5082d5SSepherosa Ziehau if ((apedata & BGE_APE_FW_STATUS_READY) == 0) { 61469f5082d5SSepherosa Ziehau device_printf(sc->bnx_dev, "APE signature found " 61479f5082d5SSepherosa Ziehau "but FW status not ready! 0x%08x\n", apedata); 61489f5082d5SSepherosa Ziehau return; 61499f5082d5SSepherosa Ziehau } 61509f5082d5SSepherosa Ziehau 61519f5082d5SSepherosa Ziehau sc->bnx_mfw_flags |= BNX_MFW_ON_APE; 61529f5082d5SSepherosa Ziehau 61539f5082d5SSepherosa Ziehau /* Fetch the APE firwmare type and version. */ 61549f5082d5SSepherosa Ziehau apedata = APE_READ_4(sc, BGE_APE_FW_VERSION); 61559f5082d5SSepherosa Ziehau features = APE_READ_4(sc, BGE_APE_FW_FEATURES); 61569f5082d5SSepherosa Ziehau if (features & BGE_APE_FW_FEATURE_NCSI) { 61579f5082d5SSepherosa Ziehau sc->bnx_mfw_flags |= BNX_MFW_TYPE_NCSI; 61589f5082d5SSepherosa Ziehau fwtype = "NCSI"; 61599f5082d5SSepherosa Ziehau } else if (features & BGE_APE_FW_FEATURE_DASH) { 61609f5082d5SSepherosa Ziehau sc->bnx_mfw_flags |= BNX_MFW_TYPE_DASH; 61619f5082d5SSepherosa Ziehau fwtype = "DASH"; 61629f5082d5SSepherosa Ziehau } else { 61639f5082d5SSepherosa Ziehau fwtype = "UNKN"; 61649f5082d5SSepherosa Ziehau } 61659f5082d5SSepherosa Ziehau 61669f5082d5SSepherosa Ziehau /* Print the APE firmware version. */ 61679f5082d5SSepherosa Ziehau device_printf(sc->bnx_dev, "APE FW version: %s v%d.%d.%d.%d\n", 61689f5082d5SSepherosa Ziehau fwtype, 61699f5082d5SSepherosa Ziehau (apedata & BGE_APE_FW_VERSION_MAJMSK) >> BGE_APE_FW_VERSION_MAJSFT, 61709f5082d5SSepherosa Ziehau (apedata & BGE_APE_FW_VERSION_MINMSK) >> BGE_APE_FW_VERSION_MINSFT, 61719f5082d5SSepherosa Ziehau (apedata & BGE_APE_FW_VERSION_REVMSK) >> BGE_APE_FW_VERSION_REVSFT, 61729f5082d5SSepherosa Ziehau (apedata & BGE_APE_FW_VERSION_BLDMSK)); 61739f5082d5SSepherosa Ziehau } 61749f5082d5SSepherosa Ziehau 61759f5082d5SSepherosa Ziehau static int 61769f5082d5SSepherosa Ziehau bnx_ape_lock(struct bnx_softc *sc, int locknum) 61779f5082d5SSepherosa Ziehau { 61789f5082d5SSepherosa Ziehau uint32_t bit, gnt, req, status; 61799f5082d5SSepherosa Ziehau int i, off; 61809f5082d5SSepherosa Ziehau 61819f5082d5SSepherosa Ziehau if ((sc->bnx_mfw_flags & BNX_MFW_ON_APE) == 0) 61829f5082d5SSepherosa Ziehau return 0; 61839f5082d5SSepherosa Ziehau 61849f5082d5SSepherosa Ziehau /* Lock request/grant registers have different bases. */ 61859f5082d5SSepherosa Ziehau req = BGE_APE_PER_LOCK_REQ; 61869f5082d5SSepherosa Ziehau gnt = BGE_APE_PER_LOCK_GRANT; 61879f5082d5SSepherosa Ziehau 61889f5082d5SSepherosa Ziehau off = 4 * locknum; 61899f5082d5SSepherosa Ziehau 61909f5082d5SSepherosa Ziehau switch (locknum) { 61919f5082d5SSepherosa Ziehau case BGE_APE_LOCK_GPIO: 61929f5082d5SSepherosa Ziehau /* Lock required when using GPIO. */ 61939f5082d5SSepherosa Ziehau if (sc->bnx_func_addr == 0) 61949f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_REQ_DRIVER0; 61959f5082d5SSepherosa Ziehau else 61969f5082d5SSepherosa Ziehau bit = 1 << sc->bnx_func_addr; 61979f5082d5SSepherosa Ziehau break; 61989f5082d5SSepherosa Ziehau 61999f5082d5SSepherosa Ziehau case BGE_APE_LOCK_GRC: 62009f5082d5SSepherosa Ziehau /* Lock required to reset the device. */ 62019f5082d5SSepherosa Ziehau if (sc->bnx_func_addr == 0) 62029f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_REQ_DRIVER0; 62039f5082d5SSepherosa Ziehau else 62049f5082d5SSepherosa Ziehau bit = 1 << sc->bnx_func_addr; 62059f5082d5SSepherosa Ziehau break; 62069f5082d5SSepherosa Ziehau 62079f5082d5SSepherosa Ziehau case BGE_APE_LOCK_MEM: 62089f5082d5SSepherosa Ziehau /* Lock required when accessing certain APE memory. */ 62099f5082d5SSepherosa Ziehau if (sc->bnx_func_addr == 0) 62109f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_REQ_DRIVER0; 62119f5082d5SSepherosa Ziehau else 62129f5082d5SSepherosa Ziehau bit = 1 << sc->bnx_func_addr; 62139f5082d5SSepherosa Ziehau break; 62149f5082d5SSepherosa Ziehau 62159f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY0: 62169f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY1: 62179f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY2: 62189f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY3: 62199f5082d5SSepherosa Ziehau /* Lock required when accessing PHYs. */ 62209f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_REQ_DRIVER0; 62219f5082d5SSepherosa Ziehau break; 62229f5082d5SSepherosa Ziehau 62239f5082d5SSepherosa Ziehau default: 62249f5082d5SSepherosa Ziehau return EINVAL; 62259f5082d5SSepherosa Ziehau } 62269f5082d5SSepherosa Ziehau 62279f5082d5SSepherosa Ziehau /* Request a lock. */ 62289f5082d5SSepherosa Ziehau APE_WRITE_4(sc, req + off, bit); 62299f5082d5SSepherosa Ziehau 62309f5082d5SSepherosa Ziehau /* Wait up to 1 second to acquire lock. */ 62319f5082d5SSepherosa Ziehau for (i = 0; i < 20000; i++) { 62329f5082d5SSepherosa Ziehau status = APE_READ_4(sc, gnt + off); 62339f5082d5SSepherosa Ziehau if (status == bit) 62349f5082d5SSepherosa Ziehau break; 62359f5082d5SSepherosa Ziehau DELAY(50); 62369f5082d5SSepherosa Ziehau } 62379f5082d5SSepherosa Ziehau 62389f5082d5SSepherosa Ziehau /* Handle any errors. */ 62399f5082d5SSepherosa Ziehau if (status != bit) { 62409f5082d5SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "APE lock %d request failed! " 62419f5082d5SSepherosa Ziehau "request = 0x%04x[0x%04x], status = 0x%04x[0x%04x]\n", 62429f5082d5SSepherosa Ziehau locknum, req + off, bit & 0xFFFF, gnt + off, 62439f5082d5SSepherosa Ziehau status & 0xFFFF); 62449f5082d5SSepherosa Ziehau /* Revoke the lock request. */ 62459f5082d5SSepherosa Ziehau APE_WRITE_4(sc, gnt + off, bit); 62469f5082d5SSepherosa Ziehau return EBUSY; 62479f5082d5SSepherosa Ziehau } 62489f5082d5SSepherosa Ziehau 62499f5082d5SSepherosa Ziehau return 0; 62509f5082d5SSepherosa Ziehau } 62519f5082d5SSepherosa Ziehau 62529f5082d5SSepherosa Ziehau static void 62539f5082d5SSepherosa Ziehau bnx_ape_unlock(struct bnx_softc *sc, int locknum) 62549f5082d5SSepherosa Ziehau { 62559f5082d5SSepherosa Ziehau uint32_t bit, gnt; 62569f5082d5SSepherosa Ziehau int off; 62579f5082d5SSepherosa Ziehau 62589f5082d5SSepherosa Ziehau if ((sc->bnx_mfw_flags & BNX_MFW_ON_APE) == 0) 62599f5082d5SSepherosa Ziehau return; 62609f5082d5SSepherosa Ziehau 62619f5082d5SSepherosa Ziehau gnt = BGE_APE_PER_LOCK_GRANT; 62629f5082d5SSepherosa Ziehau 62639f5082d5SSepherosa Ziehau off = 4 * locknum; 62649f5082d5SSepherosa Ziehau 62659f5082d5SSepherosa Ziehau switch (locknum) { 62669f5082d5SSepherosa Ziehau case BGE_APE_LOCK_GPIO: 62679f5082d5SSepherosa Ziehau if (sc->bnx_func_addr == 0) 62689f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_GRANT_DRIVER0; 62699f5082d5SSepherosa Ziehau else 62709f5082d5SSepherosa Ziehau bit = 1 << sc->bnx_func_addr; 62719f5082d5SSepherosa Ziehau break; 62729f5082d5SSepherosa Ziehau 62739f5082d5SSepherosa Ziehau case BGE_APE_LOCK_GRC: 62749f5082d5SSepherosa Ziehau if (sc->bnx_func_addr == 0) 62759f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_GRANT_DRIVER0; 62769f5082d5SSepherosa Ziehau else 62779f5082d5SSepherosa Ziehau bit = 1 << sc->bnx_func_addr; 62789f5082d5SSepherosa Ziehau break; 62799f5082d5SSepherosa Ziehau 62809f5082d5SSepherosa Ziehau case BGE_APE_LOCK_MEM: 62819f5082d5SSepherosa Ziehau if (sc->bnx_func_addr == 0) 62829f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_GRANT_DRIVER0; 62839f5082d5SSepherosa Ziehau else 62849f5082d5SSepherosa Ziehau bit = 1 << sc->bnx_func_addr; 62859f5082d5SSepherosa Ziehau break; 62869f5082d5SSepherosa Ziehau 62879f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY0: 62889f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY1: 62899f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY2: 62909f5082d5SSepherosa Ziehau case BGE_APE_LOCK_PHY3: 62919f5082d5SSepherosa Ziehau bit = BGE_APE_LOCK_GRANT_DRIVER0; 62929f5082d5SSepherosa Ziehau break; 62939f5082d5SSepherosa Ziehau 62949f5082d5SSepherosa Ziehau default: 62959f5082d5SSepherosa Ziehau return; 62969f5082d5SSepherosa Ziehau } 62979f5082d5SSepherosa Ziehau 62989f5082d5SSepherosa Ziehau APE_WRITE_4(sc, gnt + off, bit); 62999f5082d5SSepherosa Ziehau } 63009f5082d5SSepherosa Ziehau 63019f5082d5SSepherosa Ziehau /* 63029f5082d5SSepherosa Ziehau * Send an event to the APE firmware. 63039f5082d5SSepherosa Ziehau */ 63049f5082d5SSepherosa Ziehau static void 63059f5082d5SSepherosa Ziehau bnx_ape_send_event(struct bnx_softc *sc, uint32_t event) 63069f5082d5SSepherosa Ziehau { 63079f5082d5SSepherosa Ziehau uint32_t apedata; 63089f5082d5SSepherosa Ziehau int i; 63099f5082d5SSepherosa Ziehau 63109f5082d5SSepherosa Ziehau /* NCSI does not support APE events. */ 63119f5082d5SSepherosa Ziehau if ((sc->bnx_mfw_flags & BNX_MFW_ON_APE) == 0) 63129f5082d5SSepherosa Ziehau return; 63139f5082d5SSepherosa Ziehau 63149f5082d5SSepherosa Ziehau /* Wait up to 1ms for APE to service previous event. */ 63159f5082d5SSepherosa Ziehau for (i = 10; i > 0; i--) { 63169f5082d5SSepherosa Ziehau if (bnx_ape_lock(sc, BGE_APE_LOCK_MEM) != 0) 63179f5082d5SSepherosa Ziehau break; 63189f5082d5SSepherosa Ziehau apedata = APE_READ_4(sc, BGE_APE_EVENT_STATUS); 63199f5082d5SSepherosa Ziehau if ((apedata & BGE_APE_EVENT_STATUS_EVENT_PENDING) == 0) { 63209f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_EVENT_STATUS, event | 63219f5082d5SSepherosa Ziehau BGE_APE_EVENT_STATUS_EVENT_PENDING); 63229f5082d5SSepherosa Ziehau bnx_ape_unlock(sc, BGE_APE_LOCK_MEM); 63239f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_EVENT, BGE_APE_EVENT_1); 63249f5082d5SSepherosa Ziehau break; 63259f5082d5SSepherosa Ziehau } 63269f5082d5SSepherosa Ziehau bnx_ape_unlock(sc, BGE_APE_LOCK_MEM); 63279f5082d5SSepherosa Ziehau DELAY(100); 63289f5082d5SSepherosa Ziehau } 63299f5082d5SSepherosa Ziehau if (i == 0) { 63309f5082d5SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 63319f5082d5SSepherosa Ziehau "APE event 0x%08x send timed out\n", event); 63329f5082d5SSepherosa Ziehau } 63339f5082d5SSepherosa Ziehau } 63349f5082d5SSepherosa Ziehau 63359f5082d5SSepherosa Ziehau static void 63369f5082d5SSepherosa Ziehau bnx_ape_driver_state_change(struct bnx_softc *sc, int kind) 63379f5082d5SSepherosa Ziehau { 63389f5082d5SSepherosa Ziehau uint32_t apedata, event; 63399f5082d5SSepherosa Ziehau 63409f5082d5SSepherosa Ziehau if ((sc->bnx_mfw_flags & BNX_MFW_ON_APE) == 0) 63419f5082d5SSepherosa Ziehau return; 63429f5082d5SSepherosa Ziehau 63439f5082d5SSepherosa Ziehau switch (kind) { 63449f5082d5SSepherosa Ziehau case BNX_RESET_START: 63459f5082d5SSepherosa Ziehau /* If this is the first load, clear the load counter. */ 63469f5082d5SSepherosa Ziehau apedata = APE_READ_4(sc, BGE_APE_HOST_SEG_SIG); 63479f5082d5SSepherosa Ziehau if (apedata != BGE_APE_HOST_SEG_SIG_MAGIC) { 63489f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_HOST_INIT_COUNT, 0); 63499f5082d5SSepherosa Ziehau } else { 63509f5082d5SSepherosa Ziehau apedata = APE_READ_4(sc, BGE_APE_HOST_INIT_COUNT); 63519f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_HOST_INIT_COUNT, ++apedata); 63529f5082d5SSepherosa Ziehau } 63539f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_HOST_SEG_SIG, 63549f5082d5SSepherosa Ziehau BGE_APE_HOST_SEG_SIG_MAGIC); 63559f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_HOST_SEG_LEN, 63569f5082d5SSepherosa Ziehau BGE_APE_HOST_SEG_LEN_MAGIC); 63579f5082d5SSepherosa Ziehau 63589f5082d5SSepherosa Ziehau /* Add some version info if bnx(4) supports it. */ 63599f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_HOST_DRIVER_ID, 63609f5082d5SSepherosa Ziehau BGE_APE_HOST_DRIVER_ID_MAGIC(1, 0)); 63619f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_HOST_BEHAVIOR, 63629f5082d5SSepherosa Ziehau BGE_APE_HOST_BEHAV_NO_PHYLOCK); 63639f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_HOST_HEARTBEAT_INT_MS, 63649f5082d5SSepherosa Ziehau BGE_APE_HOST_HEARTBEAT_INT_DISABLE); 63659f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_HOST_DRVR_STATE, 63669f5082d5SSepherosa Ziehau BGE_APE_HOST_DRVR_STATE_START); 63679f5082d5SSepherosa Ziehau event = BGE_APE_EVENT_STATUS_STATE_START; 63689f5082d5SSepherosa Ziehau break; 63699f5082d5SSepherosa Ziehau 63709f5082d5SSepherosa Ziehau case BNX_RESET_SHUTDOWN: 63719f5082d5SSepherosa Ziehau APE_WRITE_4(sc, BGE_APE_HOST_DRVR_STATE, 63729f5082d5SSepherosa Ziehau BGE_APE_HOST_DRVR_STATE_UNLOAD); 63739f5082d5SSepherosa Ziehau event = BGE_APE_EVENT_STATUS_STATE_UNLOAD; 63749f5082d5SSepherosa Ziehau break; 63759f5082d5SSepherosa Ziehau 63769f5082d5SSepherosa Ziehau case BNX_RESET_SUSPEND: 63779f5082d5SSepherosa Ziehau event = BGE_APE_EVENT_STATUS_STATE_SUSPEND; 63789f5082d5SSepherosa Ziehau break; 63799f5082d5SSepherosa Ziehau 63809f5082d5SSepherosa Ziehau default: 63819f5082d5SSepherosa Ziehau return; 63829f5082d5SSepherosa Ziehau } 63839f5082d5SSepherosa Ziehau 63849f5082d5SSepherosa Ziehau bnx_ape_send_event(sc, event | BGE_APE_EVENT_STATUS_DRIVER_EVNT | 63859f5082d5SSepherosa Ziehau BGE_APE_EVENT_STATUS_STATE_CHNGE); 63864aa71e73SSepherosa Ziehau } 6387