From owner-p4-projects@FreeBSD.ORG Tue Aug 21 13:16:18 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 7028D16A41B; Tue, 21 Aug 2007 13:16:18 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0F00516A417 for ; Tue, 21 Aug 2007 13:16:18 +0000 (UTC) (envelope-from thioretic@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id EF9F713C458 for ; Tue, 21 Aug 2007 13:16:17 +0000 (UTC) (envelope-from thioretic@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id l7LDGH78015579 for ; Tue, 21 Aug 2007 13:16:17 GMT (envelope-from thioretic@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l7LDGF7G015576 for perforce@freebsd.org; Tue, 21 Aug 2007 13:16:15 GMT (envelope-from thioretic@FreeBSD.org) Date: Tue, 21 Aug 2007 13:16:15 GMT Message-Id: <200708211316.l7LDGF7G015576@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to thioretic@FreeBSD.org using -f From: Maxim Zhuravlev To: Perforce Change Reviews Cc: Subject: PERFORCE change 125498 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Aug 2007 13:16:18 -0000 http://perforce.freebsd.org/chv.cgi?CH=125498 Change 125498 by thioretic@thioretic_freebox on 2007/08/21 13:15:57 IFC Affected files ... .. //depot/projects/soc2007/thioretic_gidl/dev/bce/if_bce.c#3 integrate .. //depot/projects/soc2007/thioretic_gidl/dev/bce/if_bcereg.h#2 integrate .. //depot/projects/soc2007/thioretic_gidl/modules/if_tap/Makefile#2 integrate Differences ... ==== //depot/projects/soc2007/thioretic_gidl/dev/bce/if_bce.c#3 (text) ==== @@ -1,3 +1,4 @@ +>>>> ORIGINAL if_bce.c#17 /*- * Copyright (c) 2006-2007 Broadcom Corporation * David Christensen . All rights reserved. @@ -7504,3 +7505,15136 @@ return; } #endif +==== THEIRS if_bce.c#18 +/*- + * Copyright (c) 2006-2007 Broadcom Corporation + * David Christensen . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Broadcom Corporation nor the name of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written consent. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/bce/if_bce.c,v 1.2.2.20 2007/08/20 21:47:49 davidch Exp $"); + +/* + * The following controllers are supported by this driver: + * BCM5706C A2, A3 + * BCM5708C B1, B2 + * + * The following controllers are not supported by this driver: + * BCM5706C A0, A1 + * BCM5706S A0, A1, A2, A3 + * BCM5708C A0, B0 + * BCM5708S A0, B0, B1, B2 + */ + +#include "opt_bce.h" + +#include +#include + +/****************************************************************************/ +/* BCE Debug Options */ +/****************************************************************************/ +#ifdef BCE_DEBUG + u32 bce_debug = BCE_WARN; + + /* 0 = Never */ + /* 1 = 1 in 2,147,483,648 */ + /* 256 = 1 in 8,388,608 */ + /* 2048 = 1 in 1,048,576 */ + /* 65536 = 1 in 32,768 */ + /* 1048576 = 1 in 2,048 */ + /* 268435456 = 1 in 8 */ + /* 536870912 = 1 in 4 */ + /* 1073741824 = 1 in 2 */ + + /* Controls how often the l2_fhdr frame error check will fail. */ + int bce_debug_l2fhdr_status_check = 0; + + /* Controls how often the unexpected attention check will fail. */ + int bce_debug_unexpected_attention = 0; + + /* Controls how often to simulate an mbuf allocation failure. */ + int bce_debug_mbuf_allocation_failure = 0; + + /* Controls how often to simulate a DMA mapping failure. */ + int bce_debug_dma_map_addr_failure = 0; + + /* Controls how often to simulate a bootcode failure. */ + int bce_debug_bootcode_running_failure = 0; +#endif + + +/****************************************************************************/ +/* PCI Device ID Table */ +/* */ +/* Used by bce_probe() to identify the devices supported by this driver. */ +/****************************************************************************/ +#define BCE_DEVDESC_MAX 64 + +static struct bce_type bce_devs[] = { + /* BCM5706C Controllers and OEM boards. */ + { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, HP_VENDORID, 0x3101, + "HP NC370T Multifunction Gigabit Server Adapter" }, + { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, HP_VENDORID, 0x3106, + "HP NC370i Multifunction Gigabit Server Adapter" }, + { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, PCI_ANY_ID, PCI_ANY_ID, + "Broadcom NetXtreme II BCM5706 1000Base-T" }, + + /* BCM5706S controllers and OEM boards. */ + { BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, HP_VENDORID, 0x3102, + "HP NC370F Multifunction Gigabit Server Adapter" }, + { BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, PCI_ANY_ID, PCI_ANY_ID, + "Broadcom NetXtreme II BCM5706 1000Base-SX" }, + + /* BCM5708C controllers and OEM boards. */ + { BRCM_VENDORID, BRCM_DEVICEID_BCM5708, PCI_ANY_ID, PCI_ANY_ID, + "Broadcom NetXtreme II BCM5708 1000Base-T" }, + + /* BCM5708S controllers and OEM boards. */ + { BRCM_VENDORID, BRCM_DEVICEID_BCM5708S, PCI_ANY_ID, PCI_ANY_ID, + "Broadcom NetXtreme II BCM5708 1000Base-SX" }, + { 0, 0, 0, 0, NULL } +}; + + +/****************************************************************************/ +/* Supported Flash NVRAM device data. */ +/****************************************************************************/ +static struct flash_spec flash_table[] = +{ + /* Slow EEPROM */ + {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400, + 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, + SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, + "EEPROM - slow"}, + /* Expansion entry 0001 */ + {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 0001"}, + /* Saifun SA25F010 (non-buffered flash) */ + /* strap, cfg1, & write1 need updates */ + {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2, + "Non-buffered flash (128kB)"}, + /* Saifun SA25F020 (non-buffered flash) */ + /* strap, cfg1, & write1 need updates */ + {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4, + "Non-buffered flash (256kB)"}, + /* Expansion entry 0100 */ + {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 0100"}, + /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */ + {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406, + 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, + ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2, + "Entry 0101: ST M45PE10 (128kB non-bufferred)"}, + /* Entry 0110: ST M45PE20 (non-buffered flash)*/ + {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406, + 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, + ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4, + "Entry 0110: ST M45PE20 (256kB non-bufferred)"}, + /* Saifun SA25F005 (non-buffered flash) */ + /* strap, cfg1, & write1 need updates */ + {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE, + "Non-buffered flash (64kB)"}, + /* Fast EEPROM */ + {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400, + 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, + SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, + "EEPROM - fast"}, + /* Expansion entry 1001 */ + {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1001"}, + /* Expansion entry 1010 */ + {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1010"}, + /* ATMEL AT45DB011B (buffered flash) */ + {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400, + 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, + BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE, + "Buffered flash (128kB)"}, + /* Expansion entry 1100 */ + {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1100"}, + /* Expansion entry 1101 */ + {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1101"}, + /* Ateml Expansion entry 1110 */ + {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400, + 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, + BUFFERED_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1110 (Atmel)"}, + /* ATMEL AT45DB021B (buffered flash) */ + {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400, + 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, + BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2, + "Buffered flash (256kB)"}, +}; + + +/****************************************************************************/ +/* FreeBSD device entry points. */ +/****************************************************************************/ +static int bce_probe (device_t); +static int bce_attach (device_t); +static int bce_detach (device_t); +static void bce_shutdown (device_t); + + +/****************************************************************************/ +/* BCE Debug Data Structure Dump Routines */ +/****************************************************************************/ +#ifdef BCE_DEBUG +static void bce_dump_mbuf (struct bce_softc *, struct mbuf *); +static void bce_dump_tx_mbuf_chain (struct bce_softc *, int, int); +static void bce_dump_rx_mbuf_chain (struct bce_softc *, int, int); +static void bce_dump_txbd (struct bce_softc *, int, struct tx_bd *); +static void bce_dump_rxbd (struct bce_softc *, int, struct rx_bd *); +static void bce_dump_l2fhdr (struct bce_softc *, int, struct l2_fhdr *); +static void bce_dump_tx_chain (struct bce_softc *, int, int); +static void bce_dump_rx_chain (struct bce_softc *, int, int); +static void bce_dump_status_block (struct bce_softc *); +static void bce_dump_stats_block (struct bce_softc *); +static void bce_dump_driver_state (struct bce_softc *); +static void bce_dump_hw_state (struct bce_softc *); +static void bce_dump_bc_state (struct bce_softc *); +static void bce_breakpoint (struct bce_softc *); +#endif + + +/****************************************************************************/ +/* BCE Register/Memory Access Routines */ +/****************************************************************************/ +static u32 bce_reg_rd_ind (struct bce_softc *, u32); +static void bce_reg_wr_ind (struct bce_softc *, u32, u32); +static void bce_ctx_wr (struct bce_softc *, u32, u32, u32); +static int bce_miibus_read_reg (device_t, int, int); +static int bce_miibus_write_reg (device_t, int, int, int); +static void bce_miibus_statchg (device_t); + + +/****************************************************************************/ +/* BCE NVRAM Access Routines */ +/****************************************************************************/ +static int bce_acquire_nvram_lock (struct bce_softc *); +static int bce_release_nvram_lock (struct bce_softc *); +static void bce_enable_nvram_access (struct bce_softc *); +static void bce_disable_nvram_access(struct bce_softc *); +static int bce_nvram_read_dword (struct bce_softc *, u32, u8 *, u32); +static int bce_init_nvram (struct bce_softc *); +static int bce_nvram_read (struct bce_softc *, u32, u8 *, int); +static int bce_nvram_test (struct bce_softc *); +#ifdef BCE_NVRAM_WRITE_SUPPORT +static int bce_enable_nvram_write (struct bce_softc *); +static void bce_disable_nvram_write (struct bce_softc *); +static int bce_nvram_erase_page (struct bce_softc *, u32); +static int bce_nvram_write_dword (struct bce_softc *, u32, u8 *, u32); +static int bce_nvram_write (struct bce_softc *, u32, u8 *, int); +#endif + +/****************************************************************************/ +/* */ +/****************************************************************************/ +static void bce_dma_map_addr (void *, bus_dma_segment_t *, int, int); +static int bce_dma_alloc (device_t); +static void bce_dma_free (struct bce_softc *); +static void bce_release_resources (struct bce_softc *); + +/****************************************************************************/ +/* BCE Firmware Synchronization and Load */ +/****************************************************************************/ +static int bce_fw_sync (struct bce_softc *, u32); +static void bce_load_rv2p_fw (struct bce_softc *, u32 *, u32, u32); +static void bce_load_cpu_fw (struct bce_softc *, struct cpu_reg *, struct fw_info *); +static void bce_init_cpus (struct bce_softc *); + +static void bce_stop (struct bce_softc *); +static int bce_reset (struct bce_softc *, u32); +static int bce_chipinit (struct bce_softc *); +static int bce_blockinit (struct bce_softc *); +static int bce_get_buf (struct bce_softc *, struct mbuf *, u16 *, u16 *, u32 *); + +static int bce_init_tx_chain (struct bce_softc *); +static void bce_fill_rx_chain (struct bce_softc *); +static int bce_init_rx_chain (struct bce_softc *); +static void bce_free_rx_chain (struct bce_softc *); +static void bce_free_tx_chain (struct bce_softc *); + +static int bce_tx_encap (struct bce_softc *, struct mbuf **); +static void bce_start_locked (struct ifnet *); +static void bce_start (struct ifnet *); +static int bce_ioctl (struct ifnet *, u_long, caddr_t); +static void bce_watchdog (struct bce_softc *); +static int bce_ifmedia_upd (struct ifnet *); +static void bce_ifmedia_upd_locked (struct ifnet *); +static void bce_ifmedia_sts (struct ifnet *, struct ifmediareq *); +static void bce_init_locked (struct bce_softc *); +static void bce_init (void *); +static void bce_mgmt_init_locked (struct bce_softc *sc); + +static void bce_init_context (struct bce_softc *); +static void bce_get_mac_addr (struct bce_softc *); +static void bce_set_mac_addr (struct bce_softc *); +static void bce_phy_intr (struct bce_softc *); +static void bce_rx_intr (struct bce_softc *); +static void bce_tx_intr (struct bce_softc *); +static void bce_disable_intr (struct bce_softc *); +static void bce_enable_intr (struct bce_softc *); + +#ifdef DEVICE_POLLING +static void bce_poll_locked (struct ifnet *, enum poll_cmd, int); +static void bce_poll (struct ifnet *, enum poll_cmd, int); +#endif +static void bce_intr (void *); +static void bce_set_rx_mode (struct bce_softc *); +static void bce_stats_update (struct bce_softc *); +static void bce_tick (void *); +static void bce_pulse (void *); +static void bce_add_sysctls (struct bce_softc *); + + +/****************************************************************************/ +/* FreeBSD device dispatch table. */ +/****************************************************************************/ +static device_method_t bce_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bce_probe), + DEVMETHOD(device_attach, bce_attach), + DEVMETHOD(device_detach, bce_detach), + DEVMETHOD(device_shutdown, bce_shutdown), + + /* bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + + /* MII interface */ + DEVMETHOD(miibus_readreg, bce_miibus_read_reg), + DEVMETHOD(miibus_writereg, bce_miibus_write_reg), + DEVMETHOD(miibus_statchg, bce_miibus_statchg), + + { 0, 0 } +}; + +static driver_t bce_driver = { + "bce", + bce_methods, + sizeof(struct bce_softc) +}; + +static devclass_t bce_devclass; + +MODULE_DEPEND(bce, pci, 1, 1, 1); +MODULE_DEPEND(bce, ether, 1, 1, 1); +MODULE_DEPEND(bce, miibus, 1, 1, 1); + +DRIVER_MODULE(bce, pci, bce_driver, bce_devclass, 0, 0); +DRIVER_MODULE(miibus, bce, miibus_driver, miibus_devclass, 0, 0); + + +/****************************************************************************/ +/* Tunable device values */ +/****************************************************************************/ +static int bce_msi_enable = 1; + +/* Allowable values are 0 (IRQ only) and 1 (IRQ or MSI) */ +TUNABLE_INT("hw.bce.msi_enable", &bce_msi_enable); +SYSCTL_NODE(_hw, OID_AUTO, bce, CTLFLAG_RD, 0, "bce driver parameters"); +SYSCTL_UINT(_hw_bce, OID_AUTO, msi_enable, CTLFLAG_RDTUN, &bce_msi_enable, 0, +"MSI | INTx selector"); + +/****************************************************************************/ +/* Device probe function. */ +/* */ +/* Compares the device to the driver's list of supported devices and */ +/* reports back to the OS whether this is the right driver for the device. */ +/* */ +/* Returns: */ +/* BUS_PROBE_DEFAULT on success, positive value on failure. */ +/****************************************************************************/ +static int +bce_probe(device_t dev) +{ + struct bce_type *t; + struct bce_softc *sc; + char *descbuf; + u16 vid = 0, did = 0, svid = 0, sdid = 0; + + t = bce_devs; + + sc = device_get_softc(dev); + bzero(sc, sizeof(struct bce_softc)); + sc->bce_unit = device_get_unit(dev); + sc->bce_dev = dev; + + /* Get the data for the device to be probed. */ + vid = pci_get_vendor(dev); + did = pci_get_device(dev); + svid = pci_get_subvendor(dev); + sdid = pci_get_subdevice(dev); + + DBPRINT(sc, BCE_VERBOSE_LOAD, + "%s(); VID = 0x%04X, DID = 0x%04X, SVID = 0x%04X, " + "SDID = 0x%04X\n", __FUNCTION__, vid, did, svid, sdid); + + /* Look through the list of known devices for a match. */ + while(t->bce_name != NULL) { + + if ((vid == t->bce_vid) && (did == t->bce_did) && + ((svid == t->bce_svid) || (t->bce_svid == PCI_ANY_ID)) && + ((sdid == t->bce_sdid) || (t->bce_sdid == PCI_ANY_ID))) { + + descbuf = malloc(BCE_DEVDESC_MAX, M_TEMP, M_NOWAIT); + + if (descbuf == NULL) + return(ENOMEM); + + /* Print out the device identity. */ + snprintf(descbuf, BCE_DEVDESC_MAX, "%s (%c%d)", + t->bce_name, + (((pci_read_config(dev, PCIR_REVID, 4) & 0xf0) >> 4) + 'A'), + (pci_read_config(dev, PCIR_REVID, 4) & 0xf)); + + device_set_desc_copy(dev, descbuf); + free(descbuf, M_TEMP); + return(BUS_PROBE_DEFAULT); + } + t++; + } + + return(ENXIO); +} + + +/****************************************************************************/ +/* Device attach function. */ +/* */ +/* Allocates device resources, performs secondary chip identification, */ +/* resets and initializes the hardware, and initializes driver instance */ +/* variables. */ +/* */ +/* Returns: */ +/* 0 on success, positive value on failure. */ +/****************************************************************************/ +static int +bce_attach(device_t dev) +{ + struct bce_softc *sc; + struct ifnet *ifp; + u32 val; + int count, mbuf, rid, rc = 0; + + sc = device_get_softc(dev); + sc->bce_dev = dev; + + DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__); + + mbuf = device_get_unit(dev); + + /* Set initial device and PHY flags */ + sc->bce_flags = 0; + sc->bce_phy_flags = 0; + + sc->bce_unit = mbuf; + + pci_enable_busmaster(dev); + + /* Allocate PCI memory resources. */ + rid = PCIR_BAR(0); + sc->bce_res_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE | PCI_RF_DENSE); + + if (sc->bce_res_mem == NULL) { + BCE_PRINTF("%s(%d): PCI memory allocation failed\n", + __FILE__, __LINE__); + rc = ENXIO; + goto bce_attach_fail; + } + + /* Get various resource handles. */ + sc->bce_btag = rman_get_bustag(sc->bce_res_mem); + sc->bce_bhandle = rman_get_bushandle(sc->bce_res_mem); + sc->bce_vhandle = (vm_offset_t) rman_get_virtual(sc->bce_res_mem); + + /* If MSI is enabled in the driver, get the vector count. */ + count = bce_msi_enable ? pci_msi_count(dev) : 0; + + /* Allocate PCI IRQ resources. */ + if (count == 1 && pci_alloc_msi(dev, &count) == 0 && count == 1) { + rid = 1; + sc->bce_flags |= BCE_USING_MSI_FLAG; + DBPRINT(sc, BCE_VERBOSE_LOAD, + "Allocating %d MSI interrupt(s)\n", count); + } else { + rid = 0; + DBPRINT(sc, BCE_VERBOSE_LOAD, "Allocating IRQ interrupt\n"); + } + + sc->bce_res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + + if (sc->bce_res_irq == NULL) { + BCE_PRINTF("%s(%d): PCI map interrupt failed!\n", + __FILE__, __LINE__); + rc = ENXIO; + goto bce_attach_fail; + } + + /* Initialize mutex for the current device instance. */ + BCE_LOCK_INIT(sc, device_get_nameunit(dev)); + + /* + * Configure byte swap and enable indirect register access. + * Rely on CPU to do target byte swapping on big endian systems. + * Access to registers outside of PCI configurtion space are not + * valid until this is done. + */ + pci_write_config(dev, BCE_PCICFG_MISC_CONFIG, + BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA | + BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP, 4); + + /* Save ASIC revsion info. */ + sc->bce_chipid = REG_RD(sc, BCE_MISC_ID); + + /* Weed out any non-production controller revisions. */ + switch(BCE_CHIP_ID(sc)) { + case BCE_CHIP_ID_5706_A0: + case BCE_CHIP_ID_5706_A1: + case BCE_CHIP_ID_5708_A0: + case BCE_CHIP_ID_5708_B0: + BCE_PRINTF("%s(%d): Unsupported controller revision (%c%d)!\n", + __FILE__, __LINE__, + (((pci_read_config(dev, PCIR_REVID, 4) & 0xf0) >> 4) + 'A'), + (pci_read_config(dev, PCIR_REVID, 4) & 0xf)); + rc = ENODEV; + goto bce_attach_fail; + } + + /* + * The embedded PCIe to PCI-X bridge (EPB) + * in the 5708 cannot address memory above + * 40 bits (E7_5708CB1_23043 & E6_5708SB1_23043). + */ + if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708) + sc->max_bus_addr = BCE_BUS_SPACE_MAXADDR; + else + sc->max_bus_addr = BUS_SPACE_MAXADDR; + + /* + * Find the base address for shared memory access. + * Newer versions of bootcode use a signature and offset + * while older versions use a fixed address. + */ + val = REG_RD_IND(sc, BCE_SHM_HDR_SIGNATURE); + if ((val & BCE_SHM_HDR_SIGNATURE_SIG_MASK) == BCE_SHM_HDR_SIGNATURE_SIG) + sc->bce_shmem_base = REG_RD_IND(sc, BCE_SHM_HDR_ADDR_0); + else + sc->bce_shmem_base = HOST_VIEW_SHMEM_BASE; + + DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "%s(): bce_shmem_base = 0x%08X\n", + __FUNCTION__, sc->bce_shmem_base); + + sc->bce_fw_ver = REG_RD_IND(sc, sc->bce_shmem_base + + BCE_DEV_INFO_BC_REV); + DBPRINT(sc, BCE_INFO_FIRMWARE, "%s(): bce_fw_ver = 0x%08X\n", + __FUNCTION__, sc->bce_fw_ver); + + /* Check if any management firmware is running. */ + val = REG_RD_IND(sc, sc->bce_shmem_base + BCE_PORT_FEATURE); + if (val & (BCE_PORT_FEATURE_ASF_ENABLED | BCE_PORT_FEATURE_IMD_ENABLED)) { + sc->bce_flags |= BCE_MFW_ENABLE_FLAG; + DBPRINT(sc, BCE_INFO_LOAD, "%s(): BCE_MFW_ENABLE_FLAG\n", + __FUNCTION__); + } + + /* Get PCI bus information (speed and type). */ + val = REG_RD(sc, BCE_PCICFG_MISC_STATUS); + if (val & BCE_PCICFG_MISC_STATUS_PCIX_DET) { + u32 clkreg; + + sc->bce_flags |= BCE_PCIX_FLAG; + + clkreg = REG_RD(sc, BCE_PCICFG_PCI_CLOCK_CONTROL_BITS); + + clkreg &= BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET; + switch (clkreg) { + case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ: + sc->bus_speed_mhz = 133; + break; + + case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ: + sc->bus_speed_mhz = 100; + break; + + case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ: + case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ: + sc->bus_speed_mhz = 66; + break; + + case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ: + case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ: + sc->bus_speed_mhz = 50; + break; + + case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW: + case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ: + case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ: + sc->bus_speed_mhz = 33; + break; + } + } else { + if (val & BCE_PCICFG_MISC_STATUS_M66EN) + sc->bus_speed_mhz = 66; + else + sc->bus_speed_mhz = 33; + } + + if (val & BCE_PCICFG_MISC_STATUS_32BIT_DET) + sc->bce_flags |= BCE_PCI_32BIT_FLAG; + + /* Reset the controller and announce to bootcode that driver is present. */ + if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) { + BCE_PRINTF("%s(%d): Controller reset failed!\n", + __FILE__, __LINE__); + rc = ENXIO; + goto bce_attach_fail; + } + + /* Initialize the controller. */ + if (bce_chipinit(sc)) { + BCE_PRINTF("%s(%d): Controller initialization failed!\n", + __FILE__, __LINE__); + rc = ENXIO; + goto bce_attach_fail; + } + + /* Perform NVRAM test. */ + if (bce_nvram_test(sc)) { + BCE_PRINTF("%s(%d): NVRAM test failed!\n", + __FILE__, __LINE__); + rc = ENXIO; + goto bce_attach_fail; + } + + /* Fetch the permanent Ethernet MAC address. */ + bce_get_mac_addr(sc); + + /* + * Trip points control how many BDs + * should be ready before generating an + * interrupt while ticks control how long + * a BD can sit in the chain before + * generating an interrupt. Set the default + * values for the RX and TX chains. + */ + +#ifdef BCE_DEBUG + /* Force more frequent interrupts. */ + sc->bce_tx_quick_cons_trip_int = 1; + sc->bce_tx_quick_cons_trip = 1; + sc->bce_tx_ticks_int = 0; + sc->bce_tx_ticks = 0; + + sc->bce_rx_quick_cons_trip_int = 1; + sc->bce_rx_quick_cons_trip = 1; + sc->bce_rx_ticks_int = 0; + sc->bce_rx_ticks = 0; +#else + /* Improve throughput at the expense of increased latency. */ + sc->bce_tx_quick_cons_trip_int = 20; + sc->bce_tx_quick_cons_trip = 20; + sc->bce_tx_ticks_int = 80; + sc->bce_tx_ticks = 80; + + sc->bce_rx_quick_cons_trip_int = 6; + sc->bce_rx_quick_cons_trip = 6; + sc->bce_rx_ticks_int = 18; + sc->bce_rx_ticks = 18; +#endif + + /* Update statistics once every second. */ + sc->bce_stats_ticks = 1000000 & 0xffff00; + + /* + * The SerDes based NetXtreme II controllers + * that support 2.5Gb operation (currently + * 5708S) use a PHY at address 2, otherwise + * the PHY is present at address 1. + */ + sc->bce_phy_addr = 1; + + if (BCE_CHIP_BOND_ID(sc) & BCE_CHIP_BOND_ID_SERDES_BIT) { + sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG; + sc->bce_flags |= BCE_NO_WOL_FLAG; + if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5706) { + sc->bce_phy_addr = 2; + val = REG_RD_IND(sc, sc->bce_shmem_base + + BCE_SHARED_HW_CFG_CONFIG); + if (val & BCE_SHARED_HW_CFG_PHY_2_5G) { + sc->bce_phy_flags |= BCE_PHY_2_5G_CAPABLE_FLAG; + DBPRINT(sc, BCE_INFO_LOAD, "Found 2.5Gb capable adapter\n"); + } + } + } + + /* Store data needed by PHY driver for backplane applications */ + sc->bce_shared_hw_cfg = REG_RD_IND(sc, sc->bce_shmem_base + + BCE_SHARED_HW_CFG_CONFIG); + sc->bce_port_hw_cfg = REG_RD_IND(sc, sc->bce_shmem_base + + BCE_SHARED_HW_CFG_CONFIG); + + /* Allocate DMA memory resources. */ + if (bce_dma_alloc(dev)) { + BCE_PRINTF("%s(%d): DMA resource allocation failed!\n", + __FILE__, __LINE__); + rc = ENXIO; + goto bce_attach_fail; + } + + /* Allocate an ifnet structure. */ + ifp = sc->bce_ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + BCE_PRINTF("%s(%d): Interface allocation failed!\n", + __FILE__, __LINE__); + rc = ENXIO; + goto bce_attach_fail; + } + + /* Initialize the ifnet interface. */ + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = bce_ioctl; + ifp->if_start = bce_start; + ifp->if_init = bce_init; + ifp->if_mtu = ETHERMTU; + ifp->if_hwassist = BCE_IF_HWASSIST; + ifp->if_capabilities = BCE_IF_CAPABILITIES; + ifp->if_capenable = ifp->if_capabilities; + + /* Assume a standard 1500 byte MTU size for mbuf allocations. */ + sc->mbuf_alloc_size = MCLBYTES; +#ifdef DEVICE_POLLING + ifp->if_capabilities |= IFCAP_POLLING; +#endif + + ifp->if_snd.ifq_drv_maxlen = USABLE_TX_BD; + IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); + IFQ_SET_READY(&ifp->if_snd); + + if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) + ifp->if_baudrate = IF_Mbps(2500ULL); + else + ifp->if_baudrate = IF_Mbps(1000); + + /* Check for an MII child bus by probing the PHY. */ + if (mii_phy_probe(dev, &sc->bce_miibus, bce_ifmedia_upd, + bce_ifmedia_sts)) { + BCE_PRINTF("%s(%d): No PHY found on child MII bus!\n", + __FILE__, __LINE__); + rc = ENXIO; + goto bce_attach_fail; + } + + /* Attach to the Ethernet interface list. */ + ether_ifattach(ifp, sc->eaddr); + +#if __FreeBSD_version < 500000 + callout_init(&sc->bce_tick_callout); + callout_init(&sc->bce_pulse_callout); +#else + callout_init_mtx(&sc->bce_tick_callout, &sc->bce_mtx, 0); + callout_init_mtx(&sc->bce_pulse_callout, &sc->bce_mtx, 0); +#endif + + /* Hookup IRQ last. */ +#if __FreeBSD_version > 700030 + rc = bus_setup_intr(dev, sc->bce_res_irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, bce_intr, sc, &sc->bce_intrhand); +#else + rc = bus_setup_intr(dev, sc->bce_res_irq, INTR_TYPE_NET | INTR_MPSAFE, + bce_intr, sc, &sc->bce_intrhand); +#endif + + if (rc) { + BCE_PRINTF("%s(%d): Failed to setup IRQ!\n", + __FILE__, __LINE__); + bce_detach(dev); + goto bce_attach_exit; + } + + /* + * At this point we've acquired all the resources + * we need to run so there's no turning back, we're + * cleared for launch. + */ + + /* Print some important debugging info. */ + DBRUN(BCE_INFO, bce_dump_driver_state(sc)); + + /* Add the supported sysctls to the kernel. */ + bce_add_sysctls(sc); + + BCE_LOCK(sc); + /* + * The chip reset earlier notified the bootcode that + * a driver is present. We now need to start our pulse + * routine so that the bootcode is reminded that we're + * still running. + */ + bce_pulse(sc); + + bce_mgmt_init_locked(sc); + BCE_UNLOCK(sc); + + /* Finally, print some useful adapter info */ + BCE_PRINTF("ASIC (0x%08X); ", sc->bce_chipid); + printf("Rev (%c%d); ", ((BCE_CHIP_ID(sc) & 0xf000) >> 12) + 'A', + ((BCE_CHIP_ID(sc) & 0x0ff0) >> 4)); + printf("Bus (PCI%s, %s, %dMHz); ", + ((sc->bce_flags & BCE_PCIX_FLAG) ? "-X" : ""), + ((sc->bce_flags & BCE_PCI_32BIT_FLAG) ? "32-bit" : "64-bit"), + sc->bus_speed_mhz); + printf("F/W (0x%08X); Flags( ", sc->bce_fw_ver); + if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) + printf("MFW "); + if (sc->bce_flags & BCE_USING_MSI_FLAG) + printf("MSI "); + if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) + printf("2.5G "); + printf(")\n"); + + goto bce_attach_exit; + +bce_attach_fail: + bce_release_resources(sc); + +bce_attach_exit: + + DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__); + + return(rc); +} + + +/****************************************************************************/ +/* Device detach function. */ +/* */ +/* Stops the controller, resets the controller, and releases resources. */ +/* */ +/* Returns: */ +/* 0 on success, positive value on failure. */ +/****************************************************************************/ +static int +bce_detach(device_t dev) +{ + struct bce_softc *sc = device_get_softc(dev); + struct ifnet *ifp; + u32 msg; + + DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__); + + ifp = sc->bce_ifp; + +#ifdef DEVICE_POLLING + if (ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(ifp); +#endif + + /* Stop the pulse so the bootcode can go to driver absent state. */ + callout_stop(&sc->bce_pulse_callout); + + /* Stop and reset the controller. */ + BCE_LOCK(sc); + bce_stop(sc); + if (sc->bce_flags & BCE_NO_WOL_FLAG) + msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN; + else + msg = BCE_DRV_MSG_CODE_UNLOAD; + bce_reset(sc, msg); + BCE_UNLOCK(sc); + + ether_ifdetach(ifp); + + /* If we have a child device on the MII bus remove it too. */ + bus_generic_detach(dev); + device_delete_child(dev, sc->bce_miibus); + + /* Release all remaining resources. */ + bce_release_resources(sc); + + DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__); + + return(0); +} + + +/****************************************************************************/ +/* Device shutdown function. */ +/* */ +/* Stops and resets the controller. */ +/* */ +/* Returns: */ +/* Nothing */ +/****************************************************************************/ +static void +bce_shutdown(device_t dev) +{ + struct bce_softc *sc = device_get_softc(dev); + u32 msg; + + DBPRINT(sc, BCE_VERBOSE_SPECIAL, "Entering %s()\n", __FUNCTION__); + + BCE_LOCK(sc); + bce_stop(sc); + if (sc->bce_flags & BCE_NO_WOL_FLAG) + msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN; + else + msg = BCE_DRV_MSG_CODE_UNLOAD; + bce_reset(sc, msg); + BCE_UNLOCK(sc); + + DBPRINT(sc, BCE_VERBOSE_SPECIAL, "Exiting %s()\n", __FUNCTION__); +} + + +/****************************************************************************/ +/* Indirect register read. */ +/* */ +/* Reads NetXtreme II registers using an index/data register pair in PCI */ +/* configuration space. Using this mechanism avoids issues with posted */ +/* reads but is much slower than memory-mapped I/O. */ +/* */ +/* Returns: */ +/* The value of the register. */ +/****************************************************************************/ +static u32 +bce_reg_rd_ind(struct bce_softc *sc, u32 offset) +{ + device_t dev; + dev = sc->bce_dev; + + pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4); +#ifdef BCE_DEBUG + { + u32 val; + val = pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4); + DBPRINT(sc, BCE_EXCESSIVE, "%s(); offset = 0x%08X, val = 0x%08X\n", + __FUNCTION__, offset, val); + return val; + } +#else + return pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4); +#endif +} + + +/****************************************************************************/ +/* Indirect register write. */ +/* */ +/* Writes NetXtreme II registers using an index/data register pair in PCI */ +/* configuration space. Using this mechanism avoids issues with posted */ +/* writes but is muchh slower than memory-mapped I/O. */ +/* */ +/* Returns: */ +/* Nothing. */ +/****************************************************************************/ +static void +bce_reg_wr_ind(struct bce_softc *sc, u32 offset, u32 val) +{ >>> TRUNCATED FOR MAIL (1000 lines) <<<