1157642Sps/*- 2205300Sdavidch * Copyright (c) 2006-2010 Broadcom Corporation 3157642Sps * David Christensen <davidch@broadcom.com>. All rights reserved. 4157642Sps * 5157642Sps * Redistribution and use in source and binary forms, with or without 6157642Sps * modification, are permitted provided that the following conditions 7157642Sps * are met: 8157642Sps * 9157642Sps * 1. Redistributions of source code must retain the above copyright 10157642Sps * notice, this list of conditions and the following disclaimer. 11157642Sps * 2. Redistributions in binary form must reproduce the above copyright 12157642Sps * notice, this list of conditions and the following disclaimer in the 13157642Sps * documentation and/or other materials provided with the distribution. 14157642Sps * 3. Neither the name of Broadcom Corporation nor the name of its contributors 15157642Sps * may be used to endorse or promote products derived from this software 16157642Sps * without specific prior written consent. 17157642Sps * 18157642Sps * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' 19157642Sps * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20157642Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21157642Sps * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 22157642Sps * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23157642Sps * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24157642Sps * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25157642Sps * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26157642Sps * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27157642Sps * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28157642Sps * THE POSSIBILITY OF SUCH DAMAGE. 29157642Sps */ 30157642Sps 31157642Sps#include <sys/cdefs.h> 32157642Sps__FBSDID("$FreeBSD$"); 33157642Sps 34157642Sps/* 35157642Sps * The following controllers are supported by this driver: 36157642Sps * BCM5706C A2, A3 37176448Sdavidch * BCM5706S A2, A3 38169271Sdavidch * BCM5708C B1, B2 39176448Sdavidch * BCM5708S B1, B2 40182293Sdavidch * BCM5709C A1, C0 41205300Sdavidch * BCM5709S A1, C0 42206268Sdavidch * BCM5716C C0 43206268Sdavidch * BCM5716S C0 44157642Sps * 45157642Sps * The following controllers are not supported by this driver: 46176448Sdavidch * BCM5706C A0, A1 (pre-production) 47176448Sdavidch * BCM5706S A0, A1 (pre-production) 48176448Sdavidch * BCM5708C A0, B0 (pre-production) 49176448Sdavidch * BCM5708S A0, B0 (pre-production) 50179771Sdavidch * BCM5709C A0 B0, B1, B2 (pre-production) 51205300Sdavidch * BCM5709S A0, B0, B1, B2 (pre-production) 52157642Sps */ 53157642Sps 54157643Sps#include "opt_bce.h" 55157643Sps 56157642Sps#include <dev/bce/if_bcereg.h> 57157642Sps#include <dev/bce/if_bcefw.h> 58157642Sps 59157642Sps/****************************************************************************/ 60157642Sps/* BCE Debug Options */ 61157642Sps/****************************************************************************/ 62157642Sps#ifdef BCE_DEBUG 63157642Sps u32 bce_debug = BCE_WARN; 64157642Sps 65157642Sps /* 0 = Never */ 66157642Sps /* 1 = 1 in 2,147,483,648 */ 67157642Sps /* 256 = 1 in 8,388,608 */ 68157642Sps /* 2048 = 1 in 1,048,576 */ 69157642Sps /* 65536 = 1 in 32,768 */ 70157642Sps /* 1048576 = 1 in 2,048 */ 71157642Sps /* 268435456 = 1 in 8 */ 72157642Sps /* 536870912 = 1 in 4 */ 73157642Sps /* 1073741824 = 1 in 2 */ 74157642Sps 75157642Sps /* Controls how often the l2_fhdr frame error check will fail. */ 76189325Sdavidch int l2fhdr_error_sim_control = 0; 77157642Sps 78157642Sps /* Controls how often the unexpected attention check will fail. */ 79189325Sdavidch int unexpected_attention_sim_control = 0; 80157642Sps 81157642Sps /* Controls how often to simulate an mbuf allocation failure. */ 82189325Sdavidch int mbuf_alloc_failed_sim_control = 0; 83157642Sps 84157642Sps /* Controls how often to simulate a DMA mapping failure. */ 85189325Sdavidch int dma_map_addr_failed_sim_control = 0; 86157642Sps 87157642Sps /* Controls how often to simulate a bootcode failure. */ 88189325Sdavidch int bootcode_running_failure_sim_control = 0; 89157642Sps#endif 90178132Sdavidch 91179695Sdavidch/****************************************************************************/ 92157642Sps/* PCI Device ID Table */ 93157642Sps/* */ 94157642Sps/* Used by bce_probe() to identify the devices supported by this driver. */ 95157642Sps/****************************************************************************/ 96157642Sps#define BCE_DEVDESC_MAX 64 97157642Sps 98247565Smariusstatic const struct bce_type bce_devs[] = { 99157642Sps /* BCM5706C Controllers and OEM boards. */ 100157642Sps { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, HP_VENDORID, 0x3101, 101157642Sps "HP NC370T Multifunction Gigabit Server Adapter" }, 102157642Sps { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, HP_VENDORID, 0x3106, 103157642Sps "HP NC370i Multifunction Gigabit Server Adapter" }, 104187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, HP_VENDORID, 0x3070, 105187317Sdelphij "HP NC380T PCIe DP Multifunc Gig Server Adapter" }, 106187317Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, HP_VENDORID, 0x1709, 107187317Sdelphij "HP NC371i Multifunction Gigabit Server Adapter" }, 108157642Sps { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, PCI_ANY_ID, PCI_ANY_ID, 109157642Sps "Broadcom NetXtreme II BCM5706 1000Base-T" }, 110157642Sps 111157642Sps /* BCM5706S controllers and OEM boards. */ 112157642Sps { BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, HP_VENDORID, 0x3102, 113157642Sps "HP NC370F Multifunction Gigabit Server Adapter" }, 114157642Sps { BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, PCI_ANY_ID, PCI_ANY_ID, 115157642Sps "Broadcom NetXtreme II BCM5706 1000Base-SX" }, 116157642Sps 117157642Sps /* BCM5708C controllers and OEM boards. */ 118187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5708, HP_VENDORID, 0x7037, 119187317Sdelphij "HP NC373T PCIe Multifunction Gig Server Adapter" }, 120187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5708, HP_VENDORID, 0x7038, 121187317Sdelphij "HP NC373i Multifunction Gigabit Server Adapter" }, 122187317Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5708, HP_VENDORID, 0x7045, 123187317Sdelphij "HP NC374m PCIe Multifunction Adapter" }, 124157642Sps { BRCM_VENDORID, BRCM_DEVICEID_BCM5708, PCI_ANY_ID, PCI_ANY_ID, 125157642Sps "Broadcom NetXtreme II BCM5708 1000Base-T" }, 126157642Sps 127157642Sps /* BCM5708S controllers and OEM boards. */ 128187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5708S, HP_VENDORID, 0x1706, 129187317Sdelphij "HP NC373m Multifunction Gigabit Server Adapter" }, 130187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5708S, HP_VENDORID, 0x703b, 131187317Sdelphij "HP NC373i Multifunction Gigabit Server Adapter" }, 132187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5708S, HP_VENDORID, 0x703d, 133187317Sdelphij "HP NC373F PCIe Multifunc Giga Server Adapter" }, 134163814Sscottl { BRCM_VENDORID, BRCM_DEVICEID_BCM5708S, PCI_ANY_ID, PCI_ANY_ID, 135170392Sdavidch "Broadcom NetXtreme II BCM5708 1000Base-SX" }, 136179771Sdavidch 137179771Sdavidch /* BCM5709C controllers and OEM boards. */ 138187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5709, HP_VENDORID, 0x7055, 139187317Sdelphij "HP NC382i DP Multifunction Gigabit Server Adapter" }, 140187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5709, HP_VENDORID, 0x7059, 141187317Sdelphij "HP NC382T PCIe DP Multifunction Gigabit Server Adapter" }, 142179771Sdavidch { BRCM_VENDORID, BRCM_DEVICEID_BCM5709, PCI_ANY_ID, PCI_ANY_ID, 143179771Sdavidch "Broadcom NetXtreme II BCM5709 1000Base-T" }, 144179771Sdavidch 145179771Sdavidch /* BCM5709S controllers and OEM boards. */ 146187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5709S, HP_VENDORID, 0x171d, 147187317Sdelphij "HP NC382m DP 1GbE Multifunction BL-c Adapter" }, 148187133Sdelphij { BRCM_VENDORID, BRCM_DEVICEID_BCM5709S, HP_VENDORID, 0x7056, 149187317Sdelphij "HP NC382i DP Multifunction Gigabit Server Adapter" }, 150179771Sdavidch { BRCM_VENDORID, BRCM_DEVICEID_BCM5709S, PCI_ANY_ID, PCI_ANY_ID, 151179771Sdavidch "Broadcom NetXtreme II BCM5709 1000Base-SX" }, 152179771Sdavidch 153179771Sdavidch /* BCM5716 controllers and OEM boards. */ 154179771Sdavidch { BRCM_VENDORID, BRCM_DEVICEID_BCM5716, PCI_ANY_ID, PCI_ANY_ID, 155179771Sdavidch "Broadcom NetXtreme II BCM5716 1000Base-T" }, 156179771Sdavidch 157157642Sps { 0, 0, 0, 0, NULL } 158157642Sps}; 159157642Sps 160157642Sps 161157642Sps/****************************************************************************/ 162157642Sps/* Supported Flash NVRAM device data. */ 163157642Sps/****************************************************************************/ 164247565Smariusstatic const struct flash_spec flash_table[] = 165157642Sps{ 166179771Sdavidch#define BUFFERED_FLAGS (BCE_NV_BUFFERED | BCE_NV_TRANSLATE) 167179771Sdavidch#define NONBUFFERED_FLAGS (BCE_NV_WREN) 168179771Sdavidch 169157642Sps /* Slow EEPROM */ 170157642Sps {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400, 171179771Sdavidch BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, 172157642Sps SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, 173157642Sps "EEPROM - slow"}, 174157642Sps /* Expansion entry 0001 */ 175157642Sps {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406, 176179771Sdavidch NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 177157642Sps SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 178157642Sps "Entry 0001"}, 179157642Sps /* Saifun SA25F010 (non-buffered flash) */ 180157642Sps /* strap, cfg1, & write1 need updates */ 181157642Sps {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406, 182179771Sdavidch NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 183157642Sps SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2, 184157642Sps "Non-buffered flash (128kB)"}, 185157642Sps /* Saifun SA25F020 (non-buffered flash) */ 186157642Sps /* strap, cfg1, & write1 need updates */ 187157642Sps {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406, 188179771Sdavidch NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 189157642Sps SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4, 190157642Sps "Non-buffered flash (256kB)"}, 191157642Sps /* Expansion entry 0100 */ 192157642Sps {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406, 193179771Sdavidch NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 194157642Sps SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 195157642Sps "Entry 0100"}, 196157642Sps /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */ 197157642Sps {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406, 198179771Sdavidch NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, 199157642Sps ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2, 200157642Sps "Entry 0101: ST M45PE10 (128kB non-bufferred)"}, 201157642Sps /* Entry 0110: ST M45PE20 (non-buffered flash)*/ 202157642Sps {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406, 203179771Sdavidch NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, 204157642Sps ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4, 205157642Sps "Entry 0110: ST M45PE20 (256kB non-bufferred)"}, 206157642Sps /* Saifun SA25F005 (non-buffered flash) */ 207157642Sps /* strap, cfg1, & write1 need updates */ 208157642Sps {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406, 209179771Sdavidch NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 210157642Sps SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE, 211157642Sps "Non-buffered flash (64kB)"}, 212157642Sps /* Fast EEPROM */ 213157642Sps {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400, 214179771Sdavidch BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, 215157642Sps SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, 216157642Sps "EEPROM - fast"}, 217157642Sps /* Expansion entry 1001 */ 218157642Sps {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406, 219179771Sdavidch NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 220157642Sps SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 221157642Sps "Entry 1001"}, 222157642Sps /* Expansion entry 1010 */ 223157642Sps {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406, 224179771Sdavidch NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 225157642Sps SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 226157642Sps "Entry 1010"}, 227157642Sps /* ATMEL AT45DB011B (buffered flash) */ 228157642Sps {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400, 229179771Sdavidch BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, 230157642Sps BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE, 231157642Sps "Buffered flash (128kB)"}, 232157642Sps /* Expansion entry 1100 */ 233157642Sps {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406, 234179771Sdavidch NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 235157642Sps SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 236157642Sps "Entry 1100"}, 237157642Sps /* Expansion entry 1101 */ 238157642Sps {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406, 239179771Sdavidch NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 240157642Sps SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 241157642Sps "Entry 1101"}, 242157642Sps /* Ateml Expansion entry 1110 */ 243157642Sps {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400, 244179771Sdavidch BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, 245157642Sps BUFFERED_FLASH_BYTE_ADDR_MASK, 0, 246157642Sps "Entry 1110 (Atmel)"}, 247157642Sps /* ATMEL AT45DB021B (buffered flash) */ 248157642Sps {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400, 249179771Sdavidch BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, 250157642Sps BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2, 251157642Sps "Buffered flash (256kB)"}, 252157642Sps}; 253157642Sps 254179771Sdavidch/* 255179771Sdavidch * The BCM5709 controllers transparently handle the 256179771Sdavidch * differences between Atmel 264 byte pages and all 257179771Sdavidch * flash devices which use 256 byte pages, so no 258179771Sdavidch * logical-to-physical mapping is required in the 259179771Sdavidch * driver. 260179771Sdavidch */ 261247565Smariusstatic const struct flash_spec flash_5709 = { 262179771Sdavidch .flags = BCE_NV_BUFFERED, 263179771Sdavidch .page_bits = BCM5709_FLASH_PAGE_BITS, 264179771Sdavidch .page_size = BCM5709_FLASH_PAGE_SIZE, 265179771Sdavidch .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK, 266179771Sdavidch .total_size = BUFFERED_FLASH_TOTAL_SIZE * 2, 267182293Sdavidch .name = "5709/5716 buffered flash (256kB)", 268179771Sdavidch}; 269157642Sps 270179771Sdavidch 271157642Sps/****************************************************************************/ 272157642Sps/* FreeBSD device entry points. */ 273157642Sps/****************************************************************************/ 274206268Sdavidchstatic int bce_probe (device_t); 275206268Sdavidchstatic int bce_attach (device_t); 276206268Sdavidchstatic int bce_detach (device_t); 277206268Sdavidchstatic int bce_shutdown (device_t); 278157642Sps 279157642Sps 280157642Sps/****************************************************************************/ 281157642Sps/* BCE Debug Data Structure Dump Routines */ 282157642Sps/****************************************************************************/ 283157642Sps#ifdef BCE_DEBUG 284218423Sdavidchstatic u32 bce_reg_rd (struct bce_softc *, u32); 285218423Sdavidchstatic void bce_reg_wr (struct bce_softc *, u32, u32); 286218423Sdavidchstatic void bce_reg_wr16 (struct bce_softc *, u32, u16); 287218423Sdavidchstatic u32 bce_ctx_rd (struct bce_softc *, u32, u32); 288218423Sdavidchstatic void bce_dump_enet (struct bce_softc *, struct mbuf *); 289218423Sdavidchstatic void bce_dump_mbuf (struct bce_softc *, struct mbuf *); 290176448Sdavidchstatic void bce_dump_tx_mbuf_chain (struct bce_softc *, u16, int); 291176448Sdavidchstatic void bce_dump_rx_mbuf_chain (struct bce_softc *, u16, int); 292179771Sdavidchstatic void bce_dump_pg_mbuf_chain (struct bce_softc *, u16, int); 293218423Sdavidchstatic void bce_dump_txbd (struct bce_softc *, 294206268Sdavidch int, struct tx_bd *); 295218423Sdavidchstatic void bce_dump_rxbd (struct bce_softc *, 296206268Sdavidch int, struct rx_bd *); 297218423Sdavidchstatic void bce_dump_pgbd (struct bce_softc *, 298206268Sdavidch int, struct rx_bd *); 299206268Sdavidchstatic void bce_dump_l2fhdr (struct bce_softc *, 300206268Sdavidch int, struct l2_fhdr *); 301218423Sdavidchstatic void bce_dump_ctx (struct bce_softc *, u16); 302218423Sdavidchstatic void bce_dump_ftqs (struct bce_softc *); 303176448Sdavidchstatic void bce_dump_tx_chain (struct bce_softc *, u16, int); 304206268Sdavidchstatic void bce_dump_rx_bd_chain (struct bce_softc *, u16, int); 305179771Sdavidchstatic void bce_dump_pg_chain (struct bce_softc *, u16, int); 306157642Spsstatic void bce_dump_status_block (struct bce_softc *); 307157642Spsstatic void bce_dump_stats_block (struct bce_softc *); 308157642Spsstatic void bce_dump_driver_state (struct bce_softc *); 309157642Spsstatic void bce_dump_hw_state (struct bce_softc *); 310218423Sdavidchstatic void bce_dump_shmem_state (struct bce_softc *); 311206268Sdavidchstatic void bce_dump_mq_regs (struct bce_softc *); 312170810Sdavidchstatic void bce_dump_bc_state (struct bce_softc *); 313179771Sdavidchstatic void bce_dump_txp_state (struct bce_softc *, int); 314179771Sdavidchstatic void bce_dump_rxp_state (struct bce_softc *, int); 315218423Sdavidchstatic void bce_dump_tpat_state (struct bce_softc *, int); 316179771Sdavidchstatic void bce_dump_cp_state (struct bce_softc *, int); 317179771Sdavidchstatic void bce_dump_com_state (struct bce_softc *, int); 318218423Sdavidchstatic void bce_dump_rv2p_state (struct bce_softc *); 319218423Sdavidchstatic void bce_breakpoint (struct bce_softc *); 320218423Sdavidch#endif /*BCE_DEBUG */ 321157642Sps 322157642Sps 323157642Sps/****************************************************************************/ 324157642Sps/* BCE Register/Memory Access Routines */ 325157642Sps/****************************************************************************/ 326206268Sdavidchstatic u32 bce_reg_rd_ind (struct bce_softc *, u32); 327206268Sdavidchstatic void bce_reg_wr_ind (struct bce_softc *, u32, u32); 328206268Sdavidchstatic void bce_shmem_wr (struct bce_softc *, u32, u32); 329206268Sdavidchstatic u32 bce_shmem_rd (struct bce_softc *, u32); 330206268Sdavidchstatic void bce_ctx_wr (struct bce_softc *, u32, u32, u32); 331157642Spsstatic int bce_miibus_read_reg (device_t, int, int); 332157642Spsstatic int bce_miibus_write_reg (device_t, int, int, int); 333157642Spsstatic void bce_miibus_statchg (device_t); 334157642Sps 335213489Sambrisko#ifdef BCE_DEBUG 336218527Sdavidchstatic int bce_sysctl_nvram_dump(SYSCTL_HANDLER_ARGS); 337213489Sambrisko#ifdef BCE_NVRAM_WRITE_SUPPORT 338218527Sdavidchstatic int bce_sysctl_nvram_write(SYSCTL_HANDLER_ARGS); 339213489Sambrisko#endif 340213489Sambrisko#endif 341157642Sps 342157642Sps/****************************************************************************/ 343157642Sps/* BCE NVRAM Access Routines */ 344157642Sps/****************************************************************************/ 345157642Spsstatic int bce_acquire_nvram_lock (struct bce_softc *); 346157642Spsstatic int bce_release_nvram_lock (struct bce_softc *); 347218423Sdavidchstatic void bce_enable_nvram_access(struct bce_softc *); 348218423Sdavidchstatic void bce_disable_nvram_access(struct bce_softc *); 349157642Spsstatic int bce_nvram_read_dword (struct bce_softc *, u32, u8 *, u32); 350218423Sdavidchstatic int bce_init_nvram (struct bce_softc *); 351218423Sdavidchstatic int bce_nvram_read (struct bce_softc *, u32, u8 *, int); 352218423Sdavidchstatic int bce_nvram_test (struct bce_softc *); 353157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT 354157642Spsstatic int bce_enable_nvram_write (struct bce_softc *); 355218423Sdavidchstatic void bce_disable_nvram_write(struct bce_softc *); 356157642Spsstatic int bce_nvram_erase_page (struct bce_softc *, u32); 357157642Spsstatic int bce_nvram_write_dword (struct bce_softc *, u32, u8 *, u32); 358206268Sdavidchstatic int bce_nvram_write (struct bce_softc *, u32, u8 *, int); 359157642Sps#endif 360157642Sps 361157642Sps/****************************************************************************/ 362157642Sps/* */ 363157642Sps/****************************************************************************/ 364218423Sdavidchstatic void bce_get_rx_buffer_sizes(struct bce_softc *, int); 365218423Sdavidchstatic void bce_get_media (struct bce_softc *); 366218423Sdavidchstatic void bce_init_media (struct bce_softc *); 367235151Syongaristatic u32 bce_get_rphy_link (struct bce_softc *); 368218423Sdavidchstatic void bce_dma_map_addr (void *, bus_dma_segment_t *, int, int); 369218423Sdavidchstatic int bce_dma_alloc (device_t); 370218423Sdavidchstatic void bce_dma_free (struct bce_softc *); 371157642Spsstatic void bce_release_resources (struct bce_softc *); 372157642Sps 373157642Sps/****************************************************************************/ 374157642Sps/* BCE Firmware Synchronization and Load */ 375157642Sps/****************************************************************************/ 376235151Syongaristatic void bce_fw_cap_init (struct bce_softc *); 377206268Sdavidchstatic int bce_fw_sync (struct bce_softc *, u32); 378251142Smariusstatic void bce_load_rv2p_fw (struct bce_softc *, const u32 *, u32, 379251142Smarius u32); 380207411Sdavidchstatic void bce_load_cpu_fw (struct bce_softc *, 381206268Sdavidch struct cpu_reg *, struct fw_info *); 382218423Sdavidchstatic void bce_start_cpu (struct bce_softc *, struct cpu_reg *); 383218423Sdavidchstatic void bce_halt_cpu (struct bce_softc *, struct cpu_reg *); 384206268Sdavidchstatic void bce_start_rxp_cpu (struct bce_softc *); 385179771Sdavidchstatic void bce_init_rxp_cpu (struct bce_softc *); 386179771Sdavidchstatic void bce_init_txp_cpu (struct bce_softc *); 387179771Sdavidchstatic void bce_init_tpat_cpu (struct bce_softc *); 388206268Sdavidchstatic void bce_init_cp_cpu (struct bce_softc *); 389179771Sdavidchstatic void bce_init_com_cpu (struct bce_softc *); 390218423Sdavidchstatic void bce_init_cpus (struct bce_softc *); 391157642Sps 392218423Sdavidchstatic void bce_print_adapter_info (struct bce_softc *); 393179771Sdavidchstatic void bce_probe_pci_caps (device_t, struct bce_softc *); 394218423Sdavidchstatic void bce_stop (struct bce_softc *); 395218423Sdavidchstatic int bce_reset (struct bce_softc *, u32); 396218423Sdavidchstatic int bce_chipinit (struct bce_softc *); 397218423Sdavidchstatic int bce_blockinit (struct bce_softc *); 398157642Sps 399157642Spsstatic int bce_init_tx_chain (struct bce_softc *); 400176448Sdavidchstatic void bce_free_tx_chain (struct bce_softc *); 401176448Sdavidch 402251146Smariusstatic int bce_get_rx_buf (struct bce_softc *, u16, u16, u32 *); 403176448Sdavidchstatic int bce_init_rx_chain (struct bce_softc *); 404171667Sdavidchstatic void bce_fill_rx_chain (struct bce_softc *); 405157642Spsstatic void bce_free_rx_chain (struct bce_softc *); 406179771Sdavidch 407251146Smariusstatic int bce_get_pg_buf (struct bce_softc *, u16, u16); 408176448Sdavidchstatic int bce_init_pg_chain (struct bce_softc *); 409176448Sdavidchstatic void bce_fill_pg_chain (struct bce_softc *); 410179771Sdavidchstatic void bce_free_pg_chain (struct bce_softc *); 411176448Sdavidch 412207411Sdavidchstatic struct mbuf *bce_tso_setup (struct bce_softc *, 413206268Sdavidch struct mbuf **, u16 *); 414218423Sdavidchstatic int bce_tx_encap (struct bce_softc *, struct mbuf **); 415157642Spsstatic void bce_start_locked (struct ifnet *); 416218423Sdavidchstatic void bce_start (struct ifnet *); 417218423Sdavidchstatic int bce_ioctl (struct ifnet *, u_long, caddr_t); 418218423Sdavidchstatic void bce_watchdog (struct bce_softc *); 419206268Sdavidchstatic int bce_ifmedia_upd (struct ifnet *); 420210261Syongaristatic int bce_ifmedia_upd_locked (struct ifnet *); 421206268Sdavidchstatic void bce_ifmedia_sts (struct ifnet *, struct ifmediareq *); 422235151Syongaristatic void bce_ifmedia_sts_rphy (struct bce_softc *, struct ifmediareq *); 423206268Sdavidchstatic void bce_init_locked (struct bce_softc *); 424218423Sdavidchstatic void bce_init (void *); 425171667Sdavidchstatic void bce_mgmt_init_locked (struct bce_softc *sc); 426157642Sps 427218423Sdavidchstatic int bce_init_ctx (struct bce_softc *); 428157642Spsstatic void bce_get_mac_addr (struct bce_softc *); 429157642Spsstatic void bce_set_mac_addr (struct bce_softc *); 430218423Sdavidchstatic void bce_phy_intr (struct bce_softc *); 431206268Sdavidchstatic inline u16 bce_get_hw_rx_cons (struct bce_softc *); 432206268Sdavidchstatic void bce_rx_intr (struct bce_softc *); 433206268Sdavidchstatic void bce_tx_intr (struct bce_softc *); 434157642Spsstatic void bce_disable_intr (struct bce_softc *); 435206268Sdavidchstatic void bce_enable_intr (struct bce_softc *, int); 436179771Sdavidch 437218423Sdavidchstatic void bce_intr (void *); 438206268Sdavidchstatic void bce_set_rx_mode (struct bce_softc *); 439157642Spsstatic void bce_stats_update (struct bce_softc *); 440218423Sdavidchstatic void bce_tick (void *); 441218423Sdavidchstatic void bce_pulse (void *); 442206268Sdavidchstatic void bce_add_sysctls (struct bce_softc *); 443157642Sps 444157642Sps 445157642Sps/****************************************************************************/ 446157642Sps/* FreeBSD device dispatch table. */ 447157642Sps/****************************************************************************/ 448157642Spsstatic device_method_t bce_methods[] = { 449176448Sdavidch /* Device interface (device_if.h) */ 450157642Sps DEVMETHOD(device_probe, bce_probe), 451157642Sps DEVMETHOD(device_attach, bce_attach), 452157642Sps DEVMETHOD(device_detach, bce_detach), 453157642Sps DEVMETHOD(device_shutdown, bce_shutdown), 454178132Sdavidch/* Supported by device interface but not used here. */ 455176448Sdavidch/* DEVMETHOD(device_identify, bce_identify), */ 456176448Sdavidch/* DEVMETHOD(device_suspend, bce_suspend), */ 457176448Sdavidch/* DEVMETHOD(device_resume, bce_resume), */ 458176448Sdavidch/* DEVMETHOD(device_quiesce, bce_quiesce), */ 459157642Sps 460176448Sdavidch /* MII interface (miibus_if.h) */ 461157642Sps DEVMETHOD(miibus_readreg, bce_miibus_read_reg), 462157642Sps DEVMETHOD(miibus_writereg, bce_miibus_write_reg), 463157642Sps DEVMETHOD(miibus_statchg, bce_miibus_statchg), 464178132Sdavidch/* Supported by MII interface but not used here. */ 465176448Sdavidch/* DEVMETHOD(miibus_linkchg, bce_miibus_linkchg), */ 466176448Sdavidch/* DEVMETHOD(miibus_mediainit, bce_miibus_mediainit), */ 467157642Sps 468227843Smarius DEVMETHOD_END 469157642Sps}; 470157642Sps 471157642Spsstatic driver_t bce_driver = { 472157642Sps "bce", 473157642Sps bce_methods, 474157642Sps sizeof(struct bce_softc) 475157642Sps}; 476157642Sps 477157642Spsstatic devclass_t bce_devclass; 478157642Sps 479157642SpsMODULE_DEPEND(bce, pci, 1, 1, 1); 480157642SpsMODULE_DEPEND(bce, ether, 1, 1, 1); 481157642SpsMODULE_DEPEND(bce, miibus, 1, 1, 1); 482157642Sps 483247565SmariusDRIVER_MODULE(bce, pci, bce_driver, bce_devclass, NULL, NULL); 484247565SmariusDRIVER_MODULE(miibus, bce, miibus_driver, miibus_devclass, NULL, NULL); 485170392Sdavidch 486170392Sdavidch 487169632Sdavidch/****************************************************************************/ 488169632Sdavidch/* Tunable device values */ 489169632Sdavidch/****************************************************************************/ 490227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, bce, CTLFLAG_RD, 0, "bce driver parameters"); 491176448Sdavidch 492170392Sdavidch/* Allowable values are TRUE or FALSE */ 493218423Sdavidchstatic int bce_verbose = TRUE; 494218423SdavidchTUNABLE_INT("hw.bce.verbose", &bce_verbose); 495218423SdavidchSYSCTL_INT(_hw_bce, OID_AUTO, verbose, CTLFLAG_RDTUN, &bce_verbose, 0, 496218423Sdavidch "Verbose output enable/disable"); 497218423Sdavidch 498218423Sdavidch/* Allowable values are TRUE or FALSE */ 499179771Sdavidchstatic int bce_tso_enable = TRUE; 500170392SdavidchTUNABLE_INT("hw.bce.tso_enable", &bce_tso_enable); 501217323SmdfSYSCTL_INT(_hw_bce, OID_AUTO, tso_enable, CTLFLAG_RDTUN, &bce_tso_enable, 0, 502218423Sdavidch "TSO Enable/Disable"); 503176448Sdavidch 504179771Sdavidch/* Allowable values are 0 (IRQ), 1 (MSI/IRQ), and 2 (MSI-X/MSI/IRQ) */ 505179771Sdavidch/* ToDo: Add MSI-X support. */ 506179771Sdavidchstatic int bce_msi_enable = 1; 507169632SdavidchTUNABLE_INT("hw.bce.msi_enable", &bce_msi_enable); 508217323SmdfSYSCTL_INT(_hw_bce, OID_AUTO, msi_enable, CTLFLAG_RDTUN, &bce_msi_enable, 0, 509218423Sdavidch "MSI-X|MSI|INTx selector"); 510178132Sdavidch 511218423Sdavidch/* Allowable values are 1, 2, 4, 8. */ 512218423Sdavidchstatic int bce_rx_pages = DEFAULT_RX_PAGES; 513218423SdavidchTUNABLE_INT("hw.bce.rx_pages", &bce_rx_pages); 514218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_pages, CTLFLAG_RDTUN, &bce_rx_pages, 0, 515218423Sdavidch "Receive buffer descriptor pages (1 page = 255 buffer descriptors)"); 516170392Sdavidch 517218423Sdavidch/* Allowable values are 1, 2, 4, 8. */ 518218423Sdavidchstatic int bce_tx_pages = DEFAULT_TX_PAGES; 519218423SdavidchTUNABLE_INT("hw.bce.tx_pages", &bce_tx_pages); 520218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_pages, CTLFLAG_RDTUN, &bce_tx_pages, 0, 521218423Sdavidch "Transmit buffer descriptor pages (1 page = 255 buffer descriptors)"); 522182293Sdavidch 523218423Sdavidch/* Allowable values are TRUE or FALSE. */ 524218423Sdavidchstatic int bce_hdr_split = TRUE; 525218423SdavidchTUNABLE_INT("hw.bce.hdr_split", &bce_hdr_split); 526218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, hdr_split, CTLFLAG_RDTUN, &bce_hdr_split, 0, 527218423Sdavidch "Frame header/payload splitting Enable/Disable"); 528218423Sdavidch 529218423Sdavidch/* Allowable values are TRUE or FALSE. */ 530218423Sdavidchstatic int bce_strict_rx_mtu = FALSE; 531218423SdavidchTUNABLE_INT("hw.bce.strict_rx_mtu", &bce_strict_rx_mtu); 532235145SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, strict_rx_mtu, CTLFLAG_RDTUN, 533218423Sdavidch &bce_strict_rx_mtu, 0, 534218423Sdavidch "Enable/Disable strict RX frame size checking"); 535218423Sdavidch 536218423Sdavidch/* Allowable values are 0 ... 100 */ 537218423Sdavidch#ifdef BCE_DEBUG 538218423Sdavidch/* Generate 1 interrupt for every transmit completion. */ 539218423Sdavidchstatic int bce_tx_quick_cons_trip_int = 1; 540218423Sdavidch#else 541218423Sdavidch/* Generate 1 interrupt for every 20 transmit completions. */ 542218423Sdavidchstatic int bce_tx_quick_cons_trip_int = DEFAULT_TX_QUICK_CONS_TRIP_INT; 543218423Sdavidch#endif 544218423SdavidchTUNABLE_INT("hw.bce.tx_quick_cons_trip_int", &bce_tx_quick_cons_trip_int); 545218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_quick_cons_trip_int, CTLFLAG_RDTUN, 546218423Sdavidch &bce_tx_quick_cons_trip_int, 0, 547218423Sdavidch "Transmit BD trip point during interrupts"); 548218423Sdavidch 549218423Sdavidch/* Allowable values are 0 ... 100 */ 550218423Sdavidch/* Generate 1 interrupt for every transmit completion. */ 551218423Sdavidch#ifdef BCE_DEBUG 552218423Sdavidchstatic int bce_tx_quick_cons_trip = 1; 553218423Sdavidch#else 554218423Sdavidch/* Generate 1 interrupt for every 20 transmit completions. */ 555218423Sdavidchstatic int bce_tx_quick_cons_trip = DEFAULT_TX_QUICK_CONS_TRIP; 556218423Sdavidch#endif 557218423SdavidchTUNABLE_INT("hw.bce.tx_quick_cons_trip", &bce_tx_quick_cons_trip); 558218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_quick_cons_trip, CTLFLAG_RDTUN, 559218423Sdavidch &bce_tx_quick_cons_trip, 0, 560218423Sdavidch "Transmit BD trip point"); 561218423Sdavidch 562218423Sdavidch/* Allowable values are 0 ... 100 */ 563218423Sdavidch#ifdef BCE_DEBUG 564218423Sdavidch/* Generate an interrupt if 0us have elapsed since the last TX completion. */ 565218423Sdavidchstatic int bce_tx_ticks_int = 0; 566218423Sdavidch#else 567218423Sdavidch/* Generate an interrupt if 80us have elapsed since the last TX completion. */ 568218423Sdavidchstatic int bce_tx_ticks_int = DEFAULT_TX_TICKS_INT; 569218423Sdavidch#endif 570218423SdavidchTUNABLE_INT("hw.bce.tx_ticks_int", &bce_tx_ticks_int); 571218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_ticks_int, CTLFLAG_RDTUN, 572218423Sdavidch &bce_tx_ticks_int, 0, "Transmit ticks count during interrupt"); 573218423Sdavidch 574218423Sdavidch/* Allowable values are 0 ... 100 */ 575218423Sdavidch#ifdef BCE_DEBUG 576218423Sdavidch/* Generate an interrupt if 0us have elapsed since the last TX completion. */ 577218423Sdavidchstatic int bce_tx_ticks = 0; 578218423Sdavidch#else 579218423Sdavidch/* Generate an interrupt if 80us have elapsed since the last TX completion. */ 580218423Sdavidchstatic int bce_tx_ticks = DEFAULT_TX_TICKS; 581218423Sdavidch#endif 582218423SdavidchTUNABLE_INT("hw.bce.tx_ticks", &bce_tx_ticks); 583218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_ticks, CTLFLAG_RDTUN, 584218423Sdavidch &bce_tx_ticks, 0, "Transmit ticks count"); 585218423Sdavidch 586218423Sdavidch/* Allowable values are 1 ... 100 */ 587218423Sdavidch#ifdef BCE_DEBUG 588218423Sdavidch/* Generate 1 interrupt for every received frame. */ 589218423Sdavidchstatic int bce_rx_quick_cons_trip_int = 1; 590218423Sdavidch#else 591218423Sdavidch/* Generate 1 interrupt for every 6 received frames. */ 592218423Sdavidchstatic int bce_rx_quick_cons_trip_int = DEFAULT_RX_QUICK_CONS_TRIP_INT; 593218423Sdavidch#endif 594218423SdavidchTUNABLE_INT("hw.bce.rx_quick_cons_trip_int", &bce_rx_quick_cons_trip_int); 595218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_quick_cons_trip_int, CTLFLAG_RDTUN, 596218423Sdavidch &bce_rx_quick_cons_trip_int, 0, 597218423Sdavidch "Receive BD trip point duirng interrupts"); 598218423Sdavidch 599218423Sdavidch/* Allowable values are 1 ... 100 */ 600218423Sdavidch#ifdef BCE_DEBUG 601218423Sdavidch/* Generate 1 interrupt for every received frame. */ 602218423Sdavidchstatic int bce_rx_quick_cons_trip = 1; 603218423Sdavidch#else 604218423Sdavidch/* Generate 1 interrupt for every 6 received frames. */ 605218423Sdavidchstatic int bce_rx_quick_cons_trip = DEFAULT_RX_QUICK_CONS_TRIP; 606218423Sdavidch#endif 607218423SdavidchTUNABLE_INT("hw.bce.rx_quick_cons_trip", &bce_rx_quick_cons_trip); 608218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_quick_cons_trip, CTLFLAG_RDTUN, 609218423Sdavidch &bce_rx_quick_cons_trip, 0, 610218423Sdavidch "Receive BD trip point"); 611218423Sdavidch 612218423Sdavidch/* Allowable values are 0 ... 100 */ 613218423Sdavidch#ifdef BCE_DEBUG 614218423Sdavidch/* Generate an int. if 0us have elapsed since the last received frame. */ 615218423Sdavidchstatic int bce_rx_ticks_int = 0; 616218423Sdavidch#else 617218423Sdavidch/* Generate an int. if 18us have elapsed since the last received frame. */ 618218423Sdavidchstatic int bce_rx_ticks_int = DEFAULT_RX_TICKS_INT; 619218423Sdavidch#endif 620218423SdavidchTUNABLE_INT("hw.bce.rx_ticks_int", &bce_rx_ticks_int); 621218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_ticks_int, CTLFLAG_RDTUN, 622218423Sdavidch &bce_rx_ticks_int, 0, "Receive ticks count during interrupt"); 623218423Sdavidch 624218423Sdavidch/* Allowable values are 0 ... 100 */ 625218423Sdavidch#ifdef BCE_DEBUG 626218423Sdavidch/* Generate an int. if 0us have elapsed since the last received frame. */ 627218423Sdavidchstatic int bce_rx_ticks = 0; 628218423Sdavidch#else 629218423Sdavidch/* Generate an int. if 18us have elapsed since the last received frame. */ 630218423Sdavidchstatic int bce_rx_ticks = DEFAULT_RX_TICKS; 631218423Sdavidch#endif 632218423SdavidchTUNABLE_INT("hw.bce.rx_ticks", &bce_rx_ticks); 633218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_ticks, CTLFLAG_RDTUN, 634218423Sdavidch &bce_rx_ticks, 0, "Receive ticks count"); 635218423Sdavidch 636218423Sdavidch 637157642Sps/****************************************************************************/ 638157642Sps/* Device probe function. */ 639157642Sps/* */ 640157642Sps/* Compares the device to the driver's list of supported devices and */ 641157642Sps/* reports back to the OS whether this is the right driver for the device. */ 642157642Sps/* */ 643157642Sps/* Returns: */ 644157642Sps/* BUS_PROBE_DEFAULT on success, positive value on failure. */ 645157642Sps/****************************************************************************/ 646157642Spsstatic int 647157642Spsbce_probe(device_t dev) 648157642Sps{ 649247565Smarius const struct bce_type *t; 650157642Sps struct bce_softc *sc; 651157642Sps char *descbuf; 652157642Sps u16 vid = 0, did = 0, svid = 0, sdid = 0; 653157642Sps 654157642Sps t = bce_devs; 655157642Sps 656157642Sps sc = device_get_softc(dev); 657157642Sps sc->bce_unit = device_get_unit(dev); 658157642Sps sc->bce_dev = dev; 659157642Sps 660157642Sps /* Get the data for the device to be probed. */ 661157642Sps vid = pci_get_vendor(dev); 662157642Sps did = pci_get_device(dev); 663157642Sps svid = pci_get_subvendor(dev); 664157642Sps sdid = pci_get_subdevice(dev); 665157642Sps 666179771Sdavidch DBPRINT(sc, BCE_EXTREME_LOAD, 667206268Sdavidch "%s(); VID = 0x%04X, DID = 0x%04X, SVID = 0x%04X, " 668206268Sdavidch "SDID = 0x%04X\n", __FUNCTION__, vid, did, svid, sdid); 669157642Sps 670157642Sps /* Look through the list of known devices for a match. */ 671157642Sps while(t->bce_name != NULL) { 672157642Sps 673179771Sdavidch if ((vid == t->bce_vid) && (did == t->bce_did) && 674206268Sdavidch ((svid == t->bce_svid) || (t->bce_svid == PCI_ANY_ID)) && 675206268Sdavidch ((sdid == t->bce_sdid) || (t->bce_sdid == PCI_ANY_ID))) { 676157642Sps 677157642Sps descbuf = malloc(BCE_DEVDESC_MAX, M_TEMP, M_NOWAIT); 678157642Sps 679157642Sps if (descbuf == NULL) 680157642Sps return(ENOMEM); 681157642Sps 682157642Sps /* Print out the device identity. */ 683179771Sdavidch snprintf(descbuf, BCE_DEVDESC_MAX, "%s (%c%d)", 684207411Sdavidch t->bce_name, (((pci_read_config(dev, 685206268Sdavidch PCIR_REVID, 4) & 0xf0) >> 4) + 'A'), 686169271Sdavidch (pci_read_config(dev, PCIR_REVID, 4) & 0xf)); 687157642Sps 688157642Sps device_set_desc_copy(dev, descbuf); 689157642Sps free(descbuf, M_TEMP); 690157642Sps return(BUS_PROBE_DEFAULT); 691157642Sps } 692157642Sps t++; 693157642Sps } 694157642Sps 695157642Sps return(ENXIO); 696157642Sps} 697157642Sps 698157642Sps 699157642Sps/****************************************************************************/ 700179771Sdavidch/* PCI Capabilities Probe Function. */ 701179771Sdavidch/* */ 702179771Sdavidch/* Walks the PCI capabiites list for the device to find what features are */ 703179771Sdavidch/* supported. */ 704179771Sdavidch/* */ 705179771Sdavidch/* Returns: */ 706179771Sdavidch/* None. */ 707179771Sdavidch/****************************************************************************/ 708179771Sdavidchstatic void 709179771Sdavidchbce_print_adapter_info(struct bce_softc *sc) 710179771Sdavidch{ 711207411Sdavidch int i = 0; 712194781Sdavidch 713179771Sdavidch DBENTER(BCE_VERBOSE_LOAD); 714179771Sdavidch 715218423Sdavidch if (bce_verbose || bootverbose) { 716207411Sdavidch BCE_PRINTF("ASIC (0x%08X); ", sc->bce_chipid); 717207411Sdavidch printf("Rev (%c%d); ", ((BCE_CHIP_ID(sc) & 0xf000) >> 718207411Sdavidch 12) + 'A', ((BCE_CHIP_ID(sc) & 0x0ff0) >> 4)); 719179771Sdavidch 720207411Sdavidch 721207411Sdavidch /* Bus info. */ 722207411Sdavidch if (sc->bce_flags & BCE_PCIE_FLAG) { 723207411Sdavidch printf("Bus (PCIe x%d, ", sc->link_width); 724207411Sdavidch switch (sc->link_speed) { 725207411Sdavidch case 1: printf("2.5Gbps); "); break; 726207411Sdavidch case 2: printf("5Gbps); "); break; 727207411Sdavidch default: printf("Unknown link speed); "); 728207411Sdavidch } 729207411Sdavidch } else { 730207411Sdavidch printf("Bus (PCI%s, %s, %dMHz); ", 731207411Sdavidch ((sc->bce_flags & BCE_PCIX_FLAG) ? "-X" : ""), 732207411Sdavidch ((sc->bce_flags & BCE_PCI_32BIT_FLAG) ? 733207411Sdavidch "32-bit" : "64-bit"), sc->bus_speed_mhz); 734179771Sdavidch } 735179771Sdavidch 736207411Sdavidch /* Firmware version and device features. */ 737218423Sdavidch printf("B/C (%s); Bufs (RX:%d;TX:%d;PG:%d); Flags (", 738218423Sdavidch sc->bce_bc_ver, sc->rx_pages, sc->tx_pages, 739218423Sdavidch (bce_hdr_split == TRUE ? sc->pg_pages: 0)); 740194781Sdavidch 741218423Sdavidch if (bce_hdr_split == TRUE) { 742218423Sdavidch printf("SPLT"); 743218423Sdavidch i++; 744218423Sdavidch } 745202717Sdavidch 746207411Sdavidch if (sc->bce_flags & BCE_USING_MSI_FLAG) { 747207411Sdavidch if (i > 0) printf("|"); 748207411Sdavidch printf("MSI"); i++; 749207411Sdavidch } 750179771Sdavidch 751207411Sdavidch if (sc->bce_flags & BCE_USING_MSIX_FLAG) { 752207411Sdavidch if (i > 0) printf("|"); 753207411Sdavidch printf("MSI-X"); i++; 754207411Sdavidch } 755194781Sdavidch 756207411Sdavidch if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) { 757207411Sdavidch if (i > 0) printf("|"); 758207411Sdavidch printf("2.5G"); i++; 759207411Sdavidch } 760194781Sdavidch 761235151Syongari if (sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) { 762235151Syongari if (i > 0) printf("|"); 763235151Syongari printf("Remote PHY(%s)", 764235151Syongari sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG ? 765235151Syongari "FIBER" : "TP"); i++; 766235151Syongari } 767235151Syongari 768207411Sdavidch if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) { 769207411Sdavidch if (i > 0) printf("|"); 770207411Sdavidch printf("MFW); MFW (%s)\n", sc->bce_mfw_ver); 771207411Sdavidch } else { 772207411Sdavidch printf(")\n"); 773207411Sdavidch } 774218423Sdavidch 775218423Sdavidch printf("Coal (RX:%d,%d,%d,%d; TX:%d,%d,%d,%d)\n", 776218423Sdavidch sc->bce_rx_quick_cons_trip_int, 777218423Sdavidch sc->bce_rx_quick_cons_trip, 778218423Sdavidch sc->bce_rx_ticks_int, 779218423Sdavidch sc->bce_rx_ticks, 780218423Sdavidch sc->bce_tx_quick_cons_trip_int, 781218423Sdavidch sc->bce_tx_quick_cons_trip, 782218423Sdavidch sc->bce_tx_ticks_int, 783218423Sdavidch sc->bce_tx_ticks); 784218423Sdavidch 785206268Sdavidch } 786194781Sdavidch 787196970Sphk DBEXIT(BCE_VERBOSE_LOAD); 788179771Sdavidch} 789179771Sdavidch 790179771Sdavidch 791179771Sdavidch/****************************************************************************/ 792179771Sdavidch/* PCI Capabilities Probe Function. */ 793179771Sdavidch/* */ 794179771Sdavidch/* Walks the PCI capabiites list for the device to find what features are */ 795179771Sdavidch/* supported. */ 796179771Sdavidch/* */ 797179771Sdavidch/* Returns: */ 798179771Sdavidch/* None. */ 799179771Sdavidch/****************************************************************************/ 800179771Sdavidchstatic void 801179771Sdavidchbce_probe_pci_caps(device_t dev, struct bce_softc *sc) 802179771Sdavidch{ 803179771Sdavidch u32 reg; 804179771Sdavidch 805179771Sdavidch DBENTER(BCE_VERBOSE_LOAD); 806179771Sdavidch 807179771Sdavidch /* Check if PCI-X capability is enabled. */ 808219902Sjhb if (pci_find_cap(dev, PCIY_PCIX, ®) == 0) { 809179771Sdavidch if (reg != 0) 810179771Sdavidch sc->bce_cap_flags |= BCE_PCIX_CAPABLE_FLAG; 811179771Sdavidch } 812179771Sdavidch 813179771Sdavidch /* Check if PCIe capability is enabled. */ 814219902Sjhb if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) { 815179771Sdavidch if (reg != 0) { 816179771Sdavidch u16 link_status = pci_read_config(dev, reg + 0x12, 2); 817206268Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "PCIe link_status = " 818206268Sdavidch "0x%08X\n", link_status); 819179771Sdavidch sc->link_speed = link_status & 0xf; 820179771Sdavidch sc->link_width = (link_status >> 4) & 0x3f; 821179771Sdavidch sc->bce_cap_flags |= BCE_PCIE_CAPABLE_FLAG; 822179771Sdavidch sc->bce_flags |= BCE_PCIE_FLAG; 823179771Sdavidch } 824179771Sdavidch } 825179771Sdavidch 826179771Sdavidch /* Check if MSI capability is enabled. */ 827219902Sjhb if (pci_find_cap(dev, PCIY_MSI, ®) == 0) { 828179771Sdavidch if (reg != 0) 829179771Sdavidch sc->bce_cap_flags |= BCE_MSI_CAPABLE_FLAG; 830179771Sdavidch } 831179771Sdavidch 832179771Sdavidch /* Check if MSI-X capability is enabled. */ 833219902Sjhb if (pci_find_cap(dev, PCIY_MSIX, ®) == 0) { 834179771Sdavidch if (reg != 0) 835179771Sdavidch sc->bce_cap_flags |= BCE_MSIX_CAPABLE_FLAG; 836179771Sdavidch } 837179771Sdavidch 838179771Sdavidch DBEXIT(BCE_VERBOSE_LOAD); 839179771Sdavidch} 840179771Sdavidch 841179771Sdavidch 842179771Sdavidch/****************************************************************************/ 843218423Sdavidch/* Load and validate user tunable settings. */ 844218423Sdavidch/* */ 845218423Sdavidch/* Returns: */ 846218423Sdavidch/* Nothing. */ 847218423Sdavidch/****************************************************************************/ 848218423Sdavidchstatic void 849218423Sdavidchbce_set_tunables(struct bce_softc *sc) 850218423Sdavidch{ 851218423Sdavidch /* Set sysctl values for RX page count. */ 852218423Sdavidch switch (bce_rx_pages) { 853218423Sdavidch case 1: 854218423Sdavidch /* fall-through */ 855218423Sdavidch case 2: 856218423Sdavidch /* fall-through */ 857218423Sdavidch case 4: 858218423Sdavidch /* fall-through */ 859218423Sdavidch case 8: 860218423Sdavidch sc->rx_pages = bce_rx_pages; 861218423Sdavidch break; 862218423Sdavidch default: 863218423Sdavidch sc->rx_pages = DEFAULT_RX_PAGES; 864218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 865218423Sdavidch "hw.bce.rx_pages! Setting default of %d.\n", 866218423Sdavidch __FILE__, __LINE__, bce_rx_pages, DEFAULT_RX_PAGES); 867218423Sdavidch } 868218423Sdavidch 869218423Sdavidch /* ToDo: Consider allowing user setting for pg_pages. */ 870218423Sdavidch sc->pg_pages = min((sc->rx_pages * 4), MAX_PG_PAGES); 871218423Sdavidch 872218423Sdavidch /* Set sysctl values for TX page count. */ 873218423Sdavidch switch (bce_tx_pages) { 874218423Sdavidch case 1: 875218423Sdavidch /* fall-through */ 876218423Sdavidch case 2: 877218423Sdavidch /* fall-through */ 878218423Sdavidch case 4: 879218423Sdavidch /* fall-through */ 880218423Sdavidch case 8: 881218423Sdavidch sc->tx_pages = bce_tx_pages; 882218423Sdavidch break; 883218423Sdavidch default: 884218423Sdavidch sc->tx_pages = DEFAULT_TX_PAGES; 885218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 886218423Sdavidch "hw.bce.tx_pages! Setting default of %d.\n", 887218423Sdavidch __FILE__, __LINE__, bce_tx_pages, DEFAULT_TX_PAGES); 888218423Sdavidch } 889218423Sdavidch 890218423Sdavidch /* 891218423Sdavidch * Validate the TX trip point (i.e. the number of 892218423Sdavidch * TX completions before a status block update is 893218423Sdavidch * generated and an interrupt is asserted. 894218423Sdavidch */ 895218423Sdavidch if (bce_tx_quick_cons_trip_int <= 100) { 896218423Sdavidch sc->bce_tx_quick_cons_trip_int = 897218423Sdavidch bce_tx_quick_cons_trip_int; 898218423Sdavidch } else { 899218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 900218423Sdavidch "hw.bce.tx_quick_cons_trip_int! Setting default of %d.\n", 901218423Sdavidch __FILE__, __LINE__, bce_tx_quick_cons_trip_int, 902218423Sdavidch DEFAULT_TX_QUICK_CONS_TRIP_INT); 903218423Sdavidch sc->bce_tx_quick_cons_trip_int = 904218423Sdavidch DEFAULT_TX_QUICK_CONS_TRIP_INT; 905218423Sdavidch } 906218423Sdavidch 907218423Sdavidch if (bce_tx_quick_cons_trip <= 100) { 908218423Sdavidch sc->bce_tx_quick_cons_trip = 909218423Sdavidch bce_tx_quick_cons_trip; 910218423Sdavidch } else { 911218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 912218423Sdavidch "hw.bce.tx_quick_cons_trip! Setting default of %d.\n", 913218423Sdavidch __FILE__, __LINE__, bce_tx_quick_cons_trip, 914218423Sdavidch DEFAULT_TX_QUICK_CONS_TRIP); 915218423Sdavidch sc->bce_tx_quick_cons_trip = 916218423Sdavidch DEFAULT_TX_QUICK_CONS_TRIP; 917218423Sdavidch } 918218423Sdavidch 919218423Sdavidch /* 920218423Sdavidch * Validate the TX ticks count (i.e. the maximum amount 921218423Sdavidch * of time to wait after the last TX completion has 922218423Sdavidch * occurred before a status block update is generated 923218423Sdavidch * and an interrupt is asserted. 924218423Sdavidch */ 925218423Sdavidch if (bce_tx_ticks_int <= 100) { 926218423Sdavidch sc->bce_tx_ticks_int = 927218423Sdavidch bce_tx_ticks_int; 928218423Sdavidch } else { 929218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 930218423Sdavidch "hw.bce.tx_ticks_int! Setting default of %d.\n", 931218423Sdavidch __FILE__, __LINE__, bce_tx_ticks_int, 932218423Sdavidch DEFAULT_TX_TICKS_INT); 933218423Sdavidch sc->bce_tx_ticks_int = 934218423Sdavidch DEFAULT_TX_TICKS_INT; 935218423Sdavidch } 936218423Sdavidch 937218423Sdavidch if (bce_tx_ticks <= 100) { 938218423Sdavidch sc->bce_tx_ticks = 939218423Sdavidch bce_tx_ticks; 940218423Sdavidch } else { 941218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 942218423Sdavidch "hw.bce.tx_ticks! Setting default of %d.\n", 943218423Sdavidch __FILE__, __LINE__, bce_tx_ticks, 944218423Sdavidch DEFAULT_TX_TICKS); 945218423Sdavidch sc->bce_tx_ticks = 946218423Sdavidch DEFAULT_TX_TICKS; 947218423Sdavidch } 948218423Sdavidch 949218423Sdavidch /* 950218423Sdavidch * Validate the RX trip point (i.e. the number of 951218423Sdavidch * RX frames received before a status block update is 952218423Sdavidch * generated and an interrupt is asserted. 953218423Sdavidch */ 954218423Sdavidch if (bce_rx_quick_cons_trip_int <= 100) { 955218423Sdavidch sc->bce_rx_quick_cons_trip_int = 956218423Sdavidch bce_rx_quick_cons_trip_int; 957218423Sdavidch } else { 958218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 959218423Sdavidch "hw.bce.rx_quick_cons_trip_int! Setting default of %d.\n", 960218423Sdavidch __FILE__, __LINE__, bce_rx_quick_cons_trip_int, 961218423Sdavidch DEFAULT_RX_QUICK_CONS_TRIP_INT); 962218423Sdavidch sc->bce_rx_quick_cons_trip_int = 963218423Sdavidch DEFAULT_RX_QUICK_CONS_TRIP_INT; 964218423Sdavidch } 965218423Sdavidch 966218423Sdavidch if (bce_rx_quick_cons_trip <= 100) { 967218423Sdavidch sc->bce_rx_quick_cons_trip = 968218423Sdavidch bce_rx_quick_cons_trip; 969218423Sdavidch } else { 970218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 971218423Sdavidch "hw.bce.rx_quick_cons_trip! Setting default of %d.\n", 972218423Sdavidch __FILE__, __LINE__, bce_rx_quick_cons_trip, 973218423Sdavidch DEFAULT_RX_QUICK_CONS_TRIP); 974218423Sdavidch sc->bce_rx_quick_cons_trip = 975218423Sdavidch DEFAULT_RX_QUICK_CONS_TRIP; 976218423Sdavidch } 977218423Sdavidch 978218423Sdavidch /* 979218423Sdavidch * Validate the RX ticks count (i.e. the maximum amount 980218423Sdavidch * of time to wait after the last RX frame has been 981218423Sdavidch * received before a status block update is generated 982218423Sdavidch * and an interrupt is asserted. 983218423Sdavidch */ 984218423Sdavidch if (bce_rx_ticks_int <= 100) { 985218423Sdavidch sc->bce_rx_ticks_int = bce_rx_ticks_int; 986218423Sdavidch } else { 987218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 988218423Sdavidch "hw.bce.rx_ticks_int! Setting default of %d.\n", 989218423Sdavidch __FILE__, __LINE__, bce_rx_ticks_int, 990218423Sdavidch DEFAULT_RX_TICKS_INT); 991218423Sdavidch sc->bce_rx_ticks_int = DEFAULT_RX_TICKS_INT; 992218423Sdavidch } 993218423Sdavidch 994218423Sdavidch if (bce_rx_ticks <= 100) { 995218423Sdavidch sc->bce_rx_ticks = bce_rx_ticks; 996218423Sdavidch } else { 997218423Sdavidch BCE_PRINTF("%s(%d): Illegal value (%d) specified for " 998218423Sdavidch "hw.bce.rx_ticks! Setting default of %d.\n", 999218423Sdavidch __FILE__, __LINE__, bce_rx_ticks, 1000218423Sdavidch DEFAULT_RX_TICKS); 1001218423Sdavidch sc->bce_rx_ticks = DEFAULT_RX_TICKS; 1002218423Sdavidch } 1003218423Sdavidch 1004218423Sdavidch /* Disabling both RX ticks and RX trips will prevent interrupts. */ 1005218423Sdavidch if ((bce_rx_quick_cons_trip == 0) && (bce_rx_ticks == 0)) { 1006218423Sdavidch BCE_PRINTF("%s(%d): Cannot set both hw.bce.rx_ticks and " 1007218423Sdavidch "hw.bce.rx_quick_cons_trip to 0. Setting default values.\n", 1008218423Sdavidch __FILE__, __LINE__); 1009218423Sdavidch sc->bce_rx_ticks = DEFAULT_RX_TICKS; 1010218423Sdavidch sc->bce_rx_quick_cons_trip = DEFAULT_RX_QUICK_CONS_TRIP; 1011218423Sdavidch } 1012218423Sdavidch 1013218423Sdavidch /* Disabling both TX ticks and TX trips will prevent interrupts. */ 1014218423Sdavidch if ((bce_tx_quick_cons_trip == 0) && (bce_tx_ticks == 0)) { 1015218423Sdavidch BCE_PRINTF("%s(%d): Cannot set both hw.bce.tx_ticks and " 1016218423Sdavidch "hw.bce.tx_quick_cons_trip to 0. Setting default values.\n", 1017218423Sdavidch __FILE__, __LINE__); 1018218423Sdavidch sc->bce_tx_ticks = DEFAULT_TX_TICKS; 1019218423Sdavidch sc->bce_tx_quick_cons_trip = DEFAULT_TX_QUICK_CONS_TRIP; 1020218423Sdavidch } 1021218423Sdavidch} 1022218423Sdavidch 1023218423Sdavidch 1024218423Sdavidch/****************************************************************************/ 1025157642Sps/* Device attach function. */ 1026157642Sps/* */ 1027157642Sps/* Allocates device resources, performs secondary chip identification, */ 1028157642Sps/* resets and initializes the hardware, and initializes driver instance */ 1029157642Sps/* variables. */ 1030157642Sps/* */ 1031157642Sps/* Returns: */ 1032157642Sps/* 0 on success, positive value on failure. */ 1033157642Sps/****************************************************************************/ 1034157642Spsstatic int 1035157642Spsbce_attach(device_t dev) 1036157642Sps{ 1037157642Sps struct bce_softc *sc; 1038157642Sps struct ifnet *ifp; 1039157642Sps u32 val; 1040247565Smarius int count, error, rc = 0, rid; 1041157642Sps 1042157642Sps sc = device_get_softc(dev); 1043157642Sps sc->bce_dev = dev; 1044157642Sps 1045179771Sdavidch DBENTER(BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET); 1046157642Sps 1047176448Sdavidch sc->bce_unit = device_get_unit(dev); 1048170392Sdavidch 1049169632Sdavidch /* Set initial device and PHY flags */ 1050169632Sdavidch sc->bce_flags = 0; 1051169632Sdavidch sc->bce_phy_flags = 0; 1052169632Sdavidch 1053218423Sdavidch bce_set_tunables(sc); 1054218423Sdavidch 1055157642Sps pci_enable_busmaster(dev); 1056157642Sps 1057157642Sps /* Allocate PCI memory resources. */ 1058157642Sps rid = PCIR_BAR(0); 1059169632Sdavidch sc->bce_res_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 1060178588Smarius &rid, RF_ACTIVE); 1061157642Sps 1062169632Sdavidch if (sc->bce_res_mem == NULL) { 1063179771Sdavidch BCE_PRINTF("%s(%d): PCI memory allocation failed\n", 1064206268Sdavidch __FILE__, __LINE__); 1065157642Sps rc = ENXIO; 1066157642Sps goto bce_attach_fail; 1067157642Sps } 1068157642Sps 1069157642Sps /* Get various resource handles. */ 1070169632Sdavidch sc->bce_btag = rman_get_bustag(sc->bce_res_mem); 1071169632Sdavidch sc->bce_bhandle = rman_get_bushandle(sc->bce_res_mem); 1072169632Sdavidch sc->bce_vhandle = (vm_offset_t) rman_get_virtual(sc->bce_res_mem); 1073157642Sps 1074179771Sdavidch bce_probe_pci_caps(dev, sc); 1075170392Sdavidch 1076179771Sdavidch rid = 1; 1077247590Smarius count = 0; 1078179771Sdavidch#if 0 1079179771Sdavidch /* Try allocating MSI-X interrupts. */ 1080179771Sdavidch if ((sc->bce_cap_flags & BCE_MSIX_CAPABLE_FLAG) && 1081179771Sdavidch (bce_msi_enable >= 2) && 1082179771Sdavidch ((sc->bce_res_irq = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 1083179771Sdavidch &rid, RF_ACTIVE)) != NULL)) { 1084179771Sdavidch 1085247565Smarius msi_needed = count = 1; 1086179771Sdavidch 1087247565Smarius if (((error = pci_alloc_msix(dev, &count)) != 0) || 1088247565Smarius (count != msi_needed)) { 1089179771Sdavidch BCE_PRINTF("%s(%d): MSI-X allocation failed! Requested = %d," 1090179771Sdavidch "Received = %d, error = %d\n", __FILE__, __LINE__, 1091247565Smarius msi_needed, count, error); 1092247565Smarius count = 0; 1093179771Sdavidch pci_release_msi(dev); 1094179771Sdavidch bus_release_resource(dev, SYS_RES_MEMORY, rid, 1095179771Sdavidch sc->bce_res_irq); 1096179771Sdavidch sc->bce_res_irq = NULL; 1097179771Sdavidch } else { 1098179771Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using MSI-X interrupt.\n", 1099179771Sdavidch __FUNCTION__); 1100179771Sdavidch sc->bce_flags |= BCE_USING_MSIX_FLAG; 1101179771Sdavidch } 1102179771Sdavidch } 1103179771Sdavidch#endif 1104179771Sdavidch 1105179771Sdavidch /* Try allocating a MSI interrupt. */ 1106179771Sdavidch if ((sc->bce_cap_flags & BCE_MSI_CAPABLE_FLAG) && 1107247565Smarius (bce_msi_enable >= 1) && (count == 0)) { 1108247565Smarius count = 1; 1109247565Smarius if ((error = pci_alloc_msi(dev, &count)) != 0) { 1110207411Sdavidch BCE_PRINTF("%s(%d): MSI allocation failed! " 1111207411Sdavidch "error = %d\n", __FILE__, __LINE__, error); 1112247565Smarius count = 0; 1113179771Sdavidch pci_release_msi(dev); 1114179771Sdavidch } else { 1115207411Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using MSI " 1116207411Sdavidch "interrupt.\n", __FUNCTION__); 1117179771Sdavidch sc->bce_flags |= BCE_USING_MSI_FLAG; 1118226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) 1119179771Sdavidch sc->bce_flags |= BCE_ONE_SHOT_MSI_FLAG; 1120247565Smarius rid = 1; 1121179771Sdavidch } 1122179771Sdavidch } 1123179771Sdavidch 1124179771Sdavidch /* Try allocating a legacy interrupt. */ 1125247565Smarius if (count == 0) { 1126179771Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using INTx interrupt.\n", 1127179771Sdavidch __FUNCTION__); 1128170392Sdavidch rid = 0; 1129169632Sdavidch } 1130170392Sdavidch 1131179771Sdavidch sc->bce_res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1132247565Smarius &rid, RF_ACTIVE | (count != 0 ? 0 : RF_SHAREABLE)); 1133157642Sps 1134179771Sdavidch /* Report any IRQ allocation errors. */ 1135169632Sdavidch if (sc->bce_res_irq == NULL) { 1136179771Sdavidch BCE_PRINTF("%s(%d): PCI map interrupt failed!\n", 1137206268Sdavidch __FILE__, __LINE__); 1138157642Sps rc = ENXIO; 1139157642Sps goto bce_attach_fail; 1140157642Sps } 1141157642Sps 1142157642Sps /* Initialize mutex for the current device instance. */ 1143157642Sps BCE_LOCK_INIT(sc, device_get_nameunit(dev)); 1144157642Sps 1145157642Sps /* 1146157642Sps * Configure byte swap and enable indirect register access. 1147157642Sps * Rely on CPU to do target byte swapping on big endian systems. 1148157642Sps * Access to registers outside of PCI configurtion space are not 1149157642Sps * valid until this is done. 1150157642Sps */ 1151157642Sps pci_write_config(dev, BCE_PCICFG_MISC_CONFIG, 1152206268Sdavidch BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA | 1153206268Sdavidch BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP, 4); 1154157642Sps 1155157642Sps /* Save ASIC revsion info. */ 1156157642Sps sc->bce_chipid = REG_RD(sc, BCE_MISC_ID); 1157157642Sps 1158157642Sps /* Weed out any non-production controller revisions. */ 1159157642Sps switch(BCE_CHIP_ID(sc)) { 1160206268Sdavidch case BCE_CHIP_ID_5706_A0: 1161206268Sdavidch case BCE_CHIP_ID_5706_A1: 1162206268Sdavidch case BCE_CHIP_ID_5708_A0: 1163206268Sdavidch case BCE_CHIP_ID_5708_B0: 1164206268Sdavidch case BCE_CHIP_ID_5709_A0: 1165206268Sdavidch case BCE_CHIP_ID_5709_B0: 1166206268Sdavidch case BCE_CHIP_ID_5709_B1: 1167206268Sdavidch case BCE_CHIP_ID_5709_B2: 1168207411Sdavidch BCE_PRINTF("%s(%d): Unsupported controller " 1169207411Sdavidch "revision (%c%d)!\n", __FILE__, __LINE__, 1170207411Sdavidch (((pci_read_config(dev, PCIR_REVID, 4) & 1171207411Sdavidch 0xf0) >> 4) + 'A'), (pci_read_config(dev, 1172207411Sdavidch PCIR_REVID, 4) & 0xf)); 1173206268Sdavidch rc = ENODEV; 1174206268Sdavidch goto bce_attach_fail; 1175157642Sps } 1176157642Sps 1177179771Sdavidch /* 1178179771Sdavidch * The embedded PCIe to PCI-X bridge (EPB) 1179179771Sdavidch * in the 5708 cannot address memory above 1180179771Sdavidch * 40 bits (E7_5708CB1_23043 & E6_5708SB1_23043). 1181157642Sps */ 1182157642Sps if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708) 1183157642Sps sc->max_bus_addr = BCE_BUS_SPACE_MAXADDR; 1184157642Sps else 1185157642Sps sc->max_bus_addr = BUS_SPACE_MAXADDR; 1186157642Sps 1187157642Sps /* 1188157642Sps * Find the base address for shared memory access. 1189157642Sps * Newer versions of bootcode use a signature and offset 1190157642Sps * while older versions use a fixed address. 1191157642Sps */ 1192157642Sps val = REG_RD_IND(sc, BCE_SHM_HDR_SIGNATURE); 1193157642Sps if ((val & BCE_SHM_HDR_SIGNATURE_SIG_MASK) == BCE_SHM_HDR_SIGNATURE_SIG) 1194179771Sdavidch /* Multi-port devices use different offsets in shared memory. */ 1195179771Sdavidch sc->bce_shmem_base = REG_RD_IND(sc, BCE_SHM_HDR_ADDR_0 + 1196206268Sdavidch (pci_get_function(sc->bce_dev) << 2)); 1197157642Sps else 1198157642Sps sc->bce_shmem_base = HOST_VIEW_SHMEM_BASE; 1199157642Sps 1200179771Sdavidch DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "%s(): bce_shmem_base = 0x%08X\n", 1201206268Sdavidch __FUNCTION__, sc->bce_shmem_base); 1202157642Sps 1203178132Sdavidch /* Fetch the bootcode revision. */ 1204206268Sdavidch val = bce_shmem_rd(sc, BCE_DEV_INFO_BC_REV); 1205206268Sdavidch for (int i = 0, j = 0; i < 3; i++) { 1206206268Sdavidch u8 num; 1207170810Sdavidch 1208206268Sdavidch num = (u8) (val >> (24 - (i * 8))); 1209206268Sdavidch for (int k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) { 1210206268Sdavidch if (num >= k || !skip0 || k == 1) { 1211206268Sdavidch sc->bce_bc_ver[j++] = (num / k) + '0'; 1212206268Sdavidch skip0 = 0; 1213206268Sdavidch } 1214206268Sdavidch } 1215170810Sdavidch 1216206268Sdavidch if (i != 2) 1217206268Sdavidch sc->bce_bc_ver[j++] = '.'; 1218206268Sdavidch } 1219194781Sdavidch 1220206268Sdavidch /* Check if any management firwmare is enabled. */ 1221206268Sdavidch val = bce_shmem_rd(sc, BCE_PORT_FEATURE); 1222206268Sdavidch if (val & BCE_PORT_FEATURE_ASF_ENABLED) { 1223206268Sdavidch sc->bce_flags |= BCE_MFW_ENABLE_FLAG; 1224194781Sdavidch 1225206268Sdavidch /* Allow time for firmware to enter the running state. */ 1226206268Sdavidch for (int i = 0; i < 30; i++) { 1227206268Sdavidch val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION); 1228206268Sdavidch if (val & BCE_CONDITION_MFW_RUN_MASK) 1229206268Sdavidch break; 1230206268Sdavidch DELAY(10000); 1231206268Sdavidch } 1232194781Sdavidch 1233206268Sdavidch /* Check if management firmware is running. */ 1234206268Sdavidch val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION); 1235206268Sdavidch val &= BCE_CONDITION_MFW_RUN_MASK; 1236206268Sdavidch if ((val != BCE_CONDITION_MFW_RUN_UNKNOWN) && 1237206268Sdavidch (val != BCE_CONDITION_MFW_RUN_NONE)) { 1238206268Sdavidch u32 addr = bce_shmem_rd(sc, BCE_MFW_VER_PTR); 1239206268Sdavidch int i = 0; 1240194781Sdavidch 1241206268Sdavidch /* Read the management firmware version string. */ 1242206268Sdavidch for (int j = 0; j < 3; j++) { 1243206268Sdavidch val = bce_reg_rd_ind(sc, addr + j * 4); 1244206268Sdavidch val = bswap32(val); 1245206268Sdavidch memcpy(&sc->bce_mfw_ver[i], &val, 4); 1246206268Sdavidch i += 4; 1247206268Sdavidch } 1248206268Sdavidch } else { 1249206268Sdavidch /* May cause firmware synchronization timeouts. */ 1250206268Sdavidch BCE_PRINTF("%s(%d): Management firmware enabled " 1251206268Sdavidch "but not running!\n", __FILE__, __LINE__); 1252206268Sdavidch strcpy(sc->bce_mfw_ver, "NOT RUNNING!"); 1253206268Sdavidch 1254206268Sdavidch /* ToDo: Any action the driver should take? */ 1255206268Sdavidch } 1256206268Sdavidch } 1257206268Sdavidch 1258157642Sps /* Get PCI bus information (speed and type). */ 1259157642Sps val = REG_RD(sc, BCE_PCICFG_MISC_STATUS); 1260157642Sps if (val & BCE_PCICFG_MISC_STATUS_PCIX_DET) { 1261157642Sps u32 clkreg; 1262157642Sps 1263157642Sps sc->bce_flags |= BCE_PCIX_FLAG; 1264157642Sps 1265157642Sps clkreg = REG_RD(sc, BCE_PCICFG_PCI_CLOCK_CONTROL_BITS); 1266157642Sps 1267157642Sps clkreg &= BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET; 1268157642Sps switch (clkreg) { 1269157642Sps case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ: 1270157642Sps sc->bus_speed_mhz = 133; 1271157642Sps break; 1272157642Sps 1273157642Sps case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ: 1274157642Sps sc->bus_speed_mhz = 100; 1275157642Sps break; 1276157642Sps 1277157642Sps case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ: 1278157642Sps case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ: 1279157642Sps sc->bus_speed_mhz = 66; 1280157642Sps break; 1281157642Sps 1282157642Sps case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ: 1283157642Sps case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ: 1284157642Sps sc->bus_speed_mhz = 50; 1285157642Sps break; 1286157642Sps 1287157642Sps case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW: 1288157642Sps case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ: 1289157642Sps case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ: 1290157642Sps sc->bus_speed_mhz = 33; 1291157642Sps break; 1292157642Sps } 1293157642Sps } else { 1294157642Sps if (val & BCE_PCICFG_MISC_STATUS_M66EN) 1295157642Sps sc->bus_speed_mhz = 66; 1296157642Sps else 1297157642Sps sc->bus_speed_mhz = 33; 1298157642Sps } 1299157642Sps 1300157642Sps if (val & BCE_PCICFG_MISC_STATUS_32BIT_DET) 1301157642Sps sc->bce_flags |= BCE_PCI_32BIT_FLAG; 1302157642Sps 1303235151Syongari /* Find the media type for the adapter. */ 1304235151Syongari bce_get_media(sc); 1305235151Syongari 1306206268Sdavidch /* Reset controller and announce to bootcode that driver is present. */ 1307157642Sps if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) { 1308179771Sdavidch BCE_PRINTF("%s(%d): Controller reset failed!\n", 1309206268Sdavidch __FILE__, __LINE__); 1310157642Sps rc = ENXIO; 1311157642Sps goto bce_attach_fail; 1312157642Sps } 1313157642Sps 1314157642Sps /* Initialize the controller. */ 1315157642Sps if (bce_chipinit(sc)) { 1316169271Sdavidch BCE_PRINTF("%s(%d): Controller initialization failed!\n", 1317206268Sdavidch __FILE__, __LINE__); 1318157642Sps rc = ENXIO; 1319157642Sps goto bce_attach_fail; 1320157642Sps } 1321157642Sps 1322157642Sps /* Perform NVRAM test. */ 1323157642Sps if (bce_nvram_test(sc)) { 1324169271Sdavidch BCE_PRINTF("%s(%d): NVRAM test failed!\n", 1325206268Sdavidch __FILE__, __LINE__); 1326157642Sps rc = ENXIO; 1327157642Sps goto bce_attach_fail; 1328157642Sps } 1329157642Sps 1330157642Sps /* Fetch the permanent Ethernet MAC address. */ 1331157642Sps bce_get_mac_addr(sc); 1332157642Sps 1333157642Sps /* Update statistics once every second. */ 1334157642Sps sc->bce_stats_ticks = 1000000 & 0xffff00; 1335157642Sps 1336170810Sdavidch /* Store data needed by PHY driver for backplane applications */ 1337194781Sdavidch sc->bce_shared_hw_cfg = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG); 1338194781Sdavidch sc->bce_port_hw_cfg = bce_shmem_rd(sc, BCE_PORT_HW_CFG_CONFIG); 1339170392Sdavidch 1340157642Sps /* Allocate DMA memory resources. */ 1341157642Sps if (bce_dma_alloc(dev)) { 1342169271Sdavidch BCE_PRINTF("%s(%d): DMA resource allocation failed!\n", 1343157642Sps __FILE__, __LINE__); 1344157642Sps rc = ENXIO; 1345157642Sps goto bce_attach_fail; 1346157642Sps } 1347157642Sps 1348157642Sps /* Allocate an ifnet structure. */ 1349157642Sps ifp = sc->bce_ifp = if_alloc(IFT_ETHER); 1350157642Sps if (ifp == NULL) { 1351179771Sdavidch BCE_PRINTF("%s(%d): Interface allocation failed!\n", 1352207411Sdavidch __FILE__, __LINE__); 1353157642Sps rc = ENXIO; 1354157642Sps goto bce_attach_fail; 1355157642Sps } 1356157642Sps 1357157642Sps /* Initialize the ifnet interface. */ 1358207411Sdavidch ifp->if_softc = sc; 1359157642Sps if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1360207411Sdavidch ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1361207411Sdavidch ifp->if_ioctl = bce_ioctl; 1362207411Sdavidch ifp->if_start = bce_start; 1363207411Sdavidch ifp->if_init = bce_init; 1364207411Sdavidch ifp->if_mtu = ETHERMTU; 1365170392Sdavidch 1366170392Sdavidch if (bce_tso_enable) { 1367170392Sdavidch ifp->if_hwassist = BCE_IF_HWASSIST | CSUM_TSO; 1368204374Syongari ifp->if_capabilities = BCE_IF_CAPABILITIES | IFCAP_TSO4 | 1369204374Syongari IFCAP_VLAN_HWTSO; 1370170392Sdavidch } else { 1371170392Sdavidch ifp->if_hwassist = BCE_IF_HWASSIST; 1372170392Sdavidch ifp->if_capabilities = BCE_IF_CAPABILITIES; 1373170392Sdavidch } 1374169632Sdavidch 1375235151Syongari#if __FreeBSD_version >= 800505 1376235151Syongari /* 1377235151Syongari * Introducing IFCAP_LINKSTATE didn't bump __FreeBSD_version 1378235151Syongari * so it's approximate value. 1379235151Syongari */ 1380235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) 1381235151Syongari ifp->if_capabilities |= IFCAP_LINKSTATE; 1382235151Syongari#endif 1383235151Syongari 1384207411Sdavidch ifp->if_capenable = ifp->if_capabilities; 1385157642Sps 1386182293Sdavidch /* 1387182293Sdavidch * Assume standard mbuf sizes for buffer allocation. 1388182293Sdavidch * This may change later if the MTU size is set to 1389182293Sdavidch * something other than 1500. 1390179771Sdavidch */ 1391218423Sdavidch bce_get_rx_buffer_sizes(sc, 1392218423Sdavidch (ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)); 1393176448Sdavidch 1394218423Sdavidch /* Recalculate our buffer allocation sizes. */ 1395218423Sdavidch ifp->if_snd.ifq_drv_maxlen = USABLE_TX_BD_ALLOC; 1396170810Sdavidch IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 1397170810Sdavidch IFQ_SET_READY(&ifp->if_snd); 1398170810Sdavidch 1399157642Sps if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) 1400170392Sdavidch ifp->if_baudrate = IF_Mbps(2500ULL); 1401157642Sps else 1402170392Sdavidch ifp->if_baudrate = IF_Mbps(1000); 1403157642Sps 1404207411Sdavidch /* Handle any special PHY initialization for SerDes PHYs. */ 1405207411Sdavidch bce_init_media(sc); 1406205300Sdavidch 1407235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { 1408235151Syongari ifmedia_init(&sc->bce_ifmedia, IFM_IMASK, bce_ifmedia_upd, 1409235151Syongari bce_ifmedia_sts); 1410235151Syongari /* 1411235151Syongari * We can't manually override remote PHY's link and assume 1412235151Syongari * PHY port configuration(Fiber or TP) is not changed after 1413235151Syongari * device attach. This may not be correct though. 1414235151Syongari */ 1415235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) != 0) { 1416235151Syongari if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) { 1417235151Syongari ifmedia_add(&sc->bce_ifmedia, 1418235151Syongari IFM_ETHER | IFM_2500_SX, 0, NULL); 1419235151Syongari ifmedia_add(&sc->bce_ifmedia, 1420235151Syongari IFM_ETHER | IFM_2500_SX | IFM_FDX, 0, NULL); 1421235151Syongari } 1422235151Syongari ifmedia_add(&sc->bce_ifmedia, 1423235151Syongari IFM_ETHER | IFM_1000_SX, 0, NULL); 1424235151Syongari ifmedia_add(&sc->bce_ifmedia, 1425235151Syongari IFM_ETHER | IFM_1000_SX | IFM_FDX, 0, NULL); 1426235151Syongari } else { 1427235151Syongari ifmedia_add(&sc->bce_ifmedia, 1428235151Syongari IFM_ETHER | IFM_10_T, 0, NULL); 1429235151Syongari ifmedia_add(&sc->bce_ifmedia, 1430235151Syongari IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); 1431235151Syongari ifmedia_add(&sc->bce_ifmedia, 1432235151Syongari IFM_ETHER | IFM_100_TX, 0, NULL); 1433235151Syongari ifmedia_add(&sc->bce_ifmedia, 1434235151Syongari IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); 1435235151Syongari ifmedia_add(&sc->bce_ifmedia, 1436235151Syongari IFM_ETHER | IFM_1000_T, 0, NULL); 1437235151Syongari ifmedia_add(&sc->bce_ifmedia, 1438235151Syongari IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 1439235151Syongari } 1440235151Syongari ifmedia_add(&sc->bce_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); 1441235151Syongari ifmedia_set(&sc->bce_ifmedia, IFM_ETHER | IFM_AUTO); 1442235151Syongari sc->bce_ifmedia.ifm_media = sc->bce_ifmedia.ifm_cur->ifm_media; 1443235151Syongari } else { 1444235151Syongari /* MII child bus by attaching the PHY. */ 1445235151Syongari rc = mii_attach(dev, &sc->bce_miibus, ifp, bce_ifmedia_upd, 1446235151Syongari bce_ifmedia_sts, BMSR_DEFCAPMASK, sc->bce_phy_addr, 1447235151Syongari MII_OFFSET_ANY, MIIF_DOPAUSE); 1448235151Syongari if (rc != 0) { 1449235151Syongari BCE_PRINTF("%s(%d): attaching PHYs failed\n", __FILE__, 1450235151Syongari __LINE__); 1451235151Syongari goto bce_attach_fail; 1452235151Syongari } 1453157642Sps } 1454157642Sps 1455157642Sps /* Attach to the Ethernet interface list. */ 1456157642Sps ether_ifattach(ifp, sc->eaddr); 1457157642Sps 1458157642Sps#if __FreeBSD_version < 500000 1459170810Sdavidch callout_init(&sc->bce_tick_callout); 1460170810Sdavidch callout_init(&sc->bce_pulse_callout); 1461157642Sps#else 1462170810Sdavidch callout_init_mtx(&sc->bce_tick_callout, &sc->bce_mtx, 0); 1463170810Sdavidch callout_init_mtx(&sc->bce_pulse_callout, &sc->bce_mtx, 0); 1464157642Sps#endif 1465157642Sps 1466157642Sps /* Hookup IRQ last. */ 1467179771Sdavidch rc = bus_setup_intr(dev, sc->bce_res_irq, INTR_TYPE_NET | INTR_MPSAFE, 1468179771Sdavidch NULL, bce_intr, sc, &sc->bce_intrhand); 1469157642Sps 1470157642Sps if (rc) { 1471179771Sdavidch BCE_PRINTF("%s(%d): Failed to setup IRQ!\n", 1472207411Sdavidch __FILE__, __LINE__); 1473157642Sps bce_detach(dev); 1474157642Sps goto bce_attach_exit; 1475157642Sps } 1476157642Sps 1477179771Sdavidch /* 1478179771Sdavidch * At this point we've acquired all the resources 1479170810Sdavidch * we need to run so there's no turning back, we're 1480170810Sdavidch * cleared for launch. 1481170810Sdavidch */ 1482170810Sdavidch 1483157642Sps /* Print some important debugging info. */ 1484176448Sdavidch DBRUNMSG(BCE_INFO, bce_dump_driver_state(sc)); 1485157642Sps 1486157642Sps /* Add the supported sysctls to the kernel. */ 1487157642Sps bce_add_sysctls(sc); 1488157642Sps 1489170810Sdavidch BCE_LOCK(sc); 1490182293Sdavidch 1491179771Sdavidch /* 1492170810Sdavidch * The chip reset earlier notified the bootcode that 1493170810Sdavidch * a driver is present. We now need to start our pulse 1494170810Sdavidch * routine so that the bootcode is reminded that we're 1495170810Sdavidch * still running. 1496170810Sdavidch */ 1497170810Sdavidch bce_pulse(sc); 1498170810Sdavidch 1499162474Sambrisko bce_mgmt_init_locked(sc); 1500170392Sdavidch BCE_UNLOCK(sc); 1501162474Sambrisko 1502170810Sdavidch /* Finally, print some useful adapter info */ 1503179771Sdavidch bce_print_adapter_info(sc); 1504176448Sdavidch DBPRINT(sc, BCE_FATAL, "%s(): sc = %p\n", 1505176448Sdavidch __FUNCTION__, sc); 1506170810Sdavidch 1507157642Sps goto bce_attach_exit; 1508157642Sps 1509157642Spsbce_attach_fail: 1510157642Sps bce_release_resources(sc); 1511157642Sps 1512157642Spsbce_attach_exit: 1513157642Sps 1514179771Sdavidch DBEXIT(BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET); 1515157642Sps 1516157642Sps return(rc); 1517157642Sps} 1518157642Sps 1519157642Sps 1520157642Sps/****************************************************************************/ 1521157642Sps/* Device detach function. */ 1522157642Sps/* */ 1523157642Sps/* Stops the controller, resets the controller, and releases resources. */ 1524157642Sps/* */ 1525157642Sps/* Returns: */ 1526157642Sps/* 0 on success, positive value on failure. */ 1527157642Sps/****************************************************************************/ 1528157642Spsstatic int 1529157642Spsbce_detach(device_t dev) 1530157642Sps{ 1531170810Sdavidch struct bce_softc *sc = device_get_softc(dev); 1532157642Sps struct ifnet *ifp; 1533170810Sdavidch u32 msg; 1534157642Sps 1535179771Sdavidch DBENTER(BCE_VERBOSE_UNLOAD | BCE_VERBOSE_RESET); 1536157642Sps 1537157642Sps ifp = sc->bce_ifp; 1538157642Sps 1539176448Sdavidch /* Stop and reset the controller. */ 1540176448Sdavidch BCE_LOCK(sc); 1541176448Sdavidch 1542170810Sdavidch /* Stop the pulse so the bootcode can go to driver absent state. */ 1543170810Sdavidch callout_stop(&sc->bce_pulse_callout); 1544170810Sdavidch 1545157642Sps bce_stop(sc); 1546170810Sdavidch if (sc->bce_flags & BCE_NO_WOL_FLAG) 1547170810Sdavidch msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN; 1548170810Sdavidch else 1549170810Sdavidch msg = BCE_DRV_MSG_CODE_UNLOAD; 1550170810Sdavidch bce_reset(sc, msg); 1551176448Sdavidch 1552157642Sps BCE_UNLOCK(sc); 1553157642Sps 1554157642Sps ether_ifdetach(ifp); 1555157642Sps 1556157642Sps /* If we have a child device on the MII bus remove it too. */ 1557235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) 1558235151Syongari ifmedia_removeall(&sc->bce_ifmedia); 1559235151Syongari else { 1560235151Syongari bus_generic_detach(dev); 1561235151Syongari device_delete_child(dev, sc->bce_miibus); 1562235151Syongari } 1563157642Sps 1564157642Sps /* Release all remaining resources. */ 1565157642Sps bce_release_resources(sc); 1566157642Sps 1567179771Sdavidch DBEXIT(BCE_VERBOSE_UNLOAD | BCE_VERBOSE_RESET); 1568157642Sps 1569157642Sps return(0); 1570157642Sps} 1571157642Sps 1572157642Sps 1573157642Sps/****************************************************************************/ 1574157642Sps/* Device shutdown function. */ 1575157642Sps/* */ 1576157642Sps/* Stops and resets the controller. */ 1577157642Sps/* */ 1578157642Sps/* Returns: */ 1579173839Syongari/* 0 on success, positive value on failure. */ 1580157642Sps/****************************************************************************/ 1581173839Syongaristatic int 1582157642Spsbce_shutdown(device_t dev) 1583157642Sps{ 1584157642Sps struct bce_softc *sc = device_get_softc(dev); 1585170810Sdavidch u32 msg; 1586157642Sps 1587179771Sdavidch DBENTER(BCE_VERBOSE); 1588170810Sdavidch 1589157642Sps BCE_LOCK(sc); 1590157642Sps bce_stop(sc); 1591170810Sdavidch if (sc->bce_flags & BCE_NO_WOL_FLAG) 1592170810Sdavidch msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN; 1593170810Sdavidch else 1594170810Sdavidch msg = BCE_DRV_MSG_CODE_UNLOAD; 1595170810Sdavidch bce_reset(sc, msg); 1596157642Sps BCE_UNLOCK(sc); 1597173839Syongari 1598179771Sdavidch DBEXIT(BCE_VERBOSE); 1599179771Sdavidch 1600173839Syongari return (0); 1601157642Sps} 1602157642Sps 1603157642Sps 1604179771Sdavidch#ifdef BCE_DEBUG 1605157642Sps/****************************************************************************/ 1606179771Sdavidch/* Register read. */ 1607179771Sdavidch/* */ 1608179771Sdavidch/* Returns: */ 1609179771Sdavidch/* The value of the register. */ 1610179771Sdavidch/****************************************************************************/ 1611179771Sdavidchstatic u32 1612179771Sdavidchbce_reg_rd(struct bce_softc *sc, u32 offset) 1613179771Sdavidch{ 1614247565Smarius u32 val = REG_RD(sc, offset); 1615179771Sdavidch DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n", 1616179771Sdavidch __FUNCTION__, offset, val); 1617179771Sdavidch return val; 1618179771Sdavidch} 1619179771Sdavidch 1620179771Sdavidch 1621179771Sdavidch/****************************************************************************/ 1622179771Sdavidch/* Register write (16 bit). */ 1623179771Sdavidch/* */ 1624179771Sdavidch/* Returns: */ 1625179771Sdavidch/* Nothing. */ 1626179771Sdavidch/****************************************************************************/ 1627179771Sdavidchstatic void 1628179771Sdavidchbce_reg_wr16(struct bce_softc *sc, u32 offset, u16 val) 1629179771Sdavidch{ 1630179771Sdavidch DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%04X\n", 1631179771Sdavidch __FUNCTION__, offset, val); 1632247565Smarius REG_WR16(sc, offset, val); 1633179771Sdavidch} 1634179771Sdavidch 1635179771Sdavidch 1636179771Sdavidch/****************************************************************************/ 1637179771Sdavidch/* Register write. */ 1638179771Sdavidch/* */ 1639179771Sdavidch/* Returns: */ 1640179771Sdavidch/* Nothing. */ 1641179771Sdavidch/****************************************************************************/ 1642179771Sdavidchstatic void 1643179771Sdavidchbce_reg_wr(struct bce_softc *sc, u32 offset, u32 val) 1644179771Sdavidch{ 1645179771Sdavidch DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n", 1646179771Sdavidch __FUNCTION__, offset, val); 1647247565Smarius REG_WR(sc, offset, val); 1648179771Sdavidch} 1649179771Sdavidch#endif 1650179771Sdavidch 1651179771Sdavidch/****************************************************************************/ 1652157642Sps/* Indirect register read. */ 1653157642Sps/* */ 1654157642Sps/* Reads NetXtreme II registers using an index/data register pair in PCI */ 1655157642Sps/* configuration space. Using this mechanism avoids issues with posted */ 1656157642Sps/* reads but is much slower than memory-mapped I/O. */ 1657157642Sps/* */ 1658157642Sps/* Returns: */ 1659157642Sps/* The value of the register. */ 1660157642Sps/****************************************************************************/ 1661157642Spsstatic u32 1662157642Spsbce_reg_rd_ind(struct bce_softc *sc, u32 offset) 1663157642Sps{ 1664157642Sps device_t dev; 1665157642Sps dev = sc->bce_dev; 1666157642Sps 1667157642Sps pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4); 1668157642Sps#ifdef BCE_DEBUG 1669157642Sps { 1670157642Sps u32 val; 1671157642Sps val = pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4); 1672179771Sdavidch DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n", 1673157642Sps __FUNCTION__, offset, val); 1674157642Sps return val; 1675157642Sps } 1676157642Sps#else 1677157642Sps return pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4); 1678157642Sps#endif 1679157642Sps} 1680157642Sps 1681157642Sps 1682157642Sps/****************************************************************************/ 1683157642Sps/* Indirect register write. */ 1684157642Sps/* */ 1685157642Sps/* Writes NetXtreme II registers using an index/data register pair in PCI */ 1686157642Sps/* configuration space. Using this mechanism avoids issues with posted */ 1687157642Sps/* writes but is muchh slower than memory-mapped I/O. */ 1688157642Sps/* */ 1689157642Sps/* Returns: */ 1690157642Sps/* Nothing. */ 1691157642Sps/****************************************************************************/ 1692157642Spsstatic void 1693157642Spsbce_reg_wr_ind(struct bce_softc *sc, u32 offset, u32 val) 1694157642Sps{ 1695157642Sps device_t dev; 1696157642Sps dev = sc->bce_dev; 1697157642Sps 1698179771Sdavidch DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n", 1699157642Sps __FUNCTION__, offset, val); 1700157642Sps 1701157642Sps pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4); 1702157642Sps pci_write_config(dev, BCE_PCICFG_REG_WINDOW, val, 4); 1703157642Sps} 1704157642Sps 1705178132Sdavidch 1706194781Sdavidch/****************************************************************************/ 1707194781Sdavidch/* Shared memory write. */ 1708194781Sdavidch/* */ 1709194781Sdavidch/* Writes NetXtreme II shared memory region. */ 1710194781Sdavidch/* */ 1711194781Sdavidch/* Returns: */ 1712194781Sdavidch/* Nothing. */ 1713194781Sdavidch/****************************************************************************/ 1714194781Sdavidchstatic void 1715194781Sdavidchbce_shmem_wr(struct bce_softc *sc, u32 offset, u32 val) 1716194781Sdavidch{ 1717207411Sdavidch DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "%s(): Writing 0x%08X to " 1718207411Sdavidch "0x%08X\n", __FUNCTION__, val, offset); 1719207411Sdavidch 1720194781Sdavidch bce_reg_wr_ind(sc, sc->bce_shmem_base + offset, val); 1721194781Sdavidch} 1722194781Sdavidch 1723194781Sdavidch 1724194781Sdavidch/****************************************************************************/ 1725194781Sdavidch/* Shared memory read. */ 1726194781Sdavidch/* */ 1727194781Sdavidch/* Reads NetXtreme II shared memory region. */ 1728194781Sdavidch/* */ 1729194781Sdavidch/* Returns: */ 1730194781Sdavidch/* The 32 bit value read. */ 1731194781Sdavidch/****************************************************************************/ 1732194781Sdavidchstatic u32 1733194781Sdavidchbce_shmem_rd(struct bce_softc *sc, u32 offset) 1734194781Sdavidch{ 1735207411Sdavidch u32 val = bce_reg_rd_ind(sc, sc->bce_shmem_base + offset); 1736207411Sdavidch 1737207411Sdavidch DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "%s(): Reading 0x%08X from " 1738207411Sdavidch "0x%08X\n", __FUNCTION__, val, offset); 1739207411Sdavidch 1740207411Sdavidch return val; 1741194781Sdavidch} 1742194781Sdavidch 1743194781Sdavidch 1744176448Sdavidch#ifdef BCE_DEBUG 1745176448Sdavidch/****************************************************************************/ 1746176448Sdavidch/* Context memory read. */ 1747176448Sdavidch/* */ 1748176448Sdavidch/* The NetXtreme II controller uses context memory to track connection */ 1749176448Sdavidch/* information for L2 and higher network protocols. */ 1750176448Sdavidch/* */ 1751176448Sdavidch/* Returns: */ 1752176448Sdavidch/* The requested 32 bit value of context memory. */ 1753176448Sdavidch/****************************************************************************/ 1754176448Sdavidchstatic u32 1755179771Sdavidchbce_ctx_rd(struct bce_softc *sc, u32 cid_addr, u32 ctx_offset) 1756176448Sdavidch{ 1757179771Sdavidch u32 idx, offset, retry_cnt = 5, val; 1758157642Sps 1759207411Sdavidch DBRUNIF((cid_addr > MAX_CID_ADDR || ctx_offset & 0x3 || 1760207411Sdavidch cid_addr & CTX_MASK), BCE_PRINTF("%s(): Invalid CID " 1761207411Sdavidch "address: 0x%08X.\n", __FUNCTION__, cid_addr)); 1762176448Sdavidch 1763179771Sdavidch offset = ctx_offset + cid_addr; 1764176448Sdavidch 1765226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 1766179771Sdavidch 1767179771Sdavidch REG_WR(sc, BCE_CTX_CTX_CTRL, (offset | BCE_CTX_CTX_CTRL_READ_REQ)); 1768179771Sdavidch 1769179771Sdavidch for (idx = 0; idx < retry_cnt; idx++) { 1770179771Sdavidch val = REG_RD(sc, BCE_CTX_CTX_CTRL); 1771179771Sdavidch if ((val & BCE_CTX_CTX_CTRL_READ_REQ) == 0) 1772179771Sdavidch break; 1773179771Sdavidch DELAY(5); 1774179771Sdavidch } 1775179771Sdavidch 1776179771Sdavidch if (val & BCE_CTX_CTX_CTRL_READ_REQ) 1777179771Sdavidch BCE_PRINTF("%s(%d); Unable to read CTX memory: " 1778207411Sdavidch "cid_addr = 0x%08X, offset = 0x%08X!\n", 1779207411Sdavidch __FILE__, __LINE__, cid_addr, ctx_offset); 1780179771Sdavidch 1781179771Sdavidch val = REG_RD(sc, BCE_CTX_CTX_DATA); 1782179771Sdavidch } else { 1783179771Sdavidch REG_WR(sc, BCE_CTX_DATA_ADR, offset); 1784179771Sdavidch val = REG_RD(sc, BCE_CTX_DATA); 1785179771Sdavidch } 1786179771Sdavidch 1787179771Sdavidch DBPRINT(sc, BCE_EXTREME_CTX, "%s(); cid_addr = 0x%08X, offset = 0x%08X, " 1788179771Sdavidch "val = 0x%08X\n", __FUNCTION__, cid_addr, ctx_offset, val); 1789179771Sdavidch 1790176448Sdavidch return(val); 1791176448Sdavidch} 1792176448Sdavidch#endif 1793176448Sdavidch 1794178132Sdavidch 1795157642Sps/****************************************************************************/ 1796157642Sps/* Context memory write. */ 1797157642Sps/* */ 1798157642Sps/* The NetXtreme II controller uses context memory to track connection */ 1799157642Sps/* information for L2 and higher network protocols. */ 1800157642Sps/* */ 1801157642Sps/* Returns: */ 1802157642Sps/* Nothing. */ 1803157642Sps/****************************************************************************/ 1804157642Spsstatic void 1805179771Sdavidchbce_ctx_wr(struct bce_softc *sc, u32 cid_addr, u32 ctx_offset, u32 ctx_val) 1806157642Sps{ 1807179771Sdavidch u32 idx, offset = ctx_offset + cid_addr; 1808179771Sdavidch u32 val, retry_cnt = 5; 1809157642Sps 1810179771Sdavidch DBPRINT(sc, BCE_EXTREME_CTX, "%s(); cid_addr = 0x%08X, offset = 0x%08X, " 1811179771Sdavidch "val = 0x%08X\n", __FUNCTION__, cid_addr, ctx_offset, ctx_val); 1812157642Sps 1813179771Sdavidch DBRUNIF((cid_addr > MAX_CID_ADDR || ctx_offset & 0x3 || cid_addr & CTX_MASK), 1814179771Sdavidch BCE_PRINTF("%s(): Invalid CID address: 0x%08X.\n", 1815207411Sdavidch __FUNCTION__, cid_addr)); 1816179771Sdavidch 1817226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 1818179771Sdavidch 1819179771Sdavidch REG_WR(sc, BCE_CTX_CTX_DATA, ctx_val); 1820179771Sdavidch REG_WR(sc, BCE_CTX_CTX_CTRL, (offset | BCE_CTX_CTX_CTRL_WRITE_REQ)); 1821179771Sdavidch 1822179771Sdavidch for (idx = 0; idx < retry_cnt; idx++) { 1823179771Sdavidch val = REG_RD(sc, BCE_CTX_CTX_CTRL); 1824179771Sdavidch if ((val & BCE_CTX_CTX_CTRL_WRITE_REQ) == 0) 1825179771Sdavidch break; 1826179771Sdavidch DELAY(5); 1827179771Sdavidch } 1828179771Sdavidch 1829179771Sdavidch if (val & BCE_CTX_CTX_CTRL_WRITE_REQ) 1830179771Sdavidch BCE_PRINTF("%s(%d); Unable to write CTX memory: " 1831207411Sdavidch "cid_addr = 0x%08X, offset = 0x%08X!\n", 1832207411Sdavidch __FILE__, __LINE__, cid_addr, ctx_offset); 1833179771Sdavidch 1834179771Sdavidch } else { 1835179771Sdavidch REG_WR(sc, BCE_CTX_DATA_ADR, offset); 1836179771Sdavidch REG_WR(sc, BCE_CTX_DATA, ctx_val); 1837179771Sdavidch } 1838157642Sps} 1839157642Sps 1840157642Sps 1841157642Sps/****************************************************************************/ 1842157642Sps/* PHY register read. */ 1843157642Sps/* */ 1844157642Sps/* Implements register reads on the MII bus. */ 1845157642Sps/* */ 1846157642Sps/* Returns: */ 1847157642Sps/* The value of the register. */ 1848157642Sps/****************************************************************************/ 1849157642Spsstatic int 1850157642Spsbce_miibus_read_reg(device_t dev, int phy, int reg) 1851157642Sps{ 1852157642Sps struct bce_softc *sc; 1853157642Sps u32 val; 1854157642Sps int i; 1855157642Sps 1856157642Sps sc = device_get_softc(dev); 1857157642Sps 1858205300Sdavidch /* 1859205300Sdavidch * The 5709S PHY is an IEEE Clause 45 PHY 1860205300Sdavidch * with special mappings to work with IEEE 1861205300Sdavidch * Clause 22 register accesses. 1862205300Sdavidch */ 1863205300Sdavidch if ((sc->bce_phy_flags & BCE_PHY_IEEE_CLAUSE_45_FLAG) != 0) { 1864205300Sdavidch if (reg >= MII_BMCR && reg <= MII_ANLPRNP) 1865205300Sdavidch reg += 0x10; 1866205300Sdavidch } 1867205300Sdavidch 1868205300Sdavidch if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) { 1869157642Sps val = REG_RD(sc, BCE_EMAC_MDIO_MODE); 1870157642Sps val &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL; 1871157642Sps 1872157642Sps REG_WR(sc, BCE_EMAC_MDIO_MODE, val); 1873157642Sps REG_RD(sc, BCE_EMAC_MDIO_MODE); 1874157642Sps 1875157642Sps DELAY(40); 1876157642Sps } 1877157642Sps 1878179771Sdavidch 1879157642Sps val = BCE_MIPHY(phy) | BCE_MIREG(reg) | 1880206268Sdavidch BCE_EMAC_MDIO_COMM_COMMAND_READ | BCE_EMAC_MDIO_COMM_DISEXT | 1881206268Sdavidch BCE_EMAC_MDIO_COMM_START_BUSY; 1882157642Sps REG_WR(sc, BCE_EMAC_MDIO_COMM, val); 1883157642Sps 1884157642Sps for (i = 0; i < BCE_PHY_TIMEOUT; i++) { 1885157642Sps DELAY(10); 1886157642Sps 1887157642Sps val = REG_RD(sc, BCE_EMAC_MDIO_COMM); 1888157642Sps if (!(val & BCE_EMAC_MDIO_COMM_START_BUSY)) { 1889157642Sps DELAY(5); 1890157642Sps 1891157642Sps val = REG_RD(sc, BCE_EMAC_MDIO_COMM); 1892157642Sps val &= BCE_EMAC_MDIO_COMM_DATA; 1893157642Sps 1894157642Sps break; 1895157642Sps } 1896157642Sps } 1897157642Sps 1898157642Sps if (val & BCE_EMAC_MDIO_COMM_START_BUSY) { 1899206268Sdavidch BCE_PRINTF("%s(%d): Error: PHY read timeout! phy = %d, " 1900206268Sdavidch "reg = 0x%04X\n", __FILE__, __LINE__, phy, reg); 1901157642Sps val = 0x0; 1902157642Sps } else { 1903157642Sps val = REG_RD(sc, BCE_EMAC_MDIO_COMM); 1904157642Sps } 1905157642Sps 1906157642Sps 1907157642Sps if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) { 1908157642Sps val = REG_RD(sc, BCE_EMAC_MDIO_MODE); 1909157642Sps val |= BCE_EMAC_MDIO_MODE_AUTO_POLL; 1910157642Sps 1911157642Sps REG_WR(sc, BCE_EMAC_MDIO_MODE, val); 1912157642Sps REG_RD(sc, BCE_EMAC_MDIO_MODE); 1913157642Sps 1914157642Sps DELAY(40); 1915157642Sps } 1916157642Sps 1917179771Sdavidch DB_PRINT_PHY_REG(reg, val); 1918157642Sps return (val & 0xffff); 1919157642Sps} 1920157642Sps 1921157642Sps 1922157642Sps/****************************************************************************/ 1923157642Sps/* PHY register write. */ 1924157642Sps/* */ 1925157642Sps/* Implements register writes on the MII bus. */ 1926157642Sps/* */ 1927157642Sps/* Returns: */ 1928157642Sps/* The value of the register. */ 1929157642Sps/****************************************************************************/ 1930157642Spsstatic int 1931157642Spsbce_miibus_write_reg(device_t dev, int phy, int reg, int val) 1932157642Sps{ 1933157642Sps struct bce_softc *sc; 1934157642Sps u32 val1; 1935157642Sps int i; 1936157642Sps 1937157642Sps sc = device_get_softc(dev); 1938157642Sps 1939179771Sdavidch DB_PRINT_PHY_REG(reg, val); 1940157642Sps 1941206268Sdavidch /* 1942206268Sdavidch * The 5709S PHY is an IEEE Clause 45 PHY 1943206268Sdavidch * with special mappings to work with IEEE 1944206268Sdavidch * Clause 22 register accesses. 1945206268Sdavidch */ 1946205300Sdavidch if ((sc->bce_phy_flags & BCE_PHY_IEEE_CLAUSE_45_FLAG) != 0) { 1947205300Sdavidch if (reg >= MII_BMCR && reg <= MII_ANLPRNP) 1948205300Sdavidch reg += 0x10; 1949205300Sdavidch } 1950205300Sdavidch 1951157642Sps if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) { 1952157642Sps val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE); 1953157642Sps val1 &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL; 1954157642Sps 1955157642Sps REG_WR(sc, BCE_EMAC_MDIO_MODE, val1); 1956157642Sps REG_RD(sc, BCE_EMAC_MDIO_MODE); 1957157642Sps 1958157642Sps DELAY(40); 1959157642Sps } 1960157642Sps 1961157642Sps val1 = BCE_MIPHY(phy) | BCE_MIREG(reg) | val | 1962206268Sdavidch BCE_EMAC_MDIO_COMM_COMMAND_WRITE | 1963206268Sdavidch BCE_EMAC_MDIO_COMM_START_BUSY | BCE_EMAC_MDIO_COMM_DISEXT; 1964157642Sps REG_WR(sc, BCE_EMAC_MDIO_COMM, val1); 1965157642Sps 1966157642Sps for (i = 0; i < BCE_PHY_TIMEOUT; i++) { 1967157642Sps DELAY(10); 1968157642Sps 1969157642Sps val1 = REG_RD(sc, BCE_EMAC_MDIO_COMM); 1970157642Sps if (!(val1 & BCE_EMAC_MDIO_COMM_START_BUSY)) { 1971157642Sps DELAY(5); 1972157642Sps break; 1973157642Sps } 1974157642Sps } 1975157642Sps 1976157642Sps if (val1 & BCE_EMAC_MDIO_COMM_START_BUSY) 1977179771Sdavidch BCE_PRINTF("%s(%d): PHY write timeout!\n", 1978206268Sdavidch __FILE__, __LINE__); 1979157642Sps 1980157642Sps if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) { 1981157642Sps val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE); 1982157642Sps val1 |= BCE_EMAC_MDIO_MODE_AUTO_POLL; 1983157642Sps 1984157642Sps REG_WR(sc, BCE_EMAC_MDIO_MODE, val1); 1985157642Sps REG_RD(sc, BCE_EMAC_MDIO_MODE); 1986157642Sps 1987157642Sps DELAY(40); 1988157642Sps } 1989157642Sps 1990157642Sps return 0; 1991157642Sps} 1992157642Sps 1993157642Sps 1994157642Sps/****************************************************************************/ 1995157642Sps/* MII bus status change. */ 1996157642Sps/* */ 1997157642Sps/* Called by the MII bus driver when the PHY establishes link to set the */ 1998157642Sps/* MAC interface registers. */ 1999157642Sps/* */ 2000157642Sps/* Returns: */ 2001157642Sps/* Nothing. */ 2002157642Sps/****************************************************************************/ 2003157642Spsstatic void 2004157642Spsbce_miibus_statchg(device_t dev) 2005157642Sps{ 2006157642Sps struct bce_softc *sc; 2007157642Sps struct mii_data *mii; 2008235151Syongari struct ifmediareq ifmr; 2009235151Syongari int media_active, media_status, val; 2010157642Sps 2011157642Sps sc = device_get_softc(dev); 2012157642Sps 2013179771Sdavidch DBENTER(BCE_VERBOSE_PHY); 2014179771Sdavidch 2015235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { 2016235151Syongari bzero(&ifmr, sizeof(ifmr)); 2017235151Syongari bce_ifmedia_sts_rphy(sc, &ifmr); 2018235151Syongari media_active = ifmr.ifm_active; 2019235151Syongari media_status = ifmr.ifm_status; 2020235151Syongari } else { 2021235151Syongari mii = device_get_softc(sc->bce_miibus); 2022235151Syongari media_active = mii->mii_media_active; 2023235151Syongari media_status = mii->mii_media_status; 2024235151Syongari } 2025157642Sps 2026235816Syongari /* Ignore invalid media status. */ 2027235816Syongari if ((media_status & (IFM_ACTIVE | IFM_AVALID)) != 2028235816Syongari (IFM_ACTIVE | IFM_AVALID)) 2029235816Syongari goto bce_miibus_statchg_exit; 2030235816Syongari 2031170392Sdavidch val = REG_RD(sc, BCE_EMAC_MODE); 2032179771Sdavidch val &= ~(BCE_EMAC_MODE_PORT | BCE_EMAC_MODE_HALF_DUPLEX | 2033207411Sdavidch BCE_EMAC_MODE_MAC_LOOP | BCE_EMAC_MODE_FORCE_LINK | 2034207411Sdavidch BCE_EMAC_MODE_25G); 2035157642Sps 2036207411Sdavidch /* Set MII or GMII interface based on the PHY speed. */ 2037235151Syongari switch (IFM_SUBTYPE(media_active)) { 2038234121Syongari case IFM_10_T: 2039234121Syongari if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5706) { 2040234121Syongari DBPRINT(sc, BCE_INFO_PHY, 2041234121Syongari "Enabling 10Mb interface.\n"); 2042234121Syongari val |= BCE_EMAC_MODE_PORT_MII_10; 2043170392Sdavidch break; 2044170392Sdavidch } 2045234121Syongari /* fall-through */ 2046234121Syongari case IFM_100_TX: 2047234121Syongari DBPRINT(sc, BCE_INFO_PHY, "Enabling MII interface.\n"); 2048234121Syongari val |= BCE_EMAC_MODE_PORT_MII; 2049234121Syongari break; 2050234121Syongari case IFM_2500_SX: 2051234121Syongari DBPRINT(sc, BCE_INFO_PHY, "Enabling 2.5G MAC mode.\n"); 2052234121Syongari val |= BCE_EMAC_MODE_25G; 2053234121Syongari /* fall-through */ 2054234121Syongari case IFM_1000_T: 2055234121Syongari case IFM_1000_SX: 2056234121Syongari DBPRINT(sc, BCE_INFO_PHY, "Enabling GMII interface.\n"); 2057234121Syongari val |= BCE_EMAC_MODE_PORT_GMII; 2058234121Syongari break; 2059234121Syongari default: 2060234121Syongari DBPRINT(sc, BCE_INFO_PHY, "Unknown link speed, enabling " 2061234121Syongari "default GMII interface.\n"); 2062234121Syongari val |= BCE_EMAC_MODE_PORT_GMII; 2063157642Sps } 2064157642Sps 2065207411Sdavidch /* Set half or full duplex based on PHY settings. */ 2066235151Syongari if ((IFM_OPTIONS(media_active) & IFM_FDX) == 0) { 2067207411Sdavidch DBPRINT(sc, BCE_INFO_PHY, 2068207411Sdavidch "Setting Half-Duplex interface.\n"); 2069170392Sdavidch val |= BCE_EMAC_MODE_HALF_DUPLEX; 2070170392Sdavidch } else 2071207411Sdavidch DBPRINT(sc, BCE_INFO_PHY, 2072207411Sdavidch "Setting Full-Duplex interface.\n"); 2073170392Sdavidch 2074170392Sdavidch REG_WR(sc, BCE_EMAC_MODE, val); 2075170392Sdavidch 2076235151Syongari if ((IFM_OPTIONS(media_active) & IFM_ETH_RXPAUSE) != 0) { 2077207411Sdavidch DBPRINT(sc, BCE_INFO_PHY, 2078207411Sdavidch "%s(): Enabling RX flow control.\n", __FUNCTION__); 2079170392Sdavidch BCE_SETBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN); 2080252402Syongari sc->bce_flags |= BCE_USING_RX_FLOW_CONTROL; 2081207411Sdavidch } else { 2082207411Sdavidch DBPRINT(sc, BCE_INFO_PHY, 2083207411Sdavidch "%s(): Disabling RX flow control.\n", __FUNCTION__); 2084207411Sdavidch BCE_CLRBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN); 2085252402Syongari sc->bce_flags &= ~BCE_USING_RX_FLOW_CONTROL; 2086207411Sdavidch } 2087170392Sdavidch 2088235151Syongari if ((IFM_OPTIONS(media_active) & IFM_ETH_TXPAUSE) != 0) { 2089207411Sdavidch DBPRINT(sc, BCE_INFO_PHY, 2090207411Sdavidch "%s(): Enabling TX flow control.\n", __FUNCTION__); 2091207411Sdavidch BCE_SETBIT(sc, BCE_EMAC_TX_MODE, BCE_EMAC_TX_MODE_FLOW_EN); 2092207411Sdavidch sc->bce_flags |= BCE_USING_TX_FLOW_CONTROL; 2093207411Sdavidch } else { 2094207411Sdavidch DBPRINT(sc, BCE_INFO_PHY, 2095207411Sdavidch "%s(): Disabling TX flow control.\n", __FUNCTION__); 2096207411Sdavidch BCE_CLRBIT(sc, BCE_EMAC_TX_MODE, BCE_EMAC_TX_MODE_FLOW_EN); 2097207411Sdavidch sc->bce_flags &= ~BCE_USING_TX_FLOW_CONTROL; 2098207411Sdavidch } 2099207411Sdavidch 2100207411Sdavidch /* ToDo: Update watermarks in bce_init_rx_context(). */ 2101207411Sdavidch 2102235816Syongaribce_miibus_statchg_exit: 2103179771Sdavidch DBEXIT(BCE_VERBOSE_PHY); 2104157642Sps} 2105157642Sps 2106157642Sps 2107157642Sps/****************************************************************************/ 2108157642Sps/* Acquire NVRAM lock. */ 2109157642Sps/* */ 2110157642Sps/* Before the NVRAM can be accessed the caller must acquire an NVRAM lock. */ 2111157642Sps/* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is */ 2112157642Sps/* for use by the driver. */ 2113157642Sps/* */ 2114157642Sps/* Returns: */ 2115157642Sps/* 0 on success, positive value on failure. */ 2116157642Sps/****************************************************************************/ 2117157642Spsstatic int 2118157642Spsbce_acquire_nvram_lock(struct bce_softc *sc) 2119157642Sps{ 2120157642Sps u32 val; 2121179771Sdavidch int j, rc = 0; 2122157642Sps 2123179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2124157642Sps 2125157642Sps /* Request access to the flash interface. */ 2126157642Sps REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_SET2); 2127157642Sps for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 2128157642Sps val = REG_RD(sc, BCE_NVM_SW_ARB); 2129157642Sps if (val & BCE_NVM_SW_ARB_ARB_ARB2) 2130157642Sps break; 2131157642Sps 2132157642Sps DELAY(5); 2133157642Sps } 2134157642Sps 2135157642Sps if (j >= NVRAM_TIMEOUT_COUNT) { 2136157642Sps DBPRINT(sc, BCE_WARN, "Timeout acquiring NVRAM lock!\n"); 2137179771Sdavidch rc = EBUSY; 2138157642Sps } 2139157642Sps 2140179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2141179771Sdavidch return (rc); 2142157642Sps} 2143157642Sps 2144157642Sps 2145157642Sps/****************************************************************************/ 2146157642Sps/* Release NVRAM lock. */ 2147157642Sps/* */ 2148157642Sps/* When the caller is finished accessing NVRAM the lock must be released. */ 2149157642Sps/* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is */ 2150157642Sps/* for use by the driver. */ 2151157642Sps/* */ 2152157642Sps/* Returns: */ 2153157642Sps/* 0 on success, positive value on failure. */ 2154157642Sps/****************************************************************************/ 2155157642Spsstatic int 2156157642Spsbce_release_nvram_lock(struct bce_softc *sc) 2157157642Sps{ 2158157642Sps u32 val; 2159179771Sdavidch int j, rc = 0; 2160157642Sps 2161179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2162157642Sps 2163157642Sps /* 2164157642Sps * Relinquish nvram interface. 2165157642Sps */ 2166157642Sps REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_CLR2); 2167157642Sps 2168157642Sps for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 2169157642Sps val = REG_RD(sc, BCE_NVM_SW_ARB); 2170157642Sps if (!(val & BCE_NVM_SW_ARB_ARB_ARB2)) 2171157642Sps break; 2172157642Sps 2173157642Sps DELAY(5); 2174157642Sps } 2175157642Sps 2176157642Sps if (j >= NVRAM_TIMEOUT_COUNT) { 2177179771Sdavidch DBPRINT(sc, BCE_WARN, "Timeout releasing NVRAM lock!\n"); 2178179771Sdavidch rc = EBUSY; 2179157642Sps } 2180157642Sps 2181179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2182179771Sdavidch return (rc); 2183157642Sps} 2184157642Sps 2185157642Sps 2186157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT 2187157642Sps/****************************************************************************/ 2188157642Sps/* Enable NVRAM write access. */ 2189157642Sps/* */ 2190157642Sps/* Before writing to NVRAM the caller must enable NVRAM writes. */ 2191157642Sps/* */ 2192157642Sps/* Returns: */ 2193157642Sps/* 0 on success, positive value on failure. */ 2194157642Sps/****************************************************************************/ 2195157642Spsstatic int 2196157642Spsbce_enable_nvram_write(struct bce_softc *sc) 2197157642Sps{ 2198157642Sps u32 val; 2199179771Sdavidch int rc = 0; 2200157642Sps 2201179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2202157642Sps 2203157642Sps val = REG_RD(sc, BCE_MISC_CFG); 2204157642Sps REG_WR(sc, BCE_MISC_CFG, val | BCE_MISC_CFG_NVM_WR_EN_PCI); 2205157642Sps 2206179771Sdavidch if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) { 2207157642Sps int j; 2208157642Sps 2209157642Sps REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE); 2210157642Sps REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_WREN | BCE_NVM_COMMAND_DOIT); 2211157642Sps 2212157642Sps for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 2213157642Sps DELAY(5); 2214157642Sps 2215157642Sps val = REG_RD(sc, BCE_NVM_COMMAND); 2216157642Sps if (val & BCE_NVM_COMMAND_DONE) 2217157642Sps break; 2218157642Sps } 2219157642Sps 2220157642Sps if (j >= NVRAM_TIMEOUT_COUNT) { 2221157642Sps DBPRINT(sc, BCE_WARN, "Timeout writing NVRAM!\n"); 2222179771Sdavidch rc = EBUSY; 2223157642Sps } 2224157642Sps } 2225179771Sdavidch 2226179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2227179771Sdavidch return (rc); 2228157642Sps} 2229157642Sps 2230157642Sps 2231157642Sps/****************************************************************************/ 2232157642Sps/* Disable NVRAM write access. */ 2233157642Sps/* */ 2234157642Sps/* When the caller is finished writing to NVRAM write access must be */ 2235157642Sps/* disabled. */ 2236157642Sps/* */ 2237157642Sps/* Returns: */ 2238157642Sps/* Nothing. */ 2239157642Sps/****************************************************************************/ 2240157642Spsstatic void 2241157642Spsbce_disable_nvram_write(struct bce_softc *sc) 2242157642Sps{ 2243157642Sps u32 val; 2244157642Sps 2245179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2246157642Sps 2247157642Sps val = REG_RD(sc, BCE_MISC_CFG); 2248157642Sps REG_WR(sc, BCE_MISC_CFG, val & ~BCE_MISC_CFG_NVM_WR_EN); 2249179771Sdavidch 2250179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2251179771Sdavidch 2252157642Sps} 2253157642Sps#endif 2254157642Sps 2255157642Sps 2256157642Sps/****************************************************************************/ 2257157642Sps/* Enable NVRAM access. */ 2258157642Sps/* */ 2259157642Sps/* Before accessing NVRAM for read or write operations the caller must */ 2260157642Sps/* enabled NVRAM access. */ 2261157642Sps/* */ 2262157642Sps/* Returns: */ 2263157642Sps/* Nothing. */ 2264157642Sps/****************************************************************************/ 2265157642Spsstatic void 2266157642Spsbce_enable_nvram_access(struct bce_softc *sc) 2267157642Sps{ 2268157642Sps u32 val; 2269157642Sps 2270179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2271157642Sps 2272157642Sps val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE); 2273157642Sps /* Enable both bits, even on read. */ 2274207411Sdavidch REG_WR(sc, BCE_NVM_ACCESS_ENABLE, val | 2275207411Sdavidch BCE_NVM_ACCESS_ENABLE_EN | BCE_NVM_ACCESS_ENABLE_WR_EN); 2276179771Sdavidch 2277179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2278157642Sps} 2279157642Sps 2280157642Sps 2281157642Sps/****************************************************************************/ 2282157642Sps/* Disable NVRAM access. */ 2283157642Sps/* */ 2284157642Sps/* When the caller is finished accessing NVRAM access must be disabled. */ 2285157642Sps/* */ 2286157642Sps/* Returns: */ 2287157642Sps/* Nothing. */ 2288157642Sps/****************************************************************************/ 2289157642Spsstatic void 2290157642Spsbce_disable_nvram_access(struct bce_softc *sc) 2291157642Sps{ 2292157642Sps u32 val; 2293157642Sps 2294179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2295157642Sps 2296157642Sps val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE); 2297157642Sps 2298157642Sps /* Disable both bits, even after read. */ 2299207411Sdavidch REG_WR(sc, BCE_NVM_ACCESS_ENABLE, val & 2300207411Sdavidch ~(BCE_NVM_ACCESS_ENABLE_EN | BCE_NVM_ACCESS_ENABLE_WR_EN)); 2301179771Sdavidch 2302179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2303157642Sps} 2304157642Sps 2305157642Sps 2306157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT 2307157642Sps/****************************************************************************/ 2308157642Sps/* Erase NVRAM page before writing. */ 2309157642Sps/* */ 2310157642Sps/* Non-buffered flash parts require that a page be erased before it is */ 2311157642Sps/* written. */ 2312157642Sps/* */ 2313157642Sps/* Returns: */ 2314157642Sps/* 0 on success, positive value on failure. */ 2315157642Sps/****************************************************************************/ 2316157642Spsstatic int 2317157642Spsbce_nvram_erase_page(struct bce_softc *sc, u32 offset) 2318157642Sps{ 2319157642Sps u32 cmd; 2320179771Sdavidch int j, rc = 0; 2321157642Sps 2322179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2323179771Sdavidch 2324157642Sps /* Buffered flash doesn't require an erase. */ 2325179771Sdavidch if (sc->bce_flash_info->flags & BCE_NV_BUFFERED) 2326179771Sdavidch goto bce_nvram_erase_page_exit; 2327157642Sps 2328157642Sps /* Build an erase command. */ 2329157642Sps cmd = BCE_NVM_COMMAND_ERASE | BCE_NVM_COMMAND_WR | 2330207411Sdavidch BCE_NVM_COMMAND_DOIT; 2331157642Sps 2332157642Sps /* 2333157642Sps * Clear the DONE bit separately, set the NVRAM adress to erase, 2334157642Sps * and issue the erase command. 2335157642Sps */ 2336157642Sps REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE); 2337157642Sps REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE); 2338157642Sps REG_WR(sc, BCE_NVM_COMMAND, cmd); 2339157642Sps 2340157642Sps /* Wait for completion. */ 2341157642Sps for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 2342157642Sps u32 val; 2343157642Sps 2344157642Sps DELAY(5); 2345157642Sps 2346157642Sps val = REG_RD(sc, BCE_NVM_COMMAND); 2347157642Sps if (val & BCE_NVM_COMMAND_DONE) 2348157642Sps break; 2349157642Sps } 2350157642Sps 2351157642Sps if (j >= NVRAM_TIMEOUT_COUNT) { 2352157642Sps DBPRINT(sc, BCE_WARN, "Timeout erasing NVRAM.\n"); 2353179771Sdavidch rc = EBUSY; 2354157642Sps } 2355157642Sps 2356179771Sdavidchbce_nvram_erase_page_exit: 2357179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2358179771Sdavidch return (rc); 2359157642Sps} 2360157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */ 2361157642Sps 2362157642Sps 2363157642Sps/****************************************************************************/ 2364157642Sps/* Read a dword (32 bits) from NVRAM. */ 2365157642Sps/* */ 2366157642Sps/* Read a 32 bit word from NVRAM. The caller is assumed to have already */ 2367157642Sps/* obtained the NVRAM lock and enabled the controller for NVRAM access. */ 2368157642Sps/* */ 2369157642Sps/* Returns: */ 2370157642Sps/* 0 on success and the 32 bit value read, positive value on failure. */ 2371157642Sps/****************************************************************************/ 2372157642Spsstatic int 2373207411Sdavidchbce_nvram_read_dword(struct bce_softc *sc, 2374207411Sdavidch u32 offset, u8 *ret_val, u32 cmd_flags) 2375157642Sps{ 2376157642Sps u32 cmd; 2377157642Sps int i, rc = 0; 2378157642Sps 2379179771Sdavidch DBENTER(BCE_EXTREME_NVRAM); 2380179771Sdavidch 2381157642Sps /* Build the command word. */ 2382157642Sps cmd = BCE_NVM_COMMAND_DOIT | cmd_flags; 2383157642Sps 2384179771Sdavidch /* Calculate the offset for buffered flash if translation is used. */ 2385179771Sdavidch if (sc->bce_flash_info->flags & BCE_NV_TRANSLATE) { 2386157642Sps offset = ((offset / sc->bce_flash_info->page_size) << 2387207411Sdavidch sc->bce_flash_info->page_bits) + 2388207411Sdavidch (offset % sc->bce_flash_info->page_size); 2389157642Sps } 2390157642Sps 2391157642Sps /* 2392157642Sps * Clear the DONE bit separately, set the address to read, 2393157642Sps * and issue the read. 2394157642Sps */ 2395157642Sps REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE); 2396157642Sps REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE); 2397157642Sps REG_WR(sc, BCE_NVM_COMMAND, cmd); 2398157642Sps 2399157642Sps /* Wait for completion. */ 2400157642Sps for (i = 0; i < NVRAM_TIMEOUT_COUNT; i++) { 2401157642Sps u32 val; 2402157642Sps 2403157642Sps DELAY(5); 2404157642Sps 2405157642Sps val = REG_RD(sc, BCE_NVM_COMMAND); 2406157642Sps if (val & BCE_NVM_COMMAND_DONE) { 2407157642Sps val = REG_RD(sc, BCE_NVM_READ); 2408157642Sps 2409157642Sps val = bce_be32toh(val); 2410157642Sps memcpy(ret_val, &val, 4); 2411157642Sps break; 2412157642Sps } 2413157642Sps } 2414157642Sps 2415157642Sps /* Check for errors. */ 2416157642Sps if (i >= NVRAM_TIMEOUT_COUNT) { 2417207411Sdavidch BCE_PRINTF("%s(%d): Timeout error reading NVRAM at " 2418207411Sdavidch "offset 0x%08X!\n", __FILE__, __LINE__, offset); 2419157642Sps rc = EBUSY; 2420157642Sps } 2421157642Sps 2422179771Sdavidch DBEXIT(BCE_EXTREME_NVRAM); 2423157642Sps return(rc); 2424157642Sps} 2425157642Sps 2426157642Sps 2427157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT 2428157642Sps/****************************************************************************/ 2429157642Sps/* Write a dword (32 bits) to NVRAM. */ 2430157642Sps/* */ 2431157642Sps/* Write a 32 bit word to NVRAM. The caller is assumed to have already */ 2432157642Sps/* obtained the NVRAM lock, enabled the controller for NVRAM access, and */ 2433157642Sps/* enabled NVRAM write access. */ 2434157642Sps/* */ 2435157642Sps/* Returns: */ 2436157642Sps/* 0 on success, positive value on failure. */ 2437157642Sps/****************************************************************************/ 2438157642Spsstatic int 2439157642Spsbce_nvram_write_dword(struct bce_softc *sc, u32 offset, u8 *val, 2440157642Sps u32 cmd_flags) 2441157642Sps{ 2442157642Sps u32 cmd, val32; 2443179771Sdavidch int j, rc = 0; 2444157642Sps 2445179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2446179771Sdavidch 2447157642Sps /* Build the command word. */ 2448157642Sps cmd = BCE_NVM_COMMAND_DOIT | BCE_NVM_COMMAND_WR | cmd_flags; 2449157642Sps 2450179771Sdavidch /* Calculate the offset for buffered flash if translation is used. */ 2451179771Sdavidch if (sc->bce_flash_info->flags & BCE_NV_TRANSLATE) { 2452157642Sps offset = ((offset / sc->bce_flash_info->page_size) << 2453207411Sdavidch sc->bce_flash_info->page_bits) + 2454207411Sdavidch (offset % sc->bce_flash_info->page_size); 2455157642Sps } 2456157642Sps 2457157642Sps /* 2458157642Sps * Clear the DONE bit separately, convert NVRAM data to big-endian, 2459157642Sps * set the NVRAM address to write, and issue the write command 2460157642Sps */ 2461157642Sps REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE); 2462157642Sps memcpy(&val32, val, 4); 2463157642Sps val32 = htobe32(val32); 2464157642Sps REG_WR(sc, BCE_NVM_WRITE, val32); 2465157642Sps REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE); 2466157642Sps REG_WR(sc, BCE_NVM_COMMAND, cmd); 2467157642Sps 2468157642Sps /* Wait for completion. */ 2469157642Sps for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 2470157642Sps DELAY(5); 2471157642Sps 2472157642Sps if (REG_RD(sc, BCE_NVM_COMMAND) & BCE_NVM_COMMAND_DONE) 2473157642Sps break; 2474157642Sps } 2475157642Sps if (j >= NVRAM_TIMEOUT_COUNT) { 2476207411Sdavidch BCE_PRINTF("%s(%d): Timeout error writing NVRAM at " 2477207411Sdavidch "offset 0x%08X\n", __FILE__, __LINE__, offset); 2478179771Sdavidch rc = EBUSY; 2479157642Sps } 2480157642Sps 2481179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2482179771Sdavidch return (rc); 2483157642Sps} 2484157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */ 2485157642Sps 2486157642Sps 2487157642Sps/****************************************************************************/ 2488157642Sps/* Initialize NVRAM access. */ 2489157642Sps/* */ 2490157642Sps/* Identify the NVRAM device in use and prepare the NVRAM interface to */ 2491157642Sps/* access that device. */ 2492157642Sps/* */ 2493157642Sps/* Returns: */ 2494157642Sps/* 0 on success, positive value on failure. */ 2495157642Sps/****************************************************************************/ 2496157642Spsstatic int 2497157642Spsbce_init_nvram(struct bce_softc *sc) 2498157642Sps{ 2499157642Sps u32 val; 2500179771Sdavidch int j, entry_count, rc = 0; 2501247565Smarius const struct flash_spec *flash; 2502157642Sps 2503179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2504157642Sps 2505226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 2506179771Sdavidch sc->bce_flash_info = &flash_5709; 2507179771Sdavidch goto bce_init_nvram_get_flash_size; 2508179771Sdavidch } 2509179771Sdavidch 2510157642Sps /* Determine the selected interface. */ 2511157642Sps val = REG_RD(sc, BCE_NVM_CFG1); 2512157642Sps 2513157642Sps entry_count = sizeof(flash_table) / sizeof(struct flash_spec); 2514157642Sps 2515157642Sps /* 2516157642Sps * Flash reconfiguration is required to support additional 2517157642Sps * NVRAM devices not directly supported in hardware. 2518157642Sps * Check if the flash interface was reconfigured 2519157642Sps * by the bootcode. 2520157642Sps */ 2521157642Sps 2522157642Sps if (val & 0x40000000) { 2523157642Sps /* Flash interface reconfigured by bootcode. */ 2524157642Sps 2525179771Sdavidch DBPRINT(sc,BCE_INFO_LOAD, 2526157642Sps "bce_init_nvram(): Flash WAS reconfigured.\n"); 2527157642Sps 2528157642Sps for (j = 0, flash = &flash_table[0]; j < entry_count; 2529157642Sps j++, flash++) { 2530157642Sps if ((val & FLASH_BACKUP_STRAP_MASK) == 2531157642Sps (flash->config1 & FLASH_BACKUP_STRAP_MASK)) { 2532157642Sps sc->bce_flash_info = flash; 2533157642Sps break; 2534157642Sps } 2535157642Sps } 2536157642Sps } else { 2537157642Sps /* Flash interface not yet reconfigured. */ 2538157642Sps u32 mask; 2539157642Sps 2540179771Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): Flash was NOT reconfigured.\n", 2541179771Sdavidch __FUNCTION__); 2542157642Sps 2543157642Sps if (val & (1 << 23)) 2544157642Sps mask = FLASH_BACKUP_STRAP_MASK; 2545157642Sps else 2546157642Sps mask = FLASH_STRAP_MASK; 2547157642Sps 2548157642Sps /* Look for the matching NVRAM device configuration data. */ 2549157642Sps for (j = 0, flash = &flash_table[0]; j < entry_count; j++, flash++) { 2550157642Sps 2551157642Sps /* Check if the device matches any of the known devices. */ 2552157642Sps if ((val & mask) == (flash->strapping & mask)) { 2553157642Sps /* Found a device match. */ 2554157642Sps sc->bce_flash_info = flash; 2555157642Sps 2556157642Sps /* Request access to the flash interface. */ 2557157642Sps if ((rc = bce_acquire_nvram_lock(sc)) != 0) 2558157642Sps return rc; 2559157642Sps 2560157642Sps /* Reconfigure the flash interface. */ 2561157642Sps bce_enable_nvram_access(sc); 2562157642Sps REG_WR(sc, BCE_NVM_CFG1, flash->config1); 2563157642Sps REG_WR(sc, BCE_NVM_CFG2, flash->config2); 2564157642Sps REG_WR(sc, BCE_NVM_CFG3, flash->config3); 2565157642Sps REG_WR(sc, BCE_NVM_WRITE1, flash->write1); 2566157642Sps bce_disable_nvram_access(sc); 2567157642Sps bce_release_nvram_lock(sc); 2568157642Sps 2569157642Sps break; 2570157642Sps } 2571157642Sps } 2572157642Sps } 2573157642Sps 2574157642Sps /* Check if a matching device was found. */ 2575157642Sps if (j == entry_count) { 2576157642Sps sc->bce_flash_info = NULL; 2577179771Sdavidch BCE_PRINTF("%s(%d): Unknown Flash NVRAM found!\n", 2578207411Sdavidch __FILE__, __LINE__); 2579210257Syongari DBEXIT(BCE_VERBOSE_NVRAM); 2580210257Syongari return (ENODEV); 2581157642Sps } 2582157642Sps 2583179771Sdavidchbce_init_nvram_get_flash_size: 2584157642Sps /* Write the flash config data to the shared memory interface. */ 2585194781Sdavidch val = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG2); 2586157642Sps val &= BCE_SHARED_HW_CFG2_NVM_SIZE_MASK; 2587157642Sps if (val) 2588157642Sps sc->bce_flash_size = val; 2589157642Sps else 2590157642Sps sc->bce_flash_size = sc->bce_flash_info->total_size; 2591157642Sps 2592179771Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): Found %s, size = 0x%08X\n", 2593207411Sdavidch __FUNCTION__, sc->bce_flash_info->name, 2594207411Sdavidch sc->bce_flash_info->total_size); 2595157642Sps 2596179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2597157642Sps return rc; 2598157642Sps} 2599157642Sps 2600157642Sps 2601157642Sps/****************************************************************************/ 2602157642Sps/* Read an arbitrary range of data from NVRAM. */ 2603157642Sps/* */ 2604157642Sps/* Prepares the NVRAM interface for access and reads the requested data */ 2605157642Sps/* into the supplied buffer. */ 2606157642Sps/* */ 2607157642Sps/* Returns: */ 2608157642Sps/* 0 on success and the data read, positive value on failure. */ 2609157642Sps/****************************************************************************/ 2610157642Spsstatic int 2611157642Spsbce_nvram_read(struct bce_softc *sc, u32 offset, u8 *ret_buf, 2612157642Sps int buf_size) 2613157642Sps{ 2614157642Sps int rc = 0; 2615157642Sps u32 cmd_flags, offset32, len32, extra; 2616157642Sps 2617179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2618179771Sdavidch 2619157642Sps if (buf_size == 0) 2620179771Sdavidch goto bce_nvram_read_exit; 2621157642Sps 2622157642Sps /* Request access to the flash interface. */ 2623157642Sps if ((rc = bce_acquire_nvram_lock(sc)) != 0) 2624179771Sdavidch goto bce_nvram_read_exit; 2625157642Sps 2626157642Sps /* Enable access to flash interface */ 2627157642Sps bce_enable_nvram_access(sc); 2628157642Sps 2629157642Sps len32 = buf_size; 2630157642Sps offset32 = offset; 2631157642Sps extra = 0; 2632157642Sps 2633157642Sps cmd_flags = 0; 2634157642Sps 2635157642Sps if (offset32 & 3) { 2636157642Sps u8 buf[4]; 2637157642Sps u32 pre_len; 2638157642Sps 2639157642Sps offset32 &= ~3; 2640157642Sps pre_len = 4 - (offset & 3); 2641157642Sps 2642157642Sps if (pre_len >= len32) { 2643157642Sps pre_len = len32; 2644157642Sps cmd_flags = BCE_NVM_COMMAND_FIRST | BCE_NVM_COMMAND_LAST; 2645157642Sps } 2646157642Sps else { 2647157642Sps cmd_flags = BCE_NVM_COMMAND_FIRST; 2648157642Sps } 2649157642Sps 2650157642Sps rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags); 2651157642Sps 2652157642Sps if (rc) 2653157642Sps return rc; 2654157642Sps 2655157642Sps memcpy(ret_buf, buf + (offset & 3), pre_len); 2656157642Sps 2657157642Sps offset32 += 4; 2658157642Sps ret_buf += pre_len; 2659157642Sps len32 -= pre_len; 2660157642Sps } 2661157642Sps 2662157642Sps if (len32 & 3) { 2663157642Sps extra = 4 - (len32 & 3); 2664157642Sps len32 = (len32 + 4) & ~3; 2665157642Sps } 2666157642Sps 2667157642Sps if (len32 == 4) { 2668157642Sps u8 buf[4]; 2669157642Sps 2670157642Sps if (cmd_flags) 2671157642Sps cmd_flags = BCE_NVM_COMMAND_LAST; 2672157642Sps else 2673157642Sps cmd_flags = BCE_NVM_COMMAND_FIRST | 2674157642Sps BCE_NVM_COMMAND_LAST; 2675157642Sps 2676157642Sps rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags); 2677157642Sps 2678157642Sps memcpy(ret_buf, buf, 4 - extra); 2679157642Sps } 2680157642Sps else if (len32 > 0) { 2681157642Sps u8 buf[4]; 2682157642Sps 2683157642Sps /* Read the first word. */ 2684157642Sps if (cmd_flags) 2685157642Sps cmd_flags = 0; 2686157642Sps else 2687157642Sps cmd_flags = BCE_NVM_COMMAND_FIRST; 2688157642Sps 2689157642Sps rc = bce_nvram_read_dword(sc, offset32, ret_buf, cmd_flags); 2690157642Sps 2691157642Sps /* Advance to the next dword. */ 2692157642Sps offset32 += 4; 2693157642Sps ret_buf += 4; 2694157642Sps len32 -= 4; 2695157642Sps 2696157642Sps while (len32 > 4 && rc == 0) { 2697157642Sps rc = bce_nvram_read_dword(sc, offset32, ret_buf, 0); 2698157642Sps 2699157642Sps /* Advance to the next dword. */ 2700157642Sps offset32 += 4; 2701157642Sps ret_buf += 4; 2702157642Sps len32 -= 4; 2703157642Sps } 2704157642Sps 2705157642Sps if (rc) 2706179771Sdavidch goto bce_nvram_read_locked_exit; 2707157642Sps 2708157642Sps cmd_flags = BCE_NVM_COMMAND_LAST; 2709157642Sps rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags); 2710157642Sps 2711157642Sps memcpy(ret_buf, buf, 4 - extra); 2712157642Sps } 2713157642Sps 2714179771Sdavidchbce_nvram_read_locked_exit: 2715157642Sps /* Disable access to flash interface and release the lock. */ 2716157642Sps bce_disable_nvram_access(sc); 2717157642Sps bce_release_nvram_lock(sc); 2718157642Sps 2719179771Sdavidchbce_nvram_read_exit: 2720179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2721157642Sps return rc; 2722157642Sps} 2723157642Sps 2724157642Sps 2725157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT 2726157642Sps/****************************************************************************/ 2727157642Sps/* Write an arbitrary range of data from NVRAM. */ 2728157642Sps/* */ 2729157642Sps/* Prepares the NVRAM interface for write access and writes the requested */ 2730157642Sps/* data from the supplied buffer. The caller is responsible for */ 2731157642Sps/* calculating any appropriate CRCs. */ 2732157642Sps/* */ 2733157642Sps/* Returns: */ 2734157642Sps/* 0 on success, positive value on failure. */ 2735157642Sps/****************************************************************************/ 2736157642Spsstatic int 2737157642Spsbce_nvram_write(struct bce_softc *sc, u32 offset, u8 *data_buf, 2738157642Sps int buf_size) 2739157642Sps{ 2740157642Sps u32 written, offset32, len32; 2741157642Sps u8 *buf, start[4], end[4]; 2742157642Sps int rc = 0; 2743157642Sps int align_start, align_end; 2744157642Sps 2745179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM); 2746179771Sdavidch 2747157642Sps buf = data_buf; 2748157642Sps offset32 = offset; 2749157642Sps len32 = buf_size; 2750157642Sps align_start = align_end = 0; 2751157642Sps 2752157642Sps if ((align_start = (offset32 & 3))) { 2753157642Sps offset32 &= ~3; 2754157642Sps len32 += align_start; 2755157642Sps if ((rc = bce_nvram_read(sc, offset32, start, 4))) 2756179771Sdavidch goto bce_nvram_write_exit; 2757157642Sps } 2758157642Sps 2759157642Sps if (len32 & 3) { 2760157642Sps if ((len32 > 4) || !align_start) { 2761157642Sps align_end = 4 - (len32 & 3); 2762157642Sps len32 += align_end; 2763157642Sps if ((rc = bce_nvram_read(sc, offset32 + len32 - 4, 2764157642Sps end, 4))) { 2765179771Sdavidch goto bce_nvram_write_exit; 2766157642Sps } 2767157642Sps } 2768157642Sps } 2769157642Sps 2770157642Sps if (align_start || align_end) { 2771157642Sps buf = malloc(len32, M_DEVBUF, M_NOWAIT); 2772179771Sdavidch if (buf == 0) { 2773179771Sdavidch rc = ENOMEM; 2774179771Sdavidch goto bce_nvram_write_exit; 2775179771Sdavidch } 2776179771Sdavidch 2777157642Sps if (align_start) { 2778157642Sps memcpy(buf, start, 4); 2779157642Sps } 2780179771Sdavidch 2781157642Sps if (align_end) { 2782157642Sps memcpy(buf + len32 - 4, end, 4); 2783157642Sps } 2784157642Sps memcpy(buf + align_start, data_buf, buf_size); 2785157642Sps } 2786157642Sps 2787157642Sps written = 0; 2788157642Sps while ((written < len32) && (rc == 0)) { 2789157642Sps u32 page_start, page_end, data_start, data_end; 2790157642Sps u32 addr, cmd_flags; 2791157642Sps int i; 2792157642Sps u8 flash_buffer[264]; 2793157642Sps 2794157642Sps /* Find the page_start addr */ 2795157642Sps page_start = offset32 + written; 2796157642Sps page_start -= (page_start % sc->bce_flash_info->page_size); 2797157642Sps /* Find the page_end addr */ 2798157642Sps page_end = page_start + sc->bce_flash_info->page_size; 2799157642Sps /* Find the data_start addr */ 2800157642Sps data_start = (written == 0) ? offset32 : page_start; 2801157642Sps /* Find the data_end addr */ 2802157642Sps data_end = (page_end > offset32 + len32) ? 2803157642Sps (offset32 + len32) : page_end; 2804157642Sps 2805157642Sps /* Request access to the flash interface. */ 2806157642Sps if ((rc = bce_acquire_nvram_lock(sc)) != 0) 2807179771Sdavidch goto bce_nvram_write_exit; 2808157642Sps 2809157642Sps /* Enable access to flash interface */ 2810157642Sps bce_enable_nvram_access(sc); 2811157642Sps 2812157642Sps cmd_flags = BCE_NVM_COMMAND_FIRST; 2813179771Sdavidch if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) { 2814157642Sps int j; 2815157642Sps 2816157642Sps /* Read the whole page into the buffer 2817157642Sps * (non-buffer flash only) */ 2818157642Sps for (j = 0; j < sc->bce_flash_info->page_size; j += 4) { 2819157642Sps if (j == (sc->bce_flash_info->page_size - 4)) { 2820157642Sps cmd_flags |= BCE_NVM_COMMAND_LAST; 2821157642Sps } 2822157642Sps rc = bce_nvram_read_dword(sc, 2823157642Sps page_start + j, 2824157642Sps &flash_buffer[j], 2825157642Sps cmd_flags); 2826157642Sps 2827157642Sps if (rc) 2828179771Sdavidch goto bce_nvram_write_locked_exit; 2829157642Sps 2830157642Sps cmd_flags = 0; 2831157642Sps } 2832157642Sps } 2833157642Sps 2834157642Sps /* Enable writes to flash interface (unlock write-protect) */ 2835157642Sps if ((rc = bce_enable_nvram_write(sc)) != 0) 2836179771Sdavidch goto bce_nvram_write_locked_exit; 2837157642Sps 2838157642Sps /* Erase the page */ 2839157642Sps if ((rc = bce_nvram_erase_page(sc, page_start)) != 0) 2840179771Sdavidch goto bce_nvram_write_locked_exit; 2841157642Sps 2842157642Sps /* Re-enable the write again for the actual write */ 2843157642Sps bce_enable_nvram_write(sc); 2844157642Sps 2845157642Sps /* Loop to write back the buffer data from page_start to 2846157642Sps * data_start */ 2847157642Sps i = 0; 2848179771Sdavidch if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) { 2849157642Sps for (addr = page_start; addr < data_start; 2850157642Sps addr += 4, i += 4) { 2851157642Sps 2852157642Sps rc = bce_nvram_write_dword(sc, addr, 2853157642Sps &flash_buffer[i], cmd_flags); 2854157642Sps 2855157642Sps if (rc != 0) 2856179771Sdavidch goto bce_nvram_write_locked_exit; 2857157642Sps 2858157642Sps cmd_flags = 0; 2859157642Sps } 2860157642Sps } 2861157642Sps 2862157642Sps /* Loop to write the new data from data_start to data_end */ 2863157642Sps for (addr = data_start; addr < data_end; addr += 4, i++) { 2864157642Sps if ((addr == page_end - 4) || 2865179771Sdavidch ((sc->bce_flash_info->flags & BCE_NV_BUFFERED) && 2866179771Sdavidch (addr == data_end - 4))) { 2867157642Sps 2868157642Sps cmd_flags |= BCE_NVM_COMMAND_LAST; 2869157642Sps } 2870157642Sps rc = bce_nvram_write_dword(sc, addr, buf, 2871157642Sps cmd_flags); 2872157642Sps 2873157642Sps if (rc != 0) 2874179771Sdavidch goto bce_nvram_write_locked_exit; 2875157642Sps 2876157642Sps cmd_flags = 0; 2877157642Sps buf += 4; 2878157642Sps } 2879157642Sps 2880157642Sps /* Loop to write back the buffer data from data_end 2881157642Sps * to page_end */ 2882179771Sdavidch if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) { 2883157642Sps for (addr = data_end; addr < page_end; 2884157642Sps addr += 4, i += 4) { 2885157642Sps 2886157642Sps if (addr == page_end-4) { 2887157642Sps cmd_flags = BCE_NVM_COMMAND_LAST; 2888157642Sps } 2889157642Sps rc = bce_nvram_write_dword(sc, addr, 2890157642Sps &flash_buffer[i], cmd_flags); 2891157642Sps 2892157642Sps if (rc != 0) 2893179771Sdavidch goto bce_nvram_write_locked_exit; 2894157642Sps 2895157642Sps cmd_flags = 0; 2896157642Sps } 2897157642Sps } 2898157642Sps 2899157642Sps /* Disable writes to flash interface (lock write-protect) */ 2900157642Sps bce_disable_nvram_write(sc); 2901157642Sps 2902157642Sps /* Disable access to flash interface */ 2903157642Sps bce_disable_nvram_access(sc); 2904157642Sps bce_release_nvram_lock(sc); 2905157642Sps 2906157642Sps /* Increment written */ 2907157642Sps written += data_end - data_start; 2908157642Sps } 2909157642Sps 2910179771Sdavidch goto bce_nvram_write_exit; 2911179771Sdavidch 2912179771Sdavidchbce_nvram_write_locked_exit: 2913218527Sdavidch bce_disable_nvram_write(sc); 2914218527Sdavidch bce_disable_nvram_access(sc); 2915218527Sdavidch bce_release_nvram_lock(sc); 2916179771Sdavidch 2917179771Sdavidchbce_nvram_write_exit: 2918157642Sps if (align_start || align_end) 2919157642Sps free(buf, M_DEVBUF); 2920157642Sps 2921179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM); 2922179771Sdavidch return (rc); 2923157642Sps} 2924157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */ 2925157642Sps 2926157642Sps 2927157642Sps/****************************************************************************/ 2928157642Sps/* Verifies that NVRAM is accessible and contains valid data. */ 2929157642Sps/* */ 2930157642Sps/* Reads the configuration data from NVRAM and verifies that the CRC is */ 2931157642Sps/* correct. */ 2932157642Sps/* */ 2933157642Sps/* Returns: */ 2934157642Sps/* 0 on success, positive value on failure. */ 2935157642Sps/****************************************************************************/ 2936157642Spsstatic int 2937157642Spsbce_nvram_test(struct bce_softc *sc) 2938157642Sps{ 2939157642Sps u32 buf[BCE_NVRAM_SIZE / 4]; 2940157642Sps u8 *data = (u8 *) buf; 2941157642Sps int rc = 0; 2942157642Sps u32 magic, csum; 2943157642Sps 2944179771Sdavidch DBENTER(BCE_VERBOSE_NVRAM | BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET); 2945157642Sps 2946157642Sps /* 2947157642Sps * Check that the device NVRAM is valid by reading 2948157642Sps * the magic value at offset 0. 2949157642Sps */ 2950179771Sdavidch if ((rc = bce_nvram_read(sc, 0, data, 4)) != 0) { 2951207411Sdavidch BCE_PRINTF("%s(%d): Unable to read NVRAM!\n", 2952207411Sdavidch __FILE__, __LINE__); 2953179771Sdavidch goto bce_nvram_test_exit; 2954179771Sdavidch } 2955157642Sps 2956179771Sdavidch /* 2957179771Sdavidch * Verify that offset 0 of the NVRAM contains 2958179771Sdavidch * a valid magic number. 2959179771Sdavidch */ 2960218527Sdavidch magic = bce_be32toh(buf[0]); 2961157642Sps if (magic != BCE_NVRAM_MAGIC) { 2962157642Sps rc = ENODEV; 2963207411Sdavidch BCE_PRINTF("%s(%d): Invalid NVRAM magic value! " 2964207411Sdavidch "Expected: 0x%08X, Found: 0x%08X\n", 2965207411Sdavidch __FILE__, __LINE__, BCE_NVRAM_MAGIC, magic); 2966179771Sdavidch goto bce_nvram_test_exit; 2967157642Sps } 2968157642Sps 2969157642Sps /* 2970157642Sps * Verify that the device NVRAM includes valid 2971157642Sps * configuration data. 2972157642Sps */ 2973179771Sdavidch if ((rc = bce_nvram_read(sc, 0x100, data, BCE_NVRAM_SIZE)) != 0) { 2974207411Sdavidch BCE_PRINTF("%s(%d): Unable to read manufacturing " 2975207411Sdavidch "Information from NVRAM!\n", __FILE__, __LINE__); 2976179771Sdavidch goto bce_nvram_test_exit; 2977179771Sdavidch } 2978157642Sps 2979157642Sps csum = ether_crc32_le(data, 0x100); 2980157642Sps if (csum != BCE_CRC32_RESIDUAL) { 2981157642Sps rc = ENODEV; 2982207411Sdavidch BCE_PRINTF("%s(%d): Invalid manufacturing information " 2983207411Sdavidch "NVRAM CRC! Expected: 0x%08X, Found: 0x%08X\n", 2984207411Sdavidch __FILE__, __LINE__, BCE_CRC32_RESIDUAL, csum); 2985179771Sdavidch goto bce_nvram_test_exit; 2986157642Sps } 2987157642Sps 2988157642Sps csum = ether_crc32_le(data + 0x100, 0x100); 2989157642Sps if (csum != BCE_CRC32_RESIDUAL) { 2990179771Sdavidch rc = ENODEV; 2991207411Sdavidch BCE_PRINTF("%s(%d): Invalid feature configuration " 2992207411Sdavidch "information NVRAM CRC! Expected: 0x%08X, " 2993207411Sdavidch "Found: 08%08X\n", __FILE__, __LINE__, 2994207411Sdavidch BCE_CRC32_RESIDUAL, csum); 2995157642Sps } 2996157642Sps 2997179771Sdavidchbce_nvram_test_exit: 2998179771Sdavidch DBEXIT(BCE_VERBOSE_NVRAM | BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET); 2999157642Sps return rc; 3000157642Sps} 3001157642Sps 3002157642Sps 3003157642Sps/****************************************************************************/ 3004218423Sdavidch/* Calculates the size of the buffers to allocate based on the MTU. */ 3005218423Sdavidch/* */ 3006218423Sdavidch/* Returns: */ 3007218423Sdavidch/* Nothing. */ 3008218423Sdavidch/****************************************************************************/ 3009218423Sdavidchstatic void 3010218423Sdavidchbce_get_rx_buffer_sizes(struct bce_softc *sc, int mtu) 3011218423Sdavidch{ 3012218423Sdavidch DBENTER(BCE_VERBOSE_LOAD); 3013218423Sdavidch 3014218423Sdavidch /* Use a single allocation type when header splitting enabled. */ 3015218423Sdavidch if (bce_hdr_split == TRUE) { 3016218423Sdavidch sc->rx_bd_mbuf_alloc_size = MHLEN; 3017218423Sdavidch /* Make sure offset is 16 byte aligned for hardware. */ 3018218423Sdavidch sc->rx_bd_mbuf_align_pad = 3019218423Sdavidch roundup2((MSIZE - MHLEN), 16) - (MSIZE - MHLEN); 3020218423Sdavidch sc->rx_bd_mbuf_data_len = sc->rx_bd_mbuf_alloc_size - 3021218423Sdavidch sc->rx_bd_mbuf_align_pad; 3022218423Sdavidch } else { 3023218423Sdavidch if ((mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + 3024218423Sdavidch ETHER_CRC_LEN) > MCLBYTES) { 3025218423Sdavidch /* Setup for jumbo RX buffer allocations. */ 3026218423Sdavidch sc->rx_bd_mbuf_alloc_size = MJUM9BYTES; 3027218423Sdavidch sc->rx_bd_mbuf_align_pad = 3028218423Sdavidch roundup2(MJUM9BYTES, 16) - MJUM9BYTES; 3029218423Sdavidch sc->rx_bd_mbuf_data_len = 3030218423Sdavidch sc->rx_bd_mbuf_alloc_size - 3031218423Sdavidch sc->rx_bd_mbuf_align_pad; 3032218423Sdavidch } else { 3033218423Sdavidch /* Setup for standard RX buffer allocations. */ 3034218423Sdavidch sc->rx_bd_mbuf_alloc_size = MCLBYTES; 3035218423Sdavidch sc->rx_bd_mbuf_align_pad = 3036218423Sdavidch roundup2(MCLBYTES, 16) - MCLBYTES; 3037218423Sdavidch sc->rx_bd_mbuf_data_len = 3038218423Sdavidch sc->rx_bd_mbuf_alloc_size - 3039218423Sdavidch sc->rx_bd_mbuf_align_pad; 3040218423Sdavidch } 3041218423Sdavidch } 3042218423Sdavidch 3043218423Sdavidch// DBPRINT(sc, BCE_INFO_LOAD, 3044218423Sdavidch DBPRINT(sc, BCE_WARN, 3045218423Sdavidch "%s(): rx_bd_mbuf_alloc_size = %d, rx_bd_mbuf_data_len = %d, " 3046218423Sdavidch "rx_bd_mbuf_align_pad = %d\n", __FUNCTION__, 3047218423Sdavidch sc->rx_bd_mbuf_alloc_size, sc->rx_bd_mbuf_data_len, 3048218423Sdavidch sc->rx_bd_mbuf_align_pad); 3049218423Sdavidch 3050218423Sdavidch DBEXIT(BCE_VERBOSE_LOAD); 3051218423Sdavidch} 3052218423Sdavidch 3053218423Sdavidch/****************************************************************************/ 3054179771Sdavidch/* Identifies the current media type of the controller and sets the PHY */ 3055179771Sdavidch/* address. */ 3056179771Sdavidch/* */ 3057179771Sdavidch/* Returns: */ 3058179771Sdavidch/* Nothing. */ 3059179771Sdavidch/****************************************************************************/ 3060179771Sdavidchstatic void 3061179771Sdavidchbce_get_media(struct bce_softc *sc) 3062179771Sdavidch{ 3063179771Sdavidch u32 val; 3064179771Sdavidch 3065207411Sdavidch DBENTER(BCE_VERBOSE_PHY); 3066179771Sdavidch 3067182293Sdavidch /* Assume PHY address for copper controllers. */ 3068179771Sdavidch sc->bce_phy_addr = 1; 3069179771Sdavidch 3070179771Sdavidch if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 3071179771Sdavidch u32 val = REG_RD(sc, BCE_MISC_DUAL_MEDIA_CTRL); 3072179771Sdavidch u32 bond_id = val & BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID; 3073179771Sdavidch u32 strap; 3074179771Sdavidch 3075179771Sdavidch /* 3076179771Sdavidch * The BCM5709S is software configurable 3077179771Sdavidch * for Copper or SerDes operation. 3078179771Sdavidch */ 3079179771Sdavidch if (bond_id == BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) { 3080206268Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "5709 bonded " 3081206268Sdavidch "for copper.\n"); 3082179771Sdavidch goto bce_get_media_exit; 3083179771Sdavidch } else if (bond_id == BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) { 3084206268Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "5709 bonded " 3085206268Sdavidch "for dual media.\n"); 3086179771Sdavidch sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG; 3087179771Sdavidch goto bce_get_media_exit; 3088179771Sdavidch } 3089179771Sdavidch 3090179771Sdavidch if (val & BCE_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE) 3091207411Sdavidch strap = (val & 3092206268Sdavidch BCE_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21; 3093179771Sdavidch else 3094207411Sdavidch strap = (val & 3095206268Sdavidch BCE_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8; 3096179771Sdavidch 3097179771Sdavidch if (pci_get_function(sc->bce_dev) == 0) { 3098179771Sdavidch switch (strap) { 3099179771Sdavidch case 0x4: 3100179771Sdavidch case 0x5: 3101179771Sdavidch case 0x6: 3102182293Sdavidch DBPRINT(sc, BCE_INFO_LOAD, 3103206268Sdavidch "BCM5709 s/w configured for SerDes.\n"); 3104179771Sdavidch sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG; 3105206268Sdavidch break; 3106179771Sdavidch default: 3107182293Sdavidch DBPRINT(sc, BCE_INFO_LOAD, 3108206268Sdavidch "BCM5709 s/w configured for Copper.\n"); 3109206268Sdavidch break; 3110179771Sdavidch } 3111179771Sdavidch } else { 3112179771Sdavidch switch (strap) { 3113179771Sdavidch case 0x1: 3114179771Sdavidch case 0x2: 3115179771Sdavidch case 0x4: 3116182293Sdavidch DBPRINT(sc, BCE_INFO_LOAD, 3117206268Sdavidch "BCM5709 s/w configured for SerDes.\n"); 3118179771Sdavidch sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG; 3119206268Sdavidch break; 3120179771Sdavidch default: 3121182293Sdavidch DBPRINT(sc, BCE_INFO_LOAD, 3122206268Sdavidch "BCM5709 s/w configured for Copper.\n"); 3123206268Sdavidch break; 3124179771Sdavidch } 3125179771Sdavidch } 3126179771Sdavidch 3127179771Sdavidch } else if (BCE_CHIP_BOND_ID(sc) & BCE_CHIP_BOND_ID_SERDES_BIT) 3128179771Sdavidch sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG; 3129179771Sdavidch 3130185082Sdelphij if (sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) { 3131205300Sdavidch 3132179771Sdavidch sc->bce_flags |= BCE_NO_WOL_FLAG; 3133205300Sdavidch 3134206268Sdavidch if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) 3135206268Sdavidch sc->bce_phy_flags |= BCE_PHY_IEEE_CLAUSE_45_FLAG; 3136206268Sdavidch 3137206268Sdavidch if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5706) { 3138206268Sdavidch /* 5708S/09S/16S use a separate PHY for SerDes. */ 3139179771Sdavidch sc->bce_phy_addr = 2; 3140205300Sdavidch 3141194781Sdavidch val = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG); 3142179771Sdavidch if (val & BCE_SHARED_HW_CFG_PHY_2_5G) { 3143207411Sdavidch sc->bce_phy_flags |= 3144206268Sdavidch BCE_PHY_2_5G_CAPABLE_FLAG; 3145206268Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "Found 2.5Gb " 3146206268Sdavidch "capable adapter\n"); 3147179771Sdavidch } 3148206268Sdavidch } 3149179771Sdavidch } else if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) || 3150206268Sdavidch (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708)) 3151179771Sdavidch sc->bce_phy_flags |= BCE_PHY_CRC_FIX_FLAG; 3152179771Sdavidch 3153179771Sdavidchbce_get_media_exit: 3154182293Sdavidch DBPRINT(sc, (BCE_INFO_LOAD | BCE_INFO_PHY), 3155179771Sdavidch "Using PHY address %d.\n", sc->bce_phy_addr); 3156182293Sdavidch 3157207411Sdavidch DBEXIT(BCE_VERBOSE_PHY); 3158179771Sdavidch} 3159179771Sdavidch 3160179771Sdavidch 3161179771Sdavidch/****************************************************************************/ 3162205300Sdavidch/* Performs PHY initialization required before MII drivers access the */ 3163205300Sdavidch/* device. */ 3164205300Sdavidch/* */ 3165205300Sdavidch/* Returns: */ 3166205300Sdavidch/* Nothing. */ 3167205300Sdavidch/****************************************************************************/ 3168205300Sdavidchstatic void 3169205300Sdavidchbce_init_media(struct bce_softc *sc) 3170205300Sdavidch{ 3171235151Syongari if ((sc->bce_phy_flags & (BCE_PHY_IEEE_CLAUSE_45_FLAG | 3172235151Syongari BCE_PHY_REMOTE_CAP_FLAG)) == BCE_PHY_IEEE_CLAUSE_45_FLAG) { 3173205300Sdavidch /* 3174205300Sdavidch * Configure 5709S/5716S PHYs to use traditional IEEE 3175205300Sdavidch * Clause 22 method. Otherwise we have no way to attach 3176205300Sdavidch * the PHY in mii(4) layer. PHY specific configuration 3177205300Sdavidch * is done in mii layer. 3178205300Sdavidch */ 3179205300Sdavidch 3180206268Sdavidch /* Select auto-negotiation MMD of the PHY. */ 3181206268Sdavidch bce_miibus_write_reg(sc->bce_dev, sc->bce_phy_addr, 3182205300Sdavidch BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_ADDR_EXT); 3183205300Sdavidch bce_miibus_write_reg(sc->bce_dev, sc->bce_phy_addr, 3184205300Sdavidch BRGPHY_ADDR_EXT, BRGPHY_ADDR_EXT_AN_MMD); 3185205300Sdavidch 3186206268Sdavidch /* Set IEEE0 block of AN MMD (assumed in brgphy(4) code). */ 3187205300Sdavidch bce_miibus_write_reg(sc->bce_dev, sc->bce_phy_addr, 3188205300Sdavidch BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 3189205300Sdavidch } 3190205300Sdavidch} 3191205300Sdavidch 3192205300Sdavidch 3193205300Sdavidch/****************************************************************************/ 3194157642Sps/* Free any DMA memory owned by the driver. */ 3195157642Sps/* */ 3196157642Sps/* Scans through each data structre that requires DMA memory and frees */ 3197157642Sps/* the memory if allocated. */ 3198157642Sps/* */ 3199157642Sps/* Returns: */ 3200157642Sps/* Nothing. */ 3201157642Sps/****************************************************************************/ 3202157642Spsstatic void 3203157642Spsbce_dma_free(struct bce_softc *sc) 3204157642Sps{ 3205157642Sps int i; 3206157642Sps 3207179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_UNLOAD | BCE_VERBOSE_CTX); 3208157642Sps 3209179771Sdavidch /* Free, unmap, and destroy the status block. */ 3210176448Sdavidch if (sc->status_block != NULL) { 3211157642Sps bus_dmamem_free( 3212206268Sdavidch sc->status_tag, 3213157642Sps sc->status_block, 3214157642Sps sc->status_map); 3215176448Sdavidch sc->status_block = NULL; 3216176448Sdavidch } 3217157642Sps 3218157642Sps if (sc->status_map != NULL) { 3219157642Sps bus_dmamap_unload( 3220206268Sdavidch sc->status_tag, 3221157642Sps sc->status_map); 3222157642Sps bus_dmamap_destroy(sc->status_tag, 3223157642Sps sc->status_map); 3224176448Sdavidch sc->status_map = NULL; 3225157642Sps } 3226157642Sps 3227176448Sdavidch if (sc->status_tag != NULL) { 3228157642Sps bus_dma_tag_destroy(sc->status_tag); 3229176448Sdavidch sc->status_tag = NULL; 3230176448Sdavidch } 3231157642Sps 3232157642Sps 3233179771Sdavidch /* Free, unmap, and destroy the statistics block. */ 3234176448Sdavidch if (sc->stats_block != NULL) { 3235157642Sps bus_dmamem_free( 3236206268Sdavidch sc->stats_tag, 3237157642Sps sc->stats_block, 3238157642Sps sc->stats_map); 3239176448Sdavidch sc->stats_block = NULL; 3240176448Sdavidch } 3241157642Sps 3242157642Sps if (sc->stats_map != NULL) { 3243157642Sps bus_dmamap_unload( 3244206268Sdavidch sc->stats_tag, 3245157642Sps sc->stats_map); 3246157642Sps bus_dmamap_destroy(sc->stats_tag, 3247157642Sps sc->stats_map); 3248176448Sdavidch sc->stats_map = NULL; 3249157642Sps } 3250157642Sps 3251176448Sdavidch if (sc->stats_tag != NULL) { 3252157642Sps bus_dma_tag_destroy(sc->stats_tag); 3253176448Sdavidch sc->stats_tag = NULL; 3254176448Sdavidch } 3255157642Sps 3256157642Sps 3257179771Sdavidch /* Free, unmap and destroy all context memory pages. */ 3258226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 3259179771Sdavidch for (i = 0; i < sc->ctx_pages; i++ ) { 3260179771Sdavidch if (sc->ctx_block[i] != NULL) { 3261179771Sdavidch bus_dmamem_free( 3262206268Sdavidch sc->ctx_tag, 3263179771Sdavidch sc->ctx_block[i], 3264179771Sdavidch sc->ctx_map[i]); 3265179771Sdavidch sc->ctx_block[i] = NULL; 3266179771Sdavidch } 3267179771Sdavidch 3268179771Sdavidch if (sc->ctx_map[i] != NULL) { 3269179771Sdavidch bus_dmamap_unload( 3270206268Sdavidch sc->ctx_tag, 3271206268Sdavidch sc->ctx_map[i]); 3272179771Sdavidch bus_dmamap_destroy( 3273206268Sdavidch sc->ctx_tag, 3274179771Sdavidch sc->ctx_map[i]); 3275179771Sdavidch sc->ctx_map[i] = NULL; 3276179771Sdavidch } 3277179771Sdavidch } 3278179771Sdavidch 3279179771Sdavidch /* Destroy the context memory tag. */ 3280179771Sdavidch if (sc->ctx_tag != NULL) { 3281179771Sdavidch bus_dma_tag_destroy(sc->ctx_tag); 3282179771Sdavidch sc->ctx_tag = NULL; 3283179771Sdavidch } 3284179771Sdavidch } 3285179771Sdavidch 3286179771Sdavidch 3287157642Sps /* Free, unmap and destroy all TX buffer descriptor chain pages. */ 3288218423Sdavidch for (i = 0; i < sc->tx_pages; i++ ) { 3289176448Sdavidch if (sc->tx_bd_chain[i] != NULL) { 3290157642Sps bus_dmamem_free( 3291206268Sdavidch sc->tx_bd_chain_tag, 3292157642Sps sc->tx_bd_chain[i], 3293157642Sps sc->tx_bd_chain_map[i]); 3294176448Sdavidch sc->tx_bd_chain[i] = NULL; 3295176448Sdavidch } 3296157642Sps 3297157642Sps if (sc->tx_bd_chain_map[i] != NULL) { 3298157642Sps bus_dmamap_unload( 3299206268Sdavidch sc->tx_bd_chain_tag, 3300206268Sdavidch sc->tx_bd_chain_map[i]); 3301157642Sps bus_dmamap_destroy( 3302206268Sdavidch sc->tx_bd_chain_tag, 3303157642Sps sc->tx_bd_chain_map[i]); 3304176448Sdavidch sc->tx_bd_chain_map[i] = NULL; 3305157642Sps } 3306157642Sps } 3307157642Sps 3308157642Sps /* Destroy the TX buffer descriptor tag. */ 3309176448Sdavidch if (sc->tx_bd_chain_tag != NULL) { 3310157642Sps bus_dma_tag_destroy(sc->tx_bd_chain_tag); 3311176448Sdavidch sc->tx_bd_chain_tag = NULL; 3312176448Sdavidch } 3313157642Sps 3314157642Sps 3315157642Sps /* Free, unmap and destroy all RX buffer descriptor chain pages. */ 3316218423Sdavidch for (i = 0; i < sc->rx_pages; i++ ) { 3317176448Sdavidch if (sc->rx_bd_chain[i] != NULL) { 3318157642Sps bus_dmamem_free( 3319206268Sdavidch sc->rx_bd_chain_tag, 3320157642Sps sc->rx_bd_chain[i], 3321157642Sps sc->rx_bd_chain_map[i]); 3322176448Sdavidch sc->rx_bd_chain[i] = NULL; 3323176448Sdavidch } 3324157642Sps 3325157642Sps if (sc->rx_bd_chain_map[i] != NULL) { 3326157642Sps bus_dmamap_unload( 3327206268Sdavidch sc->rx_bd_chain_tag, 3328206268Sdavidch sc->rx_bd_chain_map[i]); 3329157642Sps bus_dmamap_destroy( 3330206268Sdavidch sc->rx_bd_chain_tag, 3331157642Sps sc->rx_bd_chain_map[i]); 3332176448Sdavidch sc->rx_bd_chain_map[i] = NULL; 3333157642Sps } 3334157642Sps } 3335157642Sps 3336157642Sps /* Destroy the RX buffer descriptor tag. */ 3337176448Sdavidch if (sc->rx_bd_chain_tag != NULL) { 3338157642Sps bus_dma_tag_destroy(sc->rx_bd_chain_tag); 3339176448Sdavidch sc->rx_bd_chain_tag = NULL; 3340176448Sdavidch } 3341157642Sps 3342157642Sps 3343176448Sdavidch /* Free, unmap and destroy all page buffer descriptor chain pages. */ 3344218423Sdavidch if (bce_hdr_split == TRUE) { 3345218423Sdavidch for (i = 0; i < sc->pg_pages; i++ ) { 3346218423Sdavidch if (sc->pg_bd_chain[i] != NULL) { 3347218423Sdavidch bus_dmamem_free( 3348218423Sdavidch sc->pg_bd_chain_tag, 3349218423Sdavidch sc->pg_bd_chain[i], 3350218423Sdavidch sc->pg_bd_chain_map[i]); 3351218423Sdavidch sc->pg_bd_chain[i] = NULL; 3352218423Sdavidch } 3353218423Sdavidch 3354218423Sdavidch if (sc->pg_bd_chain_map[i] != NULL) { 3355218423Sdavidch bus_dmamap_unload( 3356218423Sdavidch sc->pg_bd_chain_tag, 3357218423Sdavidch sc->pg_bd_chain_map[i]); 3358218423Sdavidch bus_dmamap_destroy( 3359218423Sdavidch sc->pg_bd_chain_tag, 3360218423Sdavidch sc->pg_bd_chain_map[i]); 3361218423Sdavidch sc->pg_bd_chain_map[i] = NULL; 3362218423Sdavidch } 3363176448Sdavidch } 3364176448Sdavidch 3365218423Sdavidch /* Destroy the page buffer descriptor tag. */ 3366218423Sdavidch if (sc->pg_bd_chain_tag != NULL) { 3367218423Sdavidch bus_dma_tag_destroy(sc->pg_bd_chain_tag); 3368218423Sdavidch sc->pg_bd_chain_tag = NULL; 3369176448Sdavidch } 3370176448Sdavidch } 3371176448Sdavidch 3372176448Sdavidch 3373157642Sps /* Unload and destroy the TX mbuf maps. */ 3374218423Sdavidch for (i = 0; i < MAX_TX_BD_AVAIL; i++) { 3375157642Sps if (sc->tx_mbuf_map[i] != NULL) { 3376179771Sdavidch bus_dmamap_unload(sc->tx_mbuf_tag, 3377206268Sdavidch sc->tx_mbuf_map[i]); 3378179771Sdavidch bus_dmamap_destroy(sc->tx_mbuf_tag, 3379206268Sdavidch sc->tx_mbuf_map[i]); 3380176448Sdavidch sc->tx_mbuf_map[i] = NULL; 3381157642Sps } 3382157642Sps } 3383157642Sps 3384157642Sps /* Destroy the TX mbuf tag. */ 3385176448Sdavidch if (sc->tx_mbuf_tag != NULL) { 3386157642Sps bus_dma_tag_destroy(sc->tx_mbuf_tag); 3387176448Sdavidch sc->tx_mbuf_tag = NULL; 3388176448Sdavidch } 3389157642Sps 3390157642Sps /* Unload and destroy the RX mbuf maps. */ 3391218423Sdavidch for (i = 0; i < MAX_RX_BD_AVAIL; i++) { 3392157642Sps if (sc->rx_mbuf_map[i] != NULL) { 3393179771Sdavidch bus_dmamap_unload(sc->rx_mbuf_tag, 3394206268Sdavidch sc->rx_mbuf_map[i]); 3395179771Sdavidch bus_dmamap_destroy(sc->rx_mbuf_tag, 3396206268Sdavidch sc->rx_mbuf_map[i]); 3397176448Sdavidch sc->rx_mbuf_map[i] = NULL; 3398157642Sps } 3399157642Sps } 3400157642Sps 3401157642Sps /* Destroy the RX mbuf tag. */ 3402176448Sdavidch if (sc->rx_mbuf_tag != NULL) { 3403157642Sps bus_dma_tag_destroy(sc->rx_mbuf_tag); 3404176448Sdavidch sc->rx_mbuf_tag = NULL; 3405176448Sdavidch } 3406157642Sps 3407176448Sdavidch /* Unload and destroy the page mbuf maps. */ 3408218423Sdavidch if (bce_hdr_split == TRUE) { 3409218423Sdavidch for (i = 0; i < MAX_PG_BD_AVAIL; i++) { 3410218423Sdavidch if (sc->pg_mbuf_map[i] != NULL) { 3411218423Sdavidch bus_dmamap_unload(sc->pg_mbuf_tag, 3412218423Sdavidch sc->pg_mbuf_map[i]); 3413218423Sdavidch bus_dmamap_destroy(sc->pg_mbuf_tag, 3414218423Sdavidch sc->pg_mbuf_map[i]); 3415218423Sdavidch sc->pg_mbuf_map[i] = NULL; 3416218423Sdavidch } 3417176448Sdavidch } 3418157642Sps 3419218423Sdavidch /* Destroy the page mbuf tag. */ 3420218423Sdavidch if (sc->pg_mbuf_tag != NULL) { 3421218423Sdavidch bus_dma_tag_destroy(sc->pg_mbuf_tag); 3422218423Sdavidch sc->pg_mbuf_tag = NULL; 3423218423Sdavidch } 3424176448Sdavidch } 3425176448Sdavidch 3426157642Sps /* Destroy the parent tag */ 3427176448Sdavidch if (sc->parent_tag != NULL) { 3428157642Sps bus_dma_tag_destroy(sc->parent_tag); 3429176448Sdavidch sc->parent_tag = NULL; 3430176448Sdavidch } 3431157642Sps 3432179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_UNLOAD | BCE_VERBOSE_CTX); 3433157642Sps} 3434157642Sps 3435157642Sps 3436157642Sps/****************************************************************************/ 3437157642Sps/* Get DMA memory from the OS. */ 3438157642Sps/* */ 3439157642Sps/* Validates that the OS has provided DMA buffers in response to a */ 3440157642Sps/* bus_dmamap_load() call and saves the physical address of those buffers. */ 3441157642Sps/* When the callback is used the OS will return 0 for the mapping function */ 3442157642Sps/* (bus_dmamap_load()) so we use the value of map_arg->maxsegs to pass any */ 3443157642Sps/* failures back to the caller. */ 3444157642Sps/* */ 3445157642Sps/* Returns: */ 3446157642Sps/* Nothing. */ 3447157642Sps/****************************************************************************/ 3448157642Spsstatic void 3449157642Spsbce_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3450157642Sps{ 3451163393Sscottl bus_addr_t *busaddr = arg; 3452157642Sps 3453210267Syongari KASSERT(nseg == 1, ("%s(): Too many segments returned (%d)!", 3454210267Syongari __FUNCTION__, nseg)); 3455157642Sps /* Simulate a mapping failure. */ 3456189325Sdavidch DBRUNIF(DB_RANDOMTRUE(dma_map_addr_failed_sim_control), 3457207411Sdavidch error = ENOMEM); 3458179771Sdavidch 3459207411Sdavidch /* ToDo: How to increment debug sim_count variable here? */ 3460207411Sdavidch 3461157642Sps /* Check for an error and signal the caller that an error occurred. */ 3462157642Sps if (error) { 3463163393Sscottl *busaddr = 0; 3464189325Sdavidch } else { 3465189325Sdavidch *busaddr = segs->ds_addr; 3466157642Sps } 3467157642Sps} 3468157642Sps 3469157642Sps 3470157642Sps/****************************************************************************/ 3471157642Sps/* Allocate any DMA memory needed by the driver. */ 3472157642Sps/* */ 3473157642Sps/* Allocates DMA memory needed for the various global structures needed by */ 3474182293Sdavidch/* hardware. */ 3475157642Sps/* */ 3476182293Sdavidch/* Memory alignment requirements: */ 3477182293Sdavidch/* +-----------------+----------+----------+----------+----------+ */ 3478182293Sdavidch/* | | 5706 | 5708 | 5709 | 5716 | */ 3479182293Sdavidch/* +-----------------+----------+----------+----------+----------+ */ 3480182293Sdavidch/* |Status Block | 8 bytes | 8 bytes | 16 bytes | 16 bytes | */ 3481182293Sdavidch/* |Statistics Block | 8 bytes | 8 bytes | 16 bytes | 16 bytes | */ 3482182293Sdavidch/* |RX Buffers | 16 bytes | 16 bytes | 16 bytes | 16 bytes | */ 3483182293Sdavidch/* |PG Buffers | none | none | none | none | */ 3484182293Sdavidch/* |TX Buffers | none | none | none | none | */ 3485182293Sdavidch/* |Chain Pages(1) | 4KiB | 4KiB | 4KiB | 4KiB | */ 3486202717Sdavidch/* |Context Memory | | | | | */ 3487182293Sdavidch/* +-----------------+----------+----------+----------+----------+ */ 3488182293Sdavidch/* */ 3489182293Sdavidch/* (1) Must align with CPU page size (BCM_PAGE_SZIE). */ 3490182293Sdavidch/* */ 3491157642Sps/* Returns: */ 3492157642Sps/* 0 for success, positive value for failure. */ 3493157642Sps/****************************************************************************/ 3494157642Spsstatic int 3495157642Spsbce_dma_alloc(device_t dev) 3496157642Sps{ 3497157642Sps struct bce_softc *sc; 3498157642Sps int i, error, rc = 0; 3499170392Sdavidch bus_size_t max_size, max_seg_size; 3500170392Sdavidch int max_segments; 3501157642Sps 3502157642Sps sc = device_get_softc(dev); 3503157642Sps 3504179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX); 3505179771Sdavidch 3506157642Sps /* 3507157642Sps * Allocate the parent bus DMA tag appropriate for PCI. 3508157642Sps */ 3509210269Syongari if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, BCE_DMA_BOUNDARY, 3510206268Sdavidch sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL, 3511210269Syongari BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, 3512210269Syongari &sc->parent_tag)) { 3513169271Sdavidch BCE_PRINTF("%s(%d): Could not allocate parent DMA tag!\n", 3514206268Sdavidch __FILE__, __LINE__); 3515157642Sps rc = ENOMEM; 3516157642Sps goto bce_dma_alloc_exit; 3517157642Sps } 3518157642Sps 3519157642Sps /* 3520157642Sps * Create a DMA tag for the status block, allocate and clear the 3521179771Sdavidch * memory, map the memory into DMA space, and fetch the physical 3522157642Sps * address of the block. 3523157642Sps */ 3524206268Sdavidch if (bus_dma_tag_create(sc->parent_tag, BCE_DMA_ALIGN, 3525206268Sdavidch BCE_DMA_BOUNDARY, sc->max_bus_addr, BUS_SPACE_MAXADDR, 3526206268Sdavidch NULL, NULL, BCE_STATUS_BLK_SZ, 1, BCE_STATUS_BLK_SZ, 3527206268Sdavidch 0, NULL, NULL, &sc->status_tag)) { 3528206268Sdavidch BCE_PRINTF("%s(%d): Could not allocate status block " 3529206268Sdavidch "DMA tag!\n", __FILE__, __LINE__); 3530157642Sps rc = ENOMEM; 3531157642Sps goto bce_dma_alloc_exit; 3532157642Sps } 3533157642Sps 3534206268Sdavidch if(bus_dmamem_alloc(sc->status_tag, (void **)&sc->status_block, 3535210270Syongari BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 3536210270Syongari &sc->status_map)) { 3537206268Sdavidch BCE_PRINTF("%s(%d): Could not allocate status block " 3538206268Sdavidch "DMA memory!\n", __FILE__, __LINE__); 3539157642Sps rc = ENOMEM; 3540157642Sps goto bce_dma_alloc_exit; 3541157642Sps } 3542157642Sps 3543206268Sdavidch error = bus_dmamap_load(sc->status_tag, sc->status_map, 3544206268Sdavidch sc->status_block, BCE_STATUS_BLK_SZ, bce_dma_map_addr, 3545206268Sdavidch &sc->status_block_paddr, BUS_DMA_NOWAIT); 3546179771Sdavidch 3547251146Smarius if (error || sc->status_block_paddr == 0) { 3548206268Sdavidch BCE_PRINTF("%s(%d): Could not map status block " 3549206268Sdavidch "DMA memory!\n", __FILE__, __LINE__); 3550157642Sps rc = ENOMEM; 3551157642Sps goto bce_dma_alloc_exit; 3552157642Sps } 3553157642Sps 3554207411Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): status_block_paddr = 0x%jX\n", 3555206268Sdavidch __FUNCTION__, (uintmax_t) sc->status_block_paddr); 3556157642Sps 3557157642Sps /* 3558157642Sps * Create a DMA tag for the statistics block, allocate and clear the 3559179771Sdavidch * memory, map the memory into DMA space, and fetch the physical 3560157642Sps * address of the block. 3561157642Sps */ 3562206268Sdavidch if (bus_dma_tag_create(sc->parent_tag, BCE_DMA_ALIGN, 3563206268Sdavidch BCE_DMA_BOUNDARY, sc->max_bus_addr, BUS_SPACE_MAXADDR, 3564206268Sdavidch NULL, NULL, BCE_STATS_BLK_SZ, 1, BCE_STATS_BLK_SZ, 3565206268Sdavidch 0, NULL, NULL, &sc->stats_tag)) { 3566206268Sdavidch BCE_PRINTF("%s(%d): Could not allocate statistics block " 3567206268Sdavidch "DMA tag!\n", __FILE__, __LINE__); 3568157642Sps rc = ENOMEM; 3569157642Sps goto bce_dma_alloc_exit; 3570157642Sps } 3571157642Sps 3572206268Sdavidch if (bus_dmamem_alloc(sc->stats_tag, (void **)&sc->stats_block, 3573210270Syongari BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->stats_map)) { 3574206268Sdavidch BCE_PRINTF("%s(%d): Could not allocate statistics block " 3575206268Sdavidch "DMA memory!\n", __FILE__, __LINE__); 3576157642Sps rc = ENOMEM; 3577157642Sps goto bce_dma_alloc_exit; 3578157642Sps } 3579157642Sps 3580206268Sdavidch error = bus_dmamap_load(sc->stats_tag, sc->stats_map, 3581206268Sdavidch sc->stats_block, BCE_STATS_BLK_SZ, bce_dma_map_addr, 3582206268Sdavidch &sc->stats_block_paddr, BUS_DMA_NOWAIT); 3583157642Sps 3584251146Smarius if (error || sc->stats_block_paddr == 0) { 3585206268Sdavidch BCE_PRINTF("%s(%d): Could not map statistics block " 3586206268Sdavidch "DMA memory!\n", __FILE__, __LINE__); 3587157642Sps rc = ENOMEM; 3588157642Sps goto bce_dma_alloc_exit; 3589157642Sps } 3590157642Sps 3591207411Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): stats_block_paddr = 0x%jX\n", 3592206268Sdavidch __FUNCTION__, (uintmax_t) sc->stats_block_paddr); 3593157642Sps 3594179771Sdavidch /* BCM5709 uses host memory as cache for context memory. */ 3595226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 3596179771Sdavidch sc->ctx_pages = 0x2000 / BCM_PAGE_SIZE; 3597179771Sdavidch if (sc->ctx_pages == 0) 3598179771Sdavidch sc->ctx_pages = 1; 3599179771Sdavidch 3600179771Sdavidch DBRUNIF((sc->ctx_pages > 512), 3601206268Sdavidch BCE_PRINTF("%s(%d): Too many CTX pages! %d > 512\n", 3602206268Sdavidch __FILE__, __LINE__, sc->ctx_pages)); 3603179771Sdavidch 3604179771Sdavidch /* 3605179771Sdavidch * Create a DMA tag for the context pages, 3606179771Sdavidch * allocate and clear the memory, map the 3607179771Sdavidch * memory into DMA space, and fetch the 3608179771Sdavidch * physical address of the block. 3609179771Sdavidch */ 3610206268Sdavidch if(bus_dma_tag_create(sc->parent_tag, BCM_PAGE_SIZE, 3611206268Sdavidch BCE_DMA_BOUNDARY, sc->max_bus_addr, BUS_SPACE_MAXADDR, 3612206268Sdavidch NULL, NULL, BCM_PAGE_SIZE, 1, BCM_PAGE_SIZE, 3613206268Sdavidch 0, NULL, NULL, &sc->ctx_tag)) { 3614207411Sdavidch BCE_PRINTF("%s(%d): Could not allocate CTX " 3615207411Sdavidch "DMA tag!\n", __FILE__, __LINE__); 3616179771Sdavidch rc = ENOMEM; 3617179771Sdavidch goto bce_dma_alloc_exit; 3618179771Sdavidch } 3619179771Sdavidch 3620179771Sdavidch for (i = 0; i < sc->ctx_pages; i++) { 3621179771Sdavidch 3622179771Sdavidch if(bus_dmamem_alloc(sc->ctx_tag, 3623206268Sdavidch (void **)&sc->ctx_block[i], 3624210270Syongari BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 3625206268Sdavidch &sc->ctx_map[i])) { 3626179771Sdavidch BCE_PRINTF("%s(%d): Could not allocate CTX " 3627206268Sdavidch "DMA memory!\n", __FILE__, __LINE__); 3628179771Sdavidch rc = ENOMEM; 3629179771Sdavidch goto bce_dma_alloc_exit; 3630179771Sdavidch } 3631179771Sdavidch 3632206268Sdavidch error = bus_dmamap_load(sc->ctx_tag, sc->ctx_map[i], 3633206268Sdavidch sc->ctx_block[i], BCM_PAGE_SIZE, bce_dma_map_addr, 3634206268Sdavidch &sc->ctx_paddr[i], BUS_DMA_NOWAIT); 3635179771Sdavidch 3636251146Smarius if (error || sc->ctx_paddr[i] == 0) { 3637206268Sdavidch BCE_PRINTF("%s(%d): Could not map CTX " 3638206268Sdavidch "DMA memory!\n", __FILE__, __LINE__); 3639179771Sdavidch rc = ENOMEM; 3640179771Sdavidch goto bce_dma_alloc_exit; 3641179771Sdavidch } 3642179771Sdavidch 3643207411Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): ctx_paddr[%d] " 3644207411Sdavidch "= 0x%jX\n", __FUNCTION__, i, 3645207411Sdavidch (uintmax_t) sc->ctx_paddr[i]); 3646179771Sdavidch } 3647179771Sdavidch } 3648179771Sdavidch 3649157642Sps /* 3650157642Sps * Create a DMA tag for the TX buffer descriptor chain, 3651157642Sps * allocate and clear the memory, and fetch the 3652157642Sps * physical address of the block. 3653157642Sps */ 3654206268Sdavidch if(bus_dma_tag_create(sc->parent_tag, BCM_PAGE_SIZE, BCE_DMA_BOUNDARY, 3655206268Sdavidch sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL, 3656206268Sdavidch BCE_TX_CHAIN_PAGE_SZ, 1, BCE_TX_CHAIN_PAGE_SZ, 0, 3657206268Sdavidch NULL, NULL, &sc->tx_bd_chain_tag)) { 3658207411Sdavidch BCE_PRINTF("%s(%d): Could not allocate TX descriptor " 3659207411Sdavidch "chain DMA tag!\n", __FILE__, __LINE__); 3660157642Sps rc = ENOMEM; 3661157642Sps goto bce_dma_alloc_exit; 3662157642Sps } 3663157642Sps 3664218423Sdavidch for (i = 0; i < sc->tx_pages; i++) { 3665157642Sps 3666207411Sdavidch if(bus_dmamem_alloc(sc->tx_bd_chain_tag, 3667210270Syongari (void **)&sc->tx_bd_chain[i], 3668210270Syongari BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 3669206268Sdavidch &sc->tx_bd_chain_map[i])) { 3670169271Sdavidch BCE_PRINTF("%s(%d): Could not allocate TX descriptor " 3671206268Sdavidch "chain DMA memory!\n", __FILE__, __LINE__); 3672157642Sps rc = ENOMEM; 3673157642Sps goto bce_dma_alloc_exit; 3674157642Sps } 3675157642Sps 3676169632Sdavidch error = bus_dmamap_load(sc->tx_bd_chain_tag, 3677206268Sdavidch sc->tx_bd_chain_map[i], sc->tx_bd_chain[i], 3678206268Sdavidch BCE_TX_CHAIN_PAGE_SZ, bce_dma_map_addr, 3679206268Sdavidch &sc->tx_bd_chain_paddr[i], BUS_DMA_NOWAIT); 3680157642Sps 3681251146Smarius if (error || sc->tx_bd_chain_paddr[i] == 0) { 3682206268Sdavidch BCE_PRINTF("%s(%d): Could not map TX descriptor " 3683206268Sdavidch "chain DMA memory!\n", __FILE__, __LINE__); 3684157642Sps rc = ENOMEM; 3685157642Sps goto bce_dma_alloc_exit; 3686157642Sps } 3687157642Sps 3688207411Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): tx_bd_chain_paddr[%d] = " 3689207411Sdavidch "0x%jX\n", __FUNCTION__, i, 3690207411Sdavidch (uintmax_t) sc->tx_bd_chain_paddr[i]); 3691157642Sps } 3692170392Sdavidch 3693170392Sdavidch /* Check the required size before mapping to conserve resources. */ 3694170392Sdavidch if (bce_tso_enable) { 3695170392Sdavidch max_size = BCE_TSO_MAX_SIZE; 3696170392Sdavidch max_segments = BCE_MAX_SEGMENTS; 3697170392Sdavidch max_seg_size = BCE_TSO_MAX_SEG_SIZE; 3698170392Sdavidch } else { 3699170392Sdavidch max_size = MCLBYTES * BCE_MAX_SEGMENTS; 3700170392Sdavidch max_segments = BCE_MAX_SEGMENTS; 3701170392Sdavidch max_seg_size = MCLBYTES; 3702170392Sdavidch } 3703179771Sdavidch 3704157642Sps /* Create a DMA tag for TX mbufs. */ 3705206268Sdavidch if (bus_dma_tag_create(sc->parent_tag, 1, BCE_DMA_BOUNDARY, 3706206268Sdavidch sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL, max_size, 3707206268Sdavidch max_segments, max_seg_size, 0, NULL, NULL, &sc->tx_mbuf_tag)) { 3708169271Sdavidch BCE_PRINTF("%s(%d): Could not allocate TX mbuf DMA tag!\n", 3709206268Sdavidch __FILE__, __LINE__); 3710157642Sps rc = ENOMEM; 3711157642Sps goto bce_dma_alloc_exit; 3712157642Sps } 3713157642Sps 3714157642Sps /* Create DMA maps for the TX mbufs clusters. */ 3715218423Sdavidch for (i = 0; i < TOTAL_TX_BD_ALLOC; i++) { 3716179771Sdavidch if (bus_dmamap_create(sc->tx_mbuf_tag, BUS_DMA_NOWAIT, 3717157642Sps &sc->tx_mbuf_map[i])) { 3718206268Sdavidch BCE_PRINTF("%s(%d): Unable to create TX mbuf DMA " 3719206268Sdavidch "map!\n", __FILE__, __LINE__); 3720157642Sps rc = ENOMEM; 3721157642Sps goto bce_dma_alloc_exit; 3722157642Sps } 3723157642Sps } 3724157642Sps 3725157642Sps /* 3726157642Sps * Create a DMA tag for the RX buffer descriptor chain, 3727176448Sdavidch * allocate and clear the memory, and fetch the physical 3728157642Sps * address of the blocks. 3729157642Sps */ 3730206268Sdavidch if (bus_dma_tag_create(sc->parent_tag, BCM_PAGE_SIZE, 3731206268Sdavidch BCE_DMA_BOUNDARY, BUS_SPACE_MAXADDR, 3732206268Sdavidch sc->max_bus_addr, NULL, NULL, 3733206268Sdavidch BCE_RX_CHAIN_PAGE_SZ, 1, BCE_RX_CHAIN_PAGE_SZ, 3734206268Sdavidch 0, NULL, NULL, &sc->rx_bd_chain_tag)) { 3735206268Sdavidch BCE_PRINTF("%s(%d): Could not allocate RX descriptor chain " 3736206268Sdavidch "DMA tag!\n", __FILE__, __LINE__); 3737157642Sps rc = ENOMEM; 3738157642Sps goto bce_dma_alloc_exit; 3739157642Sps } 3740157642Sps 3741218423Sdavidch for (i = 0; i < sc->rx_pages; i++) { 3742157642Sps 3743169632Sdavidch if (bus_dmamem_alloc(sc->rx_bd_chain_tag, 3744210270Syongari (void **)&sc->rx_bd_chain[i], 3745210270Syongari BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 3746206268Sdavidch &sc->rx_bd_chain_map[i])) { 3747206268Sdavidch BCE_PRINTF("%s(%d): Could not allocate RX descriptor " 3748206268Sdavidch "chain DMA memory!\n", __FILE__, __LINE__); 3749157642Sps rc = ENOMEM; 3750157642Sps goto bce_dma_alloc_exit; 3751157642Sps } 3752157642Sps 3753169632Sdavidch error = bus_dmamap_load(sc->rx_bd_chain_tag, 3754206268Sdavidch sc->rx_bd_chain_map[i], sc->rx_bd_chain[i], 3755206268Sdavidch BCE_RX_CHAIN_PAGE_SZ, bce_dma_map_addr, 3756206268Sdavidch &sc->rx_bd_chain_paddr[i], BUS_DMA_NOWAIT); 3757157642Sps 3758251146Smarius if (error || sc->rx_bd_chain_paddr[i] == 0) { 3759206268Sdavidch BCE_PRINTF("%s(%d): Could not map RX descriptor " 3760206268Sdavidch "chain DMA memory!\n", __FILE__, __LINE__); 3761157642Sps rc = ENOMEM; 3762157642Sps goto bce_dma_alloc_exit; 3763157642Sps } 3764157642Sps 3765207411Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): rx_bd_chain_paddr[%d] = " 3766207411Sdavidch "0x%jX\n", __FUNCTION__, i, 3767207411Sdavidch (uintmax_t) sc->rx_bd_chain_paddr[i]); 3768157642Sps } 3769157642Sps 3770157642Sps /* 3771157642Sps * Create a DMA tag for RX mbufs. 3772178132Sdavidch */ 3773218423Sdavidch if (bce_hdr_split == TRUE) 3774251142Smarius max_size = ((sc->rx_bd_mbuf_alloc_size < MCLBYTES) ? 3775218423Sdavidch MCLBYTES : sc->rx_bd_mbuf_alloc_size); 3776218423Sdavidch else 3777251142Smarius max_size = MJUM9BYTES; 3778176448Sdavidch 3779207411Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): Creating rx_mbuf_tag " 3780251142Smarius "(max size = 0x%jX)\n", __FUNCTION__, (uintmax_t)max_size); 3781189325Sdavidch 3782210271Syongari if (bus_dma_tag_create(sc->parent_tag, BCE_RX_BUF_ALIGN, 3783210270Syongari BCE_DMA_BOUNDARY, sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL, 3784251142Smarius max_size, 1, max_size, 0, NULL, NULL, &sc->rx_mbuf_tag)) { 3785169271Sdavidch BCE_PRINTF("%s(%d): Could not allocate RX mbuf DMA tag!\n", 3786206268Sdavidch __FILE__, __LINE__); 3787157642Sps rc = ENOMEM; 3788157642Sps goto bce_dma_alloc_exit; 3789157642Sps } 3790157642Sps 3791157642Sps /* Create DMA maps for the RX mbuf clusters. */ 3792218423Sdavidch for (i = 0; i < TOTAL_RX_BD_ALLOC; i++) { 3793157642Sps if (bus_dmamap_create(sc->rx_mbuf_tag, BUS_DMA_NOWAIT, 3794206268Sdavidch &sc->rx_mbuf_map[i])) { 3795206268Sdavidch BCE_PRINTF("%s(%d): Unable to create RX mbuf " 3796206268Sdavidch "DMA map!\n", __FILE__, __LINE__); 3797157642Sps rc = ENOMEM; 3798157642Sps goto bce_dma_alloc_exit; 3799157642Sps } 3800157642Sps } 3801157642Sps 3802218423Sdavidch if (bce_hdr_split == TRUE) { 3803218423Sdavidch /* 3804218423Sdavidch * Create a DMA tag for the page buffer descriptor chain, 3805218423Sdavidch * allocate and clear the memory, and fetch the physical 3806218423Sdavidch * address of the blocks. 3807218423Sdavidch */ 3808218423Sdavidch if (bus_dma_tag_create(sc->parent_tag, BCM_PAGE_SIZE, 3809218423Sdavidch BCE_DMA_BOUNDARY, BUS_SPACE_MAXADDR, sc->max_bus_addr, 3810218423Sdavidch NULL, NULL, BCE_PG_CHAIN_PAGE_SZ, 1, BCE_PG_CHAIN_PAGE_SZ, 3811218423Sdavidch 0, NULL, NULL, &sc->pg_bd_chain_tag)) { 3812218423Sdavidch BCE_PRINTF("%s(%d): Could not allocate page descriptor " 3813218423Sdavidch "chain DMA tag!\n", __FILE__, __LINE__); 3814176448Sdavidch rc = ENOMEM; 3815176448Sdavidch goto bce_dma_alloc_exit; 3816176448Sdavidch } 3817176448Sdavidch 3818218423Sdavidch for (i = 0; i < sc->pg_pages; i++) { 3819218423Sdavidch if (bus_dmamem_alloc(sc->pg_bd_chain_tag, 3820218423Sdavidch (void **)&sc->pg_bd_chain[i], 3821218423Sdavidch BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 3822218423Sdavidch &sc->pg_bd_chain_map[i])) { 3823218423Sdavidch BCE_PRINTF("%s(%d): Could not allocate page " 3824218423Sdavidch "descriptor chain DMA memory!\n", 3825218423Sdavidch __FILE__, __LINE__); 3826218423Sdavidch rc = ENOMEM; 3827218423Sdavidch goto bce_dma_alloc_exit; 3828218423Sdavidch } 3829176448Sdavidch 3830218423Sdavidch error = bus_dmamap_load(sc->pg_bd_chain_tag, 3831218423Sdavidch sc->pg_bd_chain_map[i], sc->pg_bd_chain[i], 3832218423Sdavidch BCE_PG_CHAIN_PAGE_SZ, bce_dma_map_addr, 3833218423Sdavidch &sc->pg_bd_chain_paddr[i], BUS_DMA_NOWAIT); 3834176448Sdavidch 3835251146Smarius if (error || sc->pg_bd_chain_paddr[i] == 0) { 3836218423Sdavidch BCE_PRINTF("%s(%d): Could not map page descriptor " 3837218423Sdavidch "chain DMA memory!\n", __FILE__, __LINE__); 3838218423Sdavidch rc = ENOMEM; 3839218423Sdavidch goto bce_dma_alloc_exit; 3840218423Sdavidch } 3841176448Sdavidch 3842218423Sdavidch DBPRINT(sc, BCE_INFO_LOAD, "%s(): pg_bd_chain_paddr[%d] = " 3843218423Sdavidch "0x%jX\n", __FUNCTION__, i, 3844218423Sdavidch (uintmax_t) sc->pg_bd_chain_paddr[i]); 3845218423Sdavidch } 3846176448Sdavidch 3847218423Sdavidch /* 3848218423Sdavidch * Create a DMA tag for page mbufs. 3849218423Sdavidch */ 3850218423Sdavidch if (bus_dma_tag_create(sc->parent_tag, 1, BCE_DMA_BOUNDARY, 3851251142Smarius sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 3852251142Smarius 1, MCLBYTES, 0, NULL, NULL, &sc->pg_mbuf_tag)) { 3853218423Sdavidch BCE_PRINTF("%s(%d): Could not allocate page mbuf " 3854218423Sdavidch "DMA tag!\n", __FILE__, __LINE__); 3855176448Sdavidch rc = ENOMEM; 3856176448Sdavidch goto bce_dma_alloc_exit; 3857176448Sdavidch } 3858218423Sdavidch 3859218423Sdavidch /* Create DMA maps for the page mbuf clusters. */ 3860218423Sdavidch for (i = 0; i < TOTAL_PG_BD_ALLOC; i++) { 3861218423Sdavidch if (bus_dmamap_create(sc->pg_mbuf_tag, BUS_DMA_NOWAIT, 3862218423Sdavidch &sc->pg_mbuf_map[i])) { 3863218423Sdavidch BCE_PRINTF("%s(%d): Unable to create page mbuf " 3864218423Sdavidch "DMA map!\n", __FILE__, __LINE__); 3865218423Sdavidch rc = ENOMEM; 3866218423Sdavidch goto bce_dma_alloc_exit; 3867218423Sdavidch } 3868218423Sdavidch } 3869176448Sdavidch } 3870176448Sdavidch 3871157642Spsbce_dma_alloc_exit: 3872179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX); 3873157642Sps return(rc); 3874157642Sps} 3875157642Sps 3876157642Sps 3877157642Sps/****************************************************************************/ 3878157642Sps/* Release all resources used by the driver. */ 3879157642Sps/* */ 3880157642Sps/* Releases all resources acquired by the driver including interrupts, */ 3881157642Sps/* interrupt handler, interfaces, mutexes, and DMA memory. */ 3882157642Sps/* */ 3883157642Sps/* Returns: */ 3884157642Sps/* Nothing. */ 3885157642Sps/****************************************************************************/ 3886157642Spsstatic void 3887157642Spsbce_release_resources(struct bce_softc *sc) 3888157642Sps{ 3889157642Sps device_t dev; 3890157642Sps 3891179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 3892157642Sps 3893157642Sps dev = sc->bce_dev; 3894157642Sps 3895157642Sps bce_dma_free(sc); 3896170392Sdavidch 3897170392Sdavidch if (sc->bce_intrhand != NULL) { 3898169632Sdavidch DBPRINT(sc, BCE_INFO_RESET, "Removing interrupt handler.\n"); 3899170392Sdavidch bus_teardown_intr(dev, sc->bce_res_irq, sc->bce_intrhand); 3900169632Sdavidch } 3901157642Sps 3902170392Sdavidch if (sc->bce_res_irq != NULL) { 3903169632Sdavidch DBPRINT(sc, BCE_INFO_RESET, "Releasing IRQ.\n"); 3904247565Smarius bus_release_resource(dev, SYS_RES_IRQ, 3905247565Smarius rman_get_rid(sc->bce_res_irq), sc->bce_res_irq); 3906169632Sdavidch } 3907170392Sdavidch 3908179771Sdavidch if (sc->bce_flags & (BCE_USING_MSI_FLAG | BCE_USING_MSIX_FLAG)) { 3909179771Sdavidch DBPRINT(sc, BCE_INFO_RESET, "Releasing MSI/MSI-X vector.\n"); 3910170392Sdavidch pci_release_msi(dev); 3911170392Sdavidch } 3912157642Sps 3913170392Sdavidch if (sc->bce_res_mem != NULL) { 3914169632Sdavidch DBPRINT(sc, BCE_INFO_RESET, "Releasing PCI memory.\n"); 3915207411Sdavidch bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), 3916206268Sdavidch sc->bce_res_mem); 3917169632Sdavidch } 3918157642Sps 3919170392Sdavidch if (sc->bce_ifp != NULL) { 3920169632Sdavidch DBPRINT(sc, BCE_INFO_RESET, "Releasing IF.\n"); 3921170392Sdavidch if_free(sc->bce_ifp); 3922169632Sdavidch } 3923164305Sjhb 3924157642Sps if (mtx_initialized(&sc->bce_mtx)) 3925157642Sps BCE_LOCK_DESTROY(sc); 3926157642Sps 3927179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 3928157642Sps} 3929157642Sps 3930157642Sps 3931157642Sps/****************************************************************************/ 3932157642Sps/* Firmware synchronization. */ 3933157642Sps/* */ 3934157642Sps/* Before performing certain events such as a chip reset, synchronize with */ 3935157642Sps/* the firmware first. */ 3936157642Sps/* */ 3937157642Sps/* Returns: */ 3938157642Sps/* 0 for success, positive value for failure. */ 3939157642Sps/****************************************************************************/ 3940157642Spsstatic int 3941157642Spsbce_fw_sync(struct bce_softc *sc, u32 msg_data) 3942157642Sps{ 3943157642Sps int i, rc = 0; 3944157642Sps u32 val; 3945157642Sps 3946179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 3947179771Sdavidch 3948157642Sps /* Don't waste any time if we've timed out before. */ 3949206268Sdavidch if (sc->bce_fw_timed_out == TRUE) { 3950157642Sps rc = EBUSY; 3951157642Sps goto bce_fw_sync_exit; 3952157642Sps } 3953157642Sps 3954157642Sps /* Increment the message sequence number. */ 3955157642Sps sc->bce_fw_wr_seq++; 3956157642Sps msg_data |= sc->bce_fw_wr_seq; 3957157642Sps 3958206268Sdavidch DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "bce_fw_sync(): msg_data = " 3959206268Sdavidch "0x%08X\n", msg_data); 3960157642Sps 3961157642Sps /* Send the message to the bootcode driver mailbox. */ 3962194781Sdavidch bce_shmem_wr(sc, BCE_DRV_MB, msg_data); 3963157642Sps 3964157642Sps /* Wait for the bootcode to acknowledge the message. */ 3965157642Sps for (i = 0; i < FW_ACK_TIME_OUT_MS; i++) { 3966157642Sps /* Check for a response in the bootcode firmware mailbox. */ 3967194781Sdavidch val = bce_shmem_rd(sc, BCE_FW_MB); 3968157642Sps if ((val & BCE_FW_MSG_ACK) == (msg_data & BCE_DRV_MSG_SEQ)) 3969157642Sps break; 3970157642Sps DELAY(1000); 3971157642Sps } 3972157642Sps 3973207411Sdavidch /* If we've timed out, tell bootcode that we've stopped waiting. */ 3974157642Sps if (((val & BCE_FW_MSG_ACK) != (msg_data & BCE_DRV_MSG_SEQ)) && 3975206268Sdavidch ((msg_data & BCE_DRV_MSG_DATA) != BCE_DRV_MSG_DATA_WAIT0)) { 3976157642Sps 3977169271Sdavidch BCE_PRINTF("%s(%d): Firmware synchronization timeout! " 3978206268Sdavidch "msg_data = 0x%08X\n", __FILE__, __LINE__, msg_data); 3979157642Sps 3980157642Sps msg_data &= ~BCE_DRV_MSG_CODE; 3981157642Sps msg_data |= BCE_DRV_MSG_CODE_FW_TIMEOUT; 3982157642Sps 3983194781Sdavidch bce_shmem_wr(sc, BCE_DRV_MB, msg_data); 3984157642Sps 3985206268Sdavidch sc->bce_fw_timed_out = TRUE; 3986157642Sps rc = EBUSY; 3987157642Sps } 3988157642Sps 3989157642Spsbce_fw_sync_exit: 3990179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 3991157642Sps return (rc); 3992157642Sps} 3993157642Sps 3994157642Sps 3995157642Sps/****************************************************************************/ 3996157642Sps/* Load Receive Virtual 2 Physical (RV2P) processor firmware. */ 3997157642Sps/* */ 3998157642Sps/* Returns: */ 3999157642Sps/* Nothing. */ 4000157642Sps/****************************************************************************/ 4001157642Spsstatic void 4002251142Smariusbce_load_rv2p_fw(struct bce_softc *sc, const u32 *rv2p_code, 4003157642Sps u32 rv2p_code_len, u32 rv2p_proc) 4004157642Sps{ 4005157642Sps int i; 4006157642Sps u32 val; 4007178132Sdavidch 4008179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4009179771Sdavidch 4010176448Sdavidch /* Set the page size used by RV2P. */ 4011176448Sdavidch if (rv2p_proc == RV2P_PROC2) { 4012178132Sdavidch BCE_RV2P_PROC2_CHG_MAX_BD_PAGE(USABLE_RX_BD_PER_PAGE); 4013176448Sdavidch } 4014178132Sdavidch 4015157642Sps for (i = 0; i < rv2p_code_len; i += 8) { 4016157642Sps REG_WR(sc, BCE_RV2P_INSTR_HIGH, *rv2p_code); 4017157642Sps rv2p_code++; 4018157642Sps REG_WR(sc, BCE_RV2P_INSTR_LOW, *rv2p_code); 4019157642Sps rv2p_code++; 4020157642Sps 4021157642Sps if (rv2p_proc == RV2P_PROC1) { 4022157642Sps val = (i / 8) | BCE_RV2P_PROC1_ADDR_CMD_RDWR; 4023157642Sps REG_WR(sc, BCE_RV2P_PROC1_ADDR_CMD, val); 4024157642Sps } 4025157642Sps else { 4026157642Sps val = (i / 8) | BCE_RV2P_PROC2_ADDR_CMD_RDWR; 4027157642Sps REG_WR(sc, BCE_RV2P_PROC2_ADDR_CMD, val); 4028157642Sps } 4029157642Sps } 4030157642Sps 4031157642Sps /* Reset the processor, un-stall is done later. */ 4032157642Sps if (rv2p_proc == RV2P_PROC1) { 4033157642Sps REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC1_RESET); 4034157642Sps } 4035157642Sps else { 4036157642Sps REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC2_RESET); 4037157642Sps } 4038179771Sdavidch 4039179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4040157642Sps} 4041157642Sps 4042157642Sps 4043157642Sps/****************************************************************************/ 4044157642Sps/* Load RISC processor firmware. */ 4045157642Sps/* */ 4046157642Sps/* Loads firmware from the file if_bcefw.h into the scratchpad memory */ 4047157642Sps/* associated with a particular processor. */ 4048157642Sps/* */ 4049157642Sps/* Returns: */ 4050157642Sps/* Nothing. */ 4051157642Sps/****************************************************************************/ 4052157642Spsstatic void 4053157642Spsbce_load_cpu_fw(struct bce_softc *sc, struct cpu_reg *cpu_reg, 4054157642Sps struct fw_info *fw) 4055157642Sps{ 4056157642Sps u32 offset; 4057157642Sps 4058179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4059179771Sdavidch 4060202717Sdavidch bce_halt_cpu(sc, cpu_reg); 4061157642Sps 4062157642Sps /* Load the Text area. */ 4063157642Sps offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base); 4064157642Sps if (fw->text) { 4065157642Sps int j; 4066157642Sps 4067157642Sps for (j = 0; j < (fw->text_len / 4); j++, offset += 4) { 4068157642Sps REG_WR_IND(sc, offset, fw->text[j]); 4069157642Sps } 4070157642Sps } 4071157642Sps 4072157642Sps /* Load the Data area. */ 4073157642Sps offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base); 4074157642Sps if (fw->data) { 4075157642Sps int j; 4076157642Sps 4077157642Sps for (j = 0; j < (fw->data_len / 4); j++, offset += 4) { 4078157642Sps REG_WR_IND(sc, offset, fw->data[j]); 4079157642Sps } 4080157642Sps } 4081157642Sps 4082157642Sps /* Load the SBSS area. */ 4083157642Sps offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base); 4084157642Sps if (fw->sbss) { 4085157642Sps int j; 4086157642Sps 4087157642Sps for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) { 4088157642Sps REG_WR_IND(sc, offset, fw->sbss[j]); 4089157642Sps } 4090157642Sps } 4091157642Sps 4092157642Sps /* Load the BSS area. */ 4093157642Sps offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base); 4094157642Sps if (fw->bss) { 4095157642Sps int j; 4096157642Sps 4097157642Sps for (j = 0; j < (fw->bss_len/4); j++, offset += 4) { 4098157642Sps REG_WR_IND(sc, offset, fw->bss[j]); 4099157642Sps } 4100157642Sps } 4101157642Sps 4102157642Sps /* Load the Read-Only area. */ 4103157642Sps offset = cpu_reg->spad_base + 4104157642Sps (fw->rodata_addr - cpu_reg->mips_view_base); 4105157642Sps if (fw->rodata) { 4106157642Sps int j; 4107157642Sps 4108157642Sps for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) { 4109157642Sps REG_WR_IND(sc, offset, fw->rodata[j]); 4110157642Sps } 4111157642Sps } 4112157642Sps 4113206268Sdavidch /* Clear the pre-fetch instruction and set the FW start address. */ 4114206268Sdavidch REG_WR_IND(sc, cpu_reg->inst, 0); 4115206268Sdavidch REG_WR_IND(sc, cpu_reg->pc, fw->start_addr); 4116157642Sps 4117202717Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4118202717Sdavidch} 4119202717Sdavidch 4120202717Sdavidch 4121202717Sdavidch/****************************************************************************/ 4122202717Sdavidch/* Starts the RISC processor. */ 4123202717Sdavidch/* */ 4124202717Sdavidch/* Assumes the CPU starting address has already been set. */ 4125202717Sdavidch/* */ 4126202717Sdavidch/* Returns: */ 4127202717Sdavidch/* Nothing. */ 4128202717Sdavidch/****************************************************************************/ 4129202717Sdavidchstatic void 4130202717Sdavidchbce_start_cpu(struct bce_softc *sc, struct cpu_reg *cpu_reg) 4131202717Sdavidch{ 4132202717Sdavidch u32 val; 4133202717Sdavidch 4134202717Sdavidch DBENTER(BCE_VERBOSE_RESET); 4135202717Sdavidch 4136157642Sps /* Start the CPU. */ 4137157642Sps val = REG_RD_IND(sc, cpu_reg->mode); 4138157642Sps val &= ~cpu_reg->mode_value_halt; 4139157642Sps REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear); 4140157642Sps REG_WR_IND(sc, cpu_reg->mode, val); 4141179771Sdavidch 4142179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4143157642Sps} 4144157642Sps 4145157642Sps 4146157642Sps/****************************************************************************/ 4147202717Sdavidch/* Halts the RISC processor. */ 4148202717Sdavidch/* */ 4149202717Sdavidch/* Returns: */ 4150202717Sdavidch/* Nothing. */ 4151202717Sdavidch/****************************************************************************/ 4152202717Sdavidchstatic void 4153202717Sdavidchbce_halt_cpu(struct bce_softc *sc, struct cpu_reg *cpu_reg) 4154202717Sdavidch{ 4155202717Sdavidch u32 val; 4156202717Sdavidch 4157202717Sdavidch DBENTER(BCE_VERBOSE_RESET); 4158202717Sdavidch 4159206268Sdavidch /* Halt the CPU. */ 4160206268Sdavidch val = REG_RD_IND(sc, cpu_reg->mode); 4161206268Sdavidch val |= cpu_reg->mode_value_halt; 4162206268Sdavidch REG_WR_IND(sc, cpu_reg->mode, val); 4163206268Sdavidch REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear); 4164202717Sdavidch 4165202717Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4166202717Sdavidch} 4167202717Sdavidch 4168202717Sdavidch 4169202717Sdavidch/****************************************************************************/ 4170179771Sdavidch/* Initialize the RX CPU. */ 4171157642Sps/* */ 4172157642Sps/* Returns: */ 4173157642Sps/* Nothing. */ 4174157642Sps/****************************************************************************/ 4175157642Spsstatic void 4176202717Sdavidchbce_start_rxp_cpu(struct bce_softc *sc) 4177202717Sdavidch{ 4178202717Sdavidch struct cpu_reg cpu_reg; 4179202717Sdavidch 4180202717Sdavidch DBENTER(BCE_VERBOSE_RESET); 4181202717Sdavidch 4182202717Sdavidch cpu_reg.mode = BCE_RXP_CPU_MODE; 4183202717Sdavidch cpu_reg.mode_value_halt = BCE_RXP_CPU_MODE_SOFT_HALT; 4184202717Sdavidch cpu_reg.mode_value_sstep = BCE_RXP_CPU_MODE_STEP_ENA; 4185202717Sdavidch cpu_reg.state = BCE_RXP_CPU_STATE; 4186202717Sdavidch cpu_reg.state_value_clear = 0xffffff; 4187202717Sdavidch cpu_reg.gpr0 = BCE_RXP_CPU_REG_FILE; 4188202717Sdavidch cpu_reg.evmask = BCE_RXP_CPU_EVENT_MASK; 4189202717Sdavidch cpu_reg.pc = BCE_RXP_CPU_PROGRAM_COUNTER; 4190202717Sdavidch cpu_reg.inst = BCE_RXP_CPU_INSTRUCTION; 4191202717Sdavidch cpu_reg.bp = BCE_RXP_CPU_HW_BREAKPOINT; 4192202717Sdavidch cpu_reg.spad_base = BCE_RXP_SCRATCH; 4193202717Sdavidch cpu_reg.mips_view_base = 0x8000000; 4194202717Sdavidch 4195202717Sdavidch DBPRINT(sc, BCE_INFO_RESET, "Starting RX firmware.\n"); 4196202717Sdavidch bce_start_cpu(sc, &cpu_reg); 4197202717Sdavidch 4198202717Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4199202717Sdavidch} 4200202717Sdavidch 4201202717Sdavidch 4202202717Sdavidch/****************************************************************************/ 4203202717Sdavidch/* Initialize the RX CPU. */ 4204202717Sdavidch/* */ 4205202717Sdavidch/* Returns: */ 4206202717Sdavidch/* Nothing. */ 4207202717Sdavidch/****************************************************************************/ 4208202717Sdavidchstatic void 4209179771Sdavidchbce_init_rxp_cpu(struct bce_softc *sc) 4210157642Sps{ 4211157642Sps struct cpu_reg cpu_reg; 4212157642Sps struct fw_info fw; 4213157642Sps 4214179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4215157642Sps 4216157642Sps cpu_reg.mode = BCE_RXP_CPU_MODE; 4217157642Sps cpu_reg.mode_value_halt = BCE_RXP_CPU_MODE_SOFT_HALT; 4218157642Sps cpu_reg.mode_value_sstep = BCE_RXP_CPU_MODE_STEP_ENA; 4219157642Sps cpu_reg.state = BCE_RXP_CPU_STATE; 4220157642Sps cpu_reg.state_value_clear = 0xffffff; 4221157642Sps cpu_reg.gpr0 = BCE_RXP_CPU_REG_FILE; 4222157642Sps cpu_reg.evmask = BCE_RXP_CPU_EVENT_MASK; 4223157642Sps cpu_reg.pc = BCE_RXP_CPU_PROGRAM_COUNTER; 4224157642Sps cpu_reg.inst = BCE_RXP_CPU_INSTRUCTION; 4225157642Sps cpu_reg.bp = BCE_RXP_CPU_HW_BREAKPOINT; 4226157642Sps cpu_reg.spad_base = BCE_RXP_SCRATCH; 4227157642Sps cpu_reg.mips_view_base = 0x8000000; 4228157642Sps 4229226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 4230179771Sdavidch fw.ver_major = bce_RXP_b09FwReleaseMajor; 4231179771Sdavidch fw.ver_minor = bce_RXP_b09FwReleaseMinor; 4232179771Sdavidch fw.ver_fix = bce_RXP_b09FwReleaseFix; 4233179771Sdavidch fw.start_addr = bce_RXP_b09FwStartAddr; 4234157642Sps 4235179771Sdavidch fw.text_addr = bce_RXP_b09FwTextAddr; 4236179771Sdavidch fw.text_len = bce_RXP_b09FwTextLen; 4237179771Sdavidch fw.text_index = 0; 4238179771Sdavidch fw.text = bce_RXP_b09FwText; 4239157642Sps 4240179771Sdavidch fw.data_addr = bce_RXP_b09FwDataAddr; 4241179771Sdavidch fw.data_len = bce_RXP_b09FwDataLen; 4242179771Sdavidch fw.data_index = 0; 4243179771Sdavidch fw.data = bce_RXP_b09FwData; 4244157642Sps 4245179771Sdavidch fw.sbss_addr = bce_RXP_b09FwSbssAddr; 4246179771Sdavidch fw.sbss_len = bce_RXP_b09FwSbssLen; 4247179771Sdavidch fw.sbss_index = 0; 4248179771Sdavidch fw.sbss = bce_RXP_b09FwSbss; 4249157642Sps 4250179771Sdavidch fw.bss_addr = bce_RXP_b09FwBssAddr; 4251179771Sdavidch fw.bss_len = bce_RXP_b09FwBssLen; 4252179771Sdavidch fw.bss_index = 0; 4253179771Sdavidch fw.bss = bce_RXP_b09FwBss; 4254157642Sps 4255179771Sdavidch fw.rodata_addr = bce_RXP_b09FwRodataAddr; 4256179771Sdavidch fw.rodata_len = bce_RXP_b09FwRodataLen; 4257179771Sdavidch fw.rodata_index = 0; 4258179771Sdavidch fw.rodata = bce_RXP_b09FwRodata; 4259179771Sdavidch } else { 4260179771Sdavidch fw.ver_major = bce_RXP_b06FwReleaseMajor; 4261179771Sdavidch fw.ver_minor = bce_RXP_b06FwReleaseMinor; 4262179771Sdavidch fw.ver_fix = bce_RXP_b06FwReleaseFix; 4263179771Sdavidch fw.start_addr = bce_RXP_b06FwStartAddr; 4264157642Sps 4265179771Sdavidch fw.text_addr = bce_RXP_b06FwTextAddr; 4266179771Sdavidch fw.text_len = bce_RXP_b06FwTextLen; 4267179771Sdavidch fw.text_index = 0; 4268179771Sdavidch fw.text = bce_RXP_b06FwText; 4269179771Sdavidch 4270179771Sdavidch fw.data_addr = bce_RXP_b06FwDataAddr; 4271179771Sdavidch fw.data_len = bce_RXP_b06FwDataLen; 4272179771Sdavidch fw.data_index = 0; 4273179771Sdavidch fw.data = bce_RXP_b06FwData; 4274179771Sdavidch 4275179771Sdavidch fw.sbss_addr = bce_RXP_b06FwSbssAddr; 4276179771Sdavidch fw.sbss_len = bce_RXP_b06FwSbssLen; 4277179771Sdavidch fw.sbss_index = 0; 4278179771Sdavidch fw.sbss = bce_RXP_b06FwSbss; 4279179771Sdavidch 4280179771Sdavidch fw.bss_addr = bce_RXP_b06FwBssAddr; 4281179771Sdavidch fw.bss_len = bce_RXP_b06FwBssLen; 4282179771Sdavidch fw.bss_index = 0; 4283179771Sdavidch fw.bss = bce_RXP_b06FwBss; 4284179771Sdavidch 4285179771Sdavidch fw.rodata_addr = bce_RXP_b06FwRodataAddr; 4286179771Sdavidch fw.rodata_len = bce_RXP_b06FwRodataLen; 4287179771Sdavidch fw.rodata_index = 0; 4288179771Sdavidch fw.rodata = bce_RXP_b06FwRodata; 4289179771Sdavidch } 4290179771Sdavidch 4291157642Sps DBPRINT(sc, BCE_INFO_RESET, "Loading RX firmware.\n"); 4292157642Sps bce_load_cpu_fw(sc, &cpu_reg, &fw); 4293157642Sps 4294202717Sdavidch /* Delay RXP start until initialization is complete. */ 4295202717Sdavidch 4296179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4297179771Sdavidch} 4298179771Sdavidch 4299179771Sdavidch 4300179771Sdavidch/****************************************************************************/ 4301179771Sdavidch/* Initialize the TX CPU. */ 4302179771Sdavidch/* */ 4303179771Sdavidch/* Returns: */ 4304179771Sdavidch/* Nothing. */ 4305179771Sdavidch/****************************************************************************/ 4306179771Sdavidchstatic void 4307179771Sdavidchbce_init_txp_cpu(struct bce_softc *sc) 4308179771Sdavidch{ 4309179771Sdavidch struct cpu_reg cpu_reg; 4310179771Sdavidch struct fw_info fw; 4311179771Sdavidch 4312179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4313179771Sdavidch 4314157642Sps cpu_reg.mode = BCE_TXP_CPU_MODE; 4315157642Sps cpu_reg.mode_value_halt = BCE_TXP_CPU_MODE_SOFT_HALT; 4316157642Sps cpu_reg.mode_value_sstep = BCE_TXP_CPU_MODE_STEP_ENA; 4317157642Sps cpu_reg.state = BCE_TXP_CPU_STATE; 4318157642Sps cpu_reg.state_value_clear = 0xffffff; 4319157642Sps cpu_reg.gpr0 = BCE_TXP_CPU_REG_FILE; 4320157642Sps cpu_reg.evmask = BCE_TXP_CPU_EVENT_MASK; 4321157642Sps cpu_reg.pc = BCE_TXP_CPU_PROGRAM_COUNTER; 4322157642Sps cpu_reg.inst = BCE_TXP_CPU_INSTRUCTION; 4323157642Sps cpu_reg.bp = BCE_TXP_CPU_HW_BREAKPOINT; 4324157642Sps cpu_reg.spad_base = BCE_TXP_SCRATCH; 4325157642Sps cpu_reg.mips_view_base = 0x8000000; 4326157642Sps 4327226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 4328179771Sdavidch fw.ver_major = bce_TXP_b09FwReleaseMajor; 4329179771Sdavidch fw.ver_minor = bce_TXP_b09FwReleaseMinor; 4330179771Sdavidch fw.ver_fix = bce_TXP_b09FwReleaseFix; 4331179771Sdavidch fw.start_addr = bce_TXP_b09FwStartAddr; 4332157642Sps 4333179771Sdavidch fw.text_addr = bce_TXP_b09FwTextAddr; 4334179771Sdavidch fw.text_len = bce_TXP_b09FwTextLen; 4335179771Sdavidch fw.text_index = 0; 4336179771Sdavidch fw.text = bce_TXP_b09FwText; 4337157642Sps 4338179771Sdavidch fw.data_addr = bce_TXP_b09FwDataAddr; 4339179771Sdavidch fw.data_len = bce_TXP_b09FwDataLen; 4340179771Sdavidch fw.data_index = 0; 4341179771Sdavidch fw.data = bce_TXP_b09FwData; 4342157642Sps 4343179771Sdavidch fw.sbss_addr = bce_TXP_b09FwSbssAddr; 4344179771Sdavidch fw.sbss_len = bce_TXP_b09FwSbssLen; 4345179771Sdavidch fw.sbss_index = 0; 4346179771Sdavidch fw.sbss = bce_TXP_b09FwSbss; 4347157642Sps 4348179771Sdavidch fw.bss_addr = bce_TXP_b09FwBssAddr; 4349179771Sdavidch fw.bss_len = bce_TXP_b09FwBssLen; 4350179771Sdavidch fw.bss_index = 0; 4351179771Sdavidch fw.bss = bce_TXP_b09FwBss; 4352157642Sps 4353179771Sdavidch fw.rodata_addr = bce_TXP_b09FwRodataAddr; 4354179771Sdavidch fw.rodata_len = bce_TXP_b09FwRodataLen; 4355179771Sdavidch fw.rodata_index = 0; 4356179771Sdavidch fw.rodata = bce_TXP_b09FwRodata; 4357179771Sdavidch } else { 4358179771Sdavidch fw.ver_major = bce_TXP_b06FwReleaseMajor; 4359179771Sdavidch fw.ver_minor = bce_TXP_b06FwReleaseMinor; 4360179771Sdavidch fw.ver_fix = bce_TXP_b06FwReleaseFix; 4361179771Sdavidch fw.start_addr = bce_TXP_b06FwStartAddr; 4362157642Sps 4363179771Sdavidch fw.text_addr = bce_TXP_b06FwTextAddr; 4364179771Sdavidch fw.text_len = bce_TXP_b06FwTextLen; 4365179771Sdavidch fw.text_index = 0; 4366179771Sdavidch fw.text = bce_TXP_b06FwText; 4367179771Sdavidch 4368179771Sdavidch fw.data_addr = bce_TXP_b06FwDataAddr; 4369179771Sdavidch fw.data_len = bce_TXP_b06FwDataLen; 4370179771Sdavidch fw.data_index = 0; 4371179771Sdavidch fw.data = bce_TXP_b06FwData; 4372179771Sdavidch 4373179771Sdavidch fw.sbss_addr = bce_TXP_b06FwSbssAddr; 4374179771Sdavidch fw.sbss_len = bce_TXP_b06FwSbssLen; 4375179771Sdavidch fw.sbss_index = 0; 4376179771Sdavidch fw.sbss = bce_TXP_b06FwSbss; 4377179771Sdavidch 4378179771Sdavidch fw.bss_addr = bce_TXP_b06FwBssAddr; 4379179771Sdavidch fw.bss_len = bce_TXP_b06FwBssLen; 4380179771Sdavidch fw.bss_index = 0; 4381179771Sdavidch fw.bss = bce_TXP_b06FwBss; 4382179771Sdavidch 4383179771Sdavidch fw.rodata_addr = bce_TXP_b06FwRodataAddr; 4384179771Sdavidch fw.rodata_len = bce_TXP_b06FwRodataLen; 4385179771Sdavidch fw.rodata_index = 0; 4386179771Sdavidch fw.rodata = bce_TXP_b06FwRodata; 4387179771Sdavidch } 4388179771Sdavidch 4389157642Sps DBPRINT(sc, BCE_INFO_RESET, "Loading TX firmware.\n"); 4390157642Sps bce_load_cpu_fw(sc, &cpu_reg, &fw); 4391202717Sdavidch bce_start_cpu(sc, &cpu_reg); 4392157642Sps 4393179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4394179771Sdavidch} 4395179771Sdavidch 4396179771Sdavidch 4397179771Sdavidch/****************************************************************************/ 4398179771Sdavidch/* Initialize the TPAT CPU. */ 4399179771Sdavidch/* */ 4400179771Sdavidch/* Returns: */ 4401179771Sdavidch/* Nothing. */ 4402179771Sdavidch/****************************************************************************/ 4403179771Sdavidchstatic void 4404179771Sdavidchbce_init_tpat_cpu(struct bce_softc *sc) 4405179771Sdavidch{ 4406179771Sdavidch struct cpu_reg cpu_reg; 4407179771Sdavidch struct fw_info fw; 4408179771Sdavidch 4409179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4410179771Sdavidch 4411157642Sps cpu_reg.mode = BCE_TPAT_CPU_MODE; 4412157642Sps cpu_reg.mode_value_halt = BCE_TPAT_CPU_MODE_SOFT_HALT; 4413157642Sps cpu_reg.mode_value_sstep = BCE_TPAT_CPU_MODE_STEP_ENA; 4414157642Sps cpu_reg.state = BCE_TPAT_CPU_STATE; 4415157642Sps cpu_reg.state_value_clear = 0xffffff; 4416157642Sps cpu_reg.gpr0 = BCE_TPAT_CPU_REG_FILE; 4417157642Sps cpu_reg.evmask = BCE_TPAT_CPU_EVENT_MASK; 4418157642Sps cpu_reg.pc = BCE_TPAT_CPU_PROGRAM_COUNTER; 4419157642Sps cpu_reg.inst = BCE_TPAT_CPU_INSTRUCTION; 4420157642Sps cpu_reg.bp = BCE_TPAT_CPU_HW_BREAKPOINT; 4421157642Sps cpu_reg.spad_base = BCE_TPAT_SCRATCH; 4422157642Sps cpu_reg.mips_view_base = 0x8000000; 4423157642Sps 4424226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 4425179771Sdavidch fw.ver_major = bce_TPAT_b09FwReleaseMajor; 4426179771Sdavidch fw.ver_minor = bce_TPAT_b09FwReleaseMinor; 4427179771Sdavidch fw.ver_fix = bce_TPAT_b09FwReleaseFix; 4428179771Sdavidch fw.start_addr = bce_TPAT_b09FwStartAddr; 4429157642Sps 4430179771Sdavidch fw.text_addr = bce_TPAT_b09FwTextAddr; 4431179771Sdavidch fw.text_len = bce_TPAT_b09FwTextLen; 4432179771Sdavidch fw.text_index = 0; 4433179771Sdavidch fw.text = bce_TPAT_b09FwText; 4434157642Sps 4435179771Sdavidch fw.data_addr = bce_TPAT_b09FwDataAddr; 4436179771Sdavidch fw.data_len = bce_TPAT_b09FwDataLen; 4437179771Sdavidch fw.data_index = 0; 4438179771Sdavidch fw.data = bce_TPAT_b09FwData; 4439157642Sps 4440179771Sdavidch fw.sbss_addr = bce_TPAT_b09FwSbssAddr; 4441179771Sdavidch fw.sbss_len = bce_TPAT_b09FwSbssLen; 4442179771Sdavidch fw.sbss_index = 0; 4443179771Sdavidch fw.sbss = bce_TPAT_b09FwSbss; 4444157642Sps 4445179771Sdavidch fw.bss_addr = bce_TPAT_b09FwBssAddr; 4446179771Sdavidch fw.bss_len = bce_TPAT_b09FwBssLen; 4447179771Sdavidch fw.bss_index = 0; 4448179771Sdavidch fw.bss = bce_TPAT_b09FwBss; 4449157642Sps 4450179771Sdavidch fw.rodata_addr = bce_TPAT_b09FwRodataAddr; 4451179771Sdavidch fw.rodata_len = bce_TPAT_b09FwRodataLen; 4452179771Sdavidch fw.rodata_index = 0; 4453179771Sdavidch fw.rodata = bce_TPAT_b09FwRodata; 4454179771Sdavidch } else { 4455179771Sdavidch fw.ver_major = bce_TPAT_b06FwReleaseMajor; 4456179771Sdavidch fw.ver_minor = bce_TPAT_b06FwReleaseMinor; 4457179771Sdavidch fw.ver_fix = bce_TPAT_b06FwReleaseFix; 4458179771Sdavidch fw.start_addr = bce_TPAT_b06FwStartAddr; 4459157642Sps 4460179771Sdavidch fw.text_addr = bce_TPAT_b06FwTextAddr; 4461179771Sdavidch fw.text_len = bce_TPAT_b06FwTextLen; 4462179771Sdavidch fw.text_index = 0; 4463179771Sdavidch fw.text = bce_TPAT_b06FwText; 4464157642Sps 4465179771Sdavidch fw.data_addr = bce_TPAT_b06FwDataAddr; 4466179771Sdavidch fw.data_len = bce_TPAT_b06FwDataLen; 4467179771Sdavidch fw.data_index = 0; 4468179771Sdavidch fw.data = bce_TPAT_b06FwData; 4469157642Sps 4470179771Sdavidch fw.sbss_addr = bce_TPAT_b06FwSbssAddr; 4471179771Sdavidch fw.sbss_len = bce_TPAT_b06FwSbssLen; 4472179771Sdavidch fw.sbss_index = 0; 4473179771Sdavidch fw.sbss = bce_TPAT_b06FwSbss; 4474157642Sps 4475179771Sdavidch fw.bss_addr = bce_TPAT_b06FwBssAddr; 4476179771Sdavidch fw.bss_len = bce_TPAT_b06FwBssLen; 4477179771Sdavidch fw.bss_index = 0; 4478179771Sdavidch fw.bss = bce_TPAT_b06FwBss; 4479157642Sps 4480179771Sdavidch fw.rodata_addr = bce_TPAT_b06FwRodataAddr; 4481179771Sdavidch fw.rodata_len = bce_TPAT_b06FwRodataLen; 4482179771Sdavidch fw.rodata_index = 0; 4483179771Sdavidch fw.rodata = bce_TPAT_b06FwRodata; 4484179771Sdavidch } 4485157642Sps 4486179771Sdavidch DBPRINT(sc, BCE_INFO_RESET, "Loading TPAT firmware.\n"); 4487179771Sdavidch bce_load_cpu_fw(sc, &cpu_reg, &fw); 4488206268Sdavidch bce_start_cpu(sc, &cpu_reg); 4489157642Sps 4490179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4491179771Sdavidch} 4492157642Sps 4493157642Sps 4494179771Sdavidch/****************************************************************************/ 4495179771Sdavidch/* Initialize the CP CPU. */ 4496179771Sdavidch/* */ 4497179771Sdavidch/* Returns: */ 4498179771Sdavidch/* Nothing. */ 4499179771Sdavidch/****************************************************************************/ 4500179771Sdavidchstatic void 4501179771Sdavidchbce_init_cp_cpu(struct bce_softc *sc) 4502179771Sdavidch{ 4503179771Sdavidch struct cpu_reg cpu_reg; 4504179771Sdavidch struct fw_info fw; 4505176448Sdavidch 4506179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4507179771Sdavidch 4508176448Sdavidch cpu_reg.mode = BCE_CP_CPU_MODE; 4509176448Sdavidch cpu_reg.mode_value_halt = BCE_CP_CPU_MODE_SOFT_HALT; 4510176448Sdavidch cpu_reg.mode_value_sstep = BCE_CP_CPU_MODE_STEP_ENA; 4511176448Sdavidch cpu_reg.state = BCE_CP_CPU_STATE; 4512176448Sdavidch cpu_reg.state_value_clear = 0xffffff; 4513176448Sdavidch cpu_reg.gpr0 = BCE_CP_CPU_REG_FILE; 4514176448Sdavidch cpu_reg.evmask = BCE_CP_CPU_EVENT_MASK; 4515176448Sdavidch cpu_reg.pc = BCE_CP_CPU_PROGRAM_COUNTER; 4516176448Sdavidch cpu_reg.inst = BCE_CP_CPU_INSTRUCTION; 4517176448Sdavidch cpu_reg.bp = BCE_CP_CPU_HW_BREAKPOINT; 4518176448Sdavidch cpu_reg.spad_base = BCE_CP_SCRATCH; 4519176448Sdavidch cpu_reg.mips_view_base = 0x8000000; 4520176448Sdavidch 4521226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 4522179771Sdavidch fw.ver_major = bce_CP_b09FwReleaseMajor; 4523179771Sdavidch fw.ver_minor = bce_CP_b09FwReleaseMinor; 4524179771Sdavidch fw.ver_fix = bce_CP_b09FwReleaseFix; 4525179771Sdavidch fw.start_addr = bce_CP_b09FwStartAddr; 4526176448Sdavidch 4527179771Sdavidch fw.text_addr = bce_CP_b09FwTextAddr; 4528179771Sdavidch fw.text_len = bce_CP_b09FwTextLen; 4529179771Sdavidch fw.text_index = 0; 4530179771Sdavidch fw.text = bce_CP_b09FwText; 4531176448Sdavidch 4532179771Sdavidch fw.data_addr = bce_CP_b09FwDataAddr; 4533179771Sdavidch fw.data_len = bce_CP_b09FwDataLen; 4534179771Sdavidch fw.data_index = 0; 4535179771Sdavidch fw.data = bce_CP_b09FwData; 4536176448Sdavidch 4537179771Sdavidch fw.sbss_addr = bce_CP_b09FwSbssAddr; 4538179771Sdavidch fw.sbss_len = bce_CP_b09FwSbssLen; 4539179771Sdavidch fw.sbss_index = 0; 4540179771Sdavidch fw.sbss = bce_CP_b09FwSbss; 4541176448Sdavidch 4542179771Sdavidch fw.bss_addr = bce_CP_b09FwBssAddr; 4543179771Sdavidch fw.bss_len = bce_CP_b09FwBssLen; 4544179771Sdavidch fw.bss_index = 0; 4545179771Sdavidch fw.bss = bce_CP_b09FwBss; 4546176448Sdavidch 4547179771Sdavidch fw.rodata_addr = bce_CP_b09FwRodataAddr; 4548179771Sdavidch fw.rodata_len = bce_CP_b09FwRodataLen; 4549179771Sdavidch fw.rodata_index = 0; 4550179771Sdavidch fw.rodata = bce_CP_b09FwRodata; 4551179771Sdavidch } else { 4552179771Sdavidch fw.ver_major = bce_CP_b06FwReleaseMajor; 4553179771Sdavidch fw.ver_minor = bce_CP_b06FwReleaseMinor; 4554179771Sdavidch fw.ver_fix = bce_CP_b06FwReleaseFix; 4555179771Sdavidch fw.start_addr = bce_CP_b06FwStartAddr; 4556176448Sdavidch 4557179771Sdavidch fw.text_addr = bce_CP_b06FwTextAddr; 4558179771Sdavidch fw.text_len = bce_CP_b06FwTextLen; 4559179771Sdavidch fw.text_index = 0; 4560179771Sdavidch fw.text = bce_CP_b06FwText; 4561179771Sdavidch 4562179771Sdavidch fw.data_addr = bce_CP_b06FwDataAddr; 4563179771Sdavidch fw.data_len = bce_CP_b06FwDataLen; 4564179771Sdavidch fw.data_index = 0; 4565179771Sdavidch fw.data = bce_CP_b06FwData; 4566179771Sdavidch 4567179771Sdavidch fw.sbss_addr = bce_CP_b06FwSbssAddr; 4568179771Sdavidch fw.sbss_len = bce_CP_b06FwSbssLen; 4569179771Sdavidch fw.sbss_index = 0; 4570179771Sdavidch fw.sbss = bce_CP_b06FwSbss; 4571179771Sdavidch 4572179771Sdavidch fw.bss_addr = bce_CP_b06FwBssAddr; 4573179771Sdavidch fw.bss_len = bce_CP_b06FwBssLen; 4574179771Sdavidch fw.bss_index = 0; 4575179771Sdavidch fw.bss = bce_CP_b06FwBss; 4576179771Sdavidch 4577179771Sdavidch fw.rodata_addr = bce_CP_b06FwRodataAddr; 4578179771Sdavidch fw.rodata_len = bce_CP_b06FwRodataLen; 4579179771Sdavidch fw.rodata_index = 0; 4580179771Sdavidch fw.rodata = bce_CP_b06FwRodata; 4581179771Sdavidch } 4582179771Sdavidch 4583176448Sdavidch DBPRINT(sc, BCE_INFO_RESET, "Loading CP firmware.\n"); 4584176448Sdavidch bce_load_cpu_fw(sc, &cpu_reg, &fw); 4585206268Sdavidch bce_start_cpu(sc, &cpu_reg); 4586179771Sdavidch 4587179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4588157642Sps} 4589157642Sps 4590157642Sps 4591157642Sps/****************************************************************************/ 4592179771Sdavidch/* Initialize the COM CPU. */ 4593179771Sdavidch/* */ 4594179771Sdavidch/* Returns: */ 4595179771Sdavidch/* Nothing. */ 4596179771Sdavidch/****************************************************************************/ 4597179771Sdavidchstatic void 4598179771Sdavidchbce_init_com_cpu(struct bce_softc *sc) 4599179771Sdavidch{ 4600179771Sdavidch struct cpu_reg cpu_reg; 4601179771Sdavidch struct fw_info fw; 4602179771Sdavidch 4603179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4604179771Sdavidch 4605179771Sdavidch cpu_reg.mode = BCE_COM_CPU_MODE; 4606179771Sdavidch cpu_reg.mode_value_halt = BCE_COM_CPU_MODE_SOFT_HALT; 4607179771Sdavidch cpu_reg.mode_value_sstep = BCE_COM_CPU_MODE_STEP_ENA; 4608179771Sdavidch cpu_reg.state = BCE_COM_CPU_STATE; 4609179771Sdavidch cpu_reg.state_value_clear = 0xffffff; 4610179771Sdavidch cpu_reg.gpr0 = BCE_COM_CPU_REG_FILE; 4611179771Sdavidch cpu_reg.evmask = BCE_COM_CPU_EVENT_MASK; 4612179771Sdavidch cpu_reg.pc = BCE_COM_CPU_PROGRAM_COUNTER; 4613179771Sdavidch cpu_reg.inst = BCE_COM_CPU_INSTRUCTION; 4614179771Sdavidch cpu_reg.bp = BCE_COM_CPU_HW_BREAKPOINT; 4615179771Sdavidch cpu_reg.spad_base = BCE_COM_SCRATCH; 4616179771Sdavidch cpu_reg.mips_view_base = 0x8000000; 4617179771Sdavidch 4618226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 4619179771Sdavidch fw.ver_major = bce_COM_b09FwReleaseMajor; 4620179771Sdavidch fw.ver_minor = bce_COM_b09FwReleaseMinor; 4621179771Sdavidch fw.ver_fix = bce_COM_b09FwReleaseFix; 4622179771Sdavidch fw.start_addr = bce_COM_b09FwStartAddr; 4623179771Sdavidch 4624179771Sdavidch fw.text_addr = bce_COM_b09FwTextAddr; 4625179771Sdavidch fw.text_len = bce_COM_b09FwTextLen; 4626179771Sdavidch fw.text_index = 0; 4627179771Sdavidch fw.text = bce_COM_b09FwText; 4628179771Sdavidch 4629179771Sdavidch fw.data_addr = bce_COM_b09FwDataAddr; 4630179771Sdavidch fw.data_len = bce_COM_b09FwDataLen; 4631179771Sdavidch fw.data_index = 0; 4632179771Sdavidch fw.data = bce_COM_b09FwData; 4633179771Sdavidch 4634179771Sdavidch fw.sbss_addr = bce_COM_b09FwSbssAddr; 4635179771Sdavidch fw.sbss_len = bce_COM_b09FwSbssLen; 4636179771Sdavidch fw.sbss_index = 0; 4637179771Sdavidch fw.sbss = bce_COM_b09FwSbss; 4638179771Sdavidch 4639179771Sdavidch fw.bss_addr = bce_COM_b09FwBssAddr; 4640179771Sdavidch fw.bss_len = bce_COM_b09FwBssLen; 4641179771Sdavidch fw.bss_index = 0; 4642179771Sdavidch fw.bss = bce_COM_b09FwBss; 4643179771Sdavidch 4644179771Sdavidch fw.rodata_addr = bce_COM_b09FwRodataAddr; 4645179771Sdavidch fw.rodata_len = bce_COM_b09FwRodataLen; 4646179771Sdavidch fw.rodata_index = 0; 4647179771Sdavidch fw.rodata = bce_COM_b09FwRodata; 4648179771Sdavidch } else { 4649179771Sdavidch fw.ver_major = bce_COM_b06FwReleaseMajor; 4650179771Sdavidch fw.ver_minor = bce_COM_b06FwReleaseMinor; 4651179771Sdavidch fw.ver_fix = bce_COM_b06FwReleaseFix; 4652179771Sdavidch fw.start_addr = bce_COM_b06FwStartAddr; 4653179771Sdavidch 4654179771Sdavidch fw.text_addr = bce_COM_b06FwTextAddr; 4655179771Sdavidch fw.text_len = bce_COM_b06FwTextLen; 4656179771Sdavidch fw.text_index = 0; 4657179771Sdavidch fw.text = bce_COM_b06FwText; 4658179771Sdavidch 4659179771Sdavidch fw.data_addr = bce_COM_b06FwDataAddr; 4660179771Sdavidch fw.data_len = bce_COM_b06FwDataLen; 4661179771Sdavidch fw.data_index = 0; 4662179771Sdavidch fw.data = bce_COM_b06FwData; 4663179771Sdavidch 4664179771Sdavidch fw.sbss_addr = bce_COM_b06FwSbssAddr; 4665179771Sdavidch fw.sbss_len = bce_COM_b06FwSbssLen; 4666179771Sdavidch fw.sbss_index = 0; 4667179771Sdavidch fw.sbss = bce_COM_b06FwSbss; 4668179771Sdavidch 4669179771Sdavidch fw.bss_addr = bce_COM_b06FwBssAddr; 4670179771Sdavidch fw.bss_len = bce_COM_b06FwBssLen; 4671179771Sdavidch fw.bss_index = 0; 4672179771Sdavidch fw.bss = bce_COM_b06FwBss; 4673179771Sdavidch 4674179771Sdavidch fw.rodata_addr = bce_COM_b06FwRodataAddr; 4675179771Sdavidch fw.rodata_len = bce_COM_b06FwRodataLen; 4676179771Sdavidch fw.rodata_index = 0; 4677179771Sdavidch fw.rodata = bce_COM_b06FwRodata; 4678179771Sdavidch } 4679179771Sdavidch 4680179771Sdavidch DBPRINT(sc, BCE_INFO_RESET, "Loading COM firmware.\n"); 4681179771Sdavidch bce_load_cpu_fw(sc, &cpu_reg, &fw); 4682206268Sdavidch bce_start_cpu(sc, &cpu_reg); 4683179771Sdavidch 4684179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4685179771Sdavidch} 4686179771Sdavidch 4687179771Sdavidch 4688179771Sdavidch/****************************************************************************/ 4689179771Sdavidch/* Initialize the RV2P, RX, TX, TPAT, COM, and CP CPUs. */ 4690179771Sdavidch/* */ 4691179771Sdavidch/* Loads the firmware for each CPU and starts the CPU. */ 4692179771Sdavidch/* */ 4693179771Sdavidch/* Returns: */ 4694179771Sdavidch/* Nothing. */ 4695179771Sdavidch/****************************************************************************/ 4696179771Sdavidchstatic void 4697179771Sdavidchbce_init_cpus(struct bce_softc *sc) 4698179771Sdavidch{ 4699179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4700179771Sdavidch 4701226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 4702189325Sdavidch 4703189325Sdavidch if ((BCE_CHIP_REV(sc) == BCE_CHIP_REV_Ax)) { 4704207411Sdavidch bce_load_rv2p_fw(sc, bce_xi90_rv2p_proc1, 4705207411Sdavidch sizeof(bce_xi90_rv2p_proc1), RV2P_PROC1); 4706207411Sdavidch bce_load_rv2p_fw(sc, bce_xi90_rv2p_proc2, 4707207411Sdavidch sizeof(bce_xi90_rv2p_proc2), RV2P_PROC2); 4708189325Sdavidch } else { 4709207411Sdavidch bce_load_rv2p_fw(sc, bce_xi_rv2p_proc1, 4710207411Sdavidch sizeof(bce_xi_rv2p_proc1), RV2P_PROC1); 4711207411Sdavidch bce_load_rv2p_fw(sc, bce_xi_rv2p_proc2, 4712207411Sdavidch sizeof(bce_xi_rv2p_proc2), RV2P_PROC2); 4713189325Sdavidch } 4714189325Sdavidch 4715179771Sdavidch } else { 4716207411Sdavidch bce_load_rv2p_fw(sc, bce_rv2p_proc1, 4717207411Sdavidch sizeof(bce_rv2p_proc1), RV2P_PROC1); 4718189325Sdavidch bce_load_rv2p_fw(sc, bce_rv2p_proc2, 4719207411Sdavidch sizeof(bce_rv2p_proc2), RV2P_PROC2); 4720179771Sdavidch } 4721179771Sdavidch 4722179771Sdavidch bce_init_rxp_cpu(sc); 4723179771Sdavidch bce_init_txp_cpu(sc); 4724179771Sdavidch bce_init_tpat_cpu(sc); 4725179771Sdavidch bce_init_com_cpu(sc); 4726179771Sdavidch bce_init_cp_cpu(sc); 4727179771Sdavidch 4728179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4729179771Sdavidch} 4730179771Sdavidch 4731179771Sdavidch 4732179771Sdavidch/****************************************************************************/ 4733157642Sps/* Initialize context memory. */ 4734157642Sps/* */ 4735157642Sps/* Clears the memory associated with each Context ID (CID). */ 4736157642Sps/* */ 4737157642Sps/* Returns: */ 4738157642Sps/* Nothing. */ 4739157642Sps/****************************************************************************/ 4740210259Syongaristatic int 4741176448Sdavidchbce_init_ctx(struct bce_softc *sc) 4742157642Sps{ 4743210259Syongari u32 offset, val, vcid_addr; 4744210259Syongari int i, j, rc, retry_cnt; 4745157642Sps 4746210259Syongari rc = 0; 4747179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX); 4748157642Sps 4749226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 4750210259Syongari retry_cnt = CTX_INIT_RETRY_COUNT; 4751157642Sps 4752179771Sdavidch DBPRINT(sc, BCE_INFO_CTX, "Initializing 5709 context.\n"); 4753157642Sps 4754179771Sdavidch /* 4755179771Sdavidch * BCM5709 context memory may be cached 4756179771Sdavidch * in host memory so prepare the host memory 4757179771Sdavidch * for access. 4758179771Sdavidch */ 4759207411Sdavidch val = BCE_CTX_COMMAND_ENABLED | 4760206268Sdavidch BCE_CTX_COMMAND_MEM_INIT | (1 << 12); 4761179771Sdavidch val |= (BCM_PAGE_BITS - 8) << 16; 4762179771Sdavidch REG_WR(sc, BCE_CTX_COMMAND, val); 4763157642Sps 4764179771Sdavidch /* Wait for mem init command to complete. */ 4765179771Sdavidch for (i = 0; i < retry_cnt; i++) { 4766179771Sdavidch val = REG_RD(sc, BCE_CTX_COMMAND); 4767179771Sdavidch if (!(val & BCE_CTX_COMMAND_MEM_INIT)) 4768179771Sdavidch break; 4769179771Sdavidch DELAY(2); 4770179771Sdavidch } 4771210259Syongari if ((val & BCE_CTX_COMMAND_MEM_INIT) != 0) { 4772210259Syongari BCE_PRINTF("%s(): Context memory initialization failed!\n", 4773210259Syongari __FUNCTION__); 4774210259Syongari rc = EBUSY; 4775210259Syongari goto init_ctx_fail; 4776210259Syongari } 4777182293Sdavidch 4778179771Sdavidch for (i = 0; i < sc->ctx_pages; i++) { 4779206268Sdavidch /* Set the physical address of the context memory. */ 4780179771Sdavidch REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_DATA0, 4781206268Sdavidch BCE_ADDR_LO(sc->ctx_paddr[i] & 0xfffffff0) | 4782206268Sdavidch BCE_CTX_HOST_PAGE_TBL_DATA0_VALID); 4783179771Sdavidch REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_DATA1, 4784206268Sdavidch BCE_ADDR_HI(sc->ctx_paddr[i])); 4785179771Sdavidch REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_CTRL, i | 4786206268Sdavidch BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ); 4787179771Sdavidch 4788206268Sdavidch /* Verify the context memory write was successful. */ 4789179771Sdavidch for (j = 0; j < retry_cnt; j++) { 4790179771Sdavidch val = REG_RD(sc, BCE_CTX_HOST_PAGE_TBL_CTRL); 4791207411Sdavidch if ((val & 4792206268Sdavidch BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) == 0) 4793179771Sdavidch break; 4794179771Sdavidch DELAY(5); 4795179771Sdavidch } 4796210259Syongari if ((val & BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) != 0) { 4797210259Syongari BCE_PRINTF("%s(): Failed to initialize " 4798210259Syongari "context page %d!\n", __FUNCTION__, i); 4799210259Syongari rc = EBUSY; 4800210259Syongari goto init_ctx_fail; 4801210259Syongari } 4802179771Sdavidch } 4803179771Sdavidch } else { 4804179771Sdavidch 4805179771Sdavidch DBPRINT(sc, BCE_INFO, "Initializing 5706/5708 context.\n"); 4806179771Sdavidch 4807179771Sdavidch /* 4808179771Sdavidch * For the 5706/5708, context memory is local to 4809179771Sdavidch * the controller, so initialize the controller 4810179771Sdavidch * context memory. 4811179771Sdavidch */ 4812179771Sdavidch 4813179771Sdavidch vcid_addr = GET_CID_ADDR(96); 4814179771Sdavidch while (vcid_addr) { 4815179771Sdavidch 4816179771Sdavidch vcid_addr -= PHY_CTX_SIZE; 4817179771Sdavidch 4818179771Sdavidch REG_WR(sc, BCE_CTX_VIRT_ADDR, 0); 4819179771Sdavidch REG_WR(sc, BCE_CTX_PAGE_TBL, vcid_addr); 4820179771Sdavidch 4821206268Sdavidch for(offset = 0; offset < PHY_CTX_SIZE; offset += 4) { 4822206268Sdavidch CTX_WR(sc, 0x00, offset, 0); 4823206268Sdavidch } 4824179771Sdavidch 4825176448Sdavidch REG_WR(sc, BCE_CTX_VIRT_ADDR, vcid_addr); 4826179771Sdavidch REG_WR(sc, BCE_CTX_PAGE_TBL, vcid_addr); 4827179771Sdavidch } 4828176448Sdavidch 4829157642Sps } 4830210259Syongariinit_ctx_fail: 4831179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX); 4832210259Syongari return (rc); 4833157642Sps} 4834157642Sps 4835182293Sdavidch 4836157642Sps/****************************************************************************/ 4837157642Sps/* Fetch the permanent MAC address of the controller. */ 4838157642Sps/* */ 4839157642Sps/* Returns: */ 4840157642Sps/* Nothing. */ 4841157642Sps/****************************************************************************/ 4842157642Spsstatic void 4843157642Spsbce_get_mac_addr(struct bce_softc *sc) 4844157642Sps{ 4845157642Sps u32 mac_lo = 0, mac_hi = 0; 4846157642Sps 4847179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4848207411Sdavidch 4849157642Sps /* 4850157642Sps * The NetXtreme II bootcode populates various NIC 4851157642Sps * power-on and runtime configuration items in a 4852157642Sps * shared memory area. The factory configured MAC 4853157642Sps * address is available from both NVRAM and the 4854157642Sps * shared memory area so we'll read the value from 4855157642Sps * shared memory for speed. 4856157642Sps */ 4857157642Sps 4858194781Sdavidch mac_hi = bce_shmem_rd(sc, BCE_PORT_HW_CFG_MAC_UPPER); 4859194781Sdavidch mac_lo = bce_shmem_rd(sc, BCE_PORT_HW_CFG_MAC_LOWER); 4860157642Sps 4861157642Sps if ((mac_lo == 0) && (mac_hi == 0)) { 4862179771Sdavidch BCE_PRINTF("%s(%d): Invalid Ethernet address!\n", 4863207411Sdavidch __FILE__, __LINE__); 4864157642Sps } else { 4865157642Sps sc->eaddr[0] = (u_char)(mac_hi >> 8); 4866157642Sps sc->eaddr[1] = (u_char)(mac_hi >> 0); 4867157642Sps sc->eaddr[2] = (u_char)(mac_lo >> 24); 4868157642Sps sc->eaddr[3] = (u_char)(mac_lo >> 16); 4869157642Sps sc->eaddr[4] = (u_char)(mac_lo >> 8); 4870157642Sps sc->eaddr[5] = (u_char)(mac_lo >> 0); 4871157642Sps } 4872157642Sps 4873207411Sdavidch DBPRINT(sc, BCE_INFO_MISC, "Permanent Ethernet " 4874207411Sdavidch "address = %6D\n", sc->eaddr, ":"); 4875179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4876157642Sps} 4877157642Sps 4878157642Sps 4879157642Sps/****************************************************************************/ 4880157642Sps/* Program the MAC address. */ 4881157642Sps/* */ 4882157642Sps/* Returns: */ 4883157642Sps/* Nothing. */ 4884157642Sps/****************************************************************************/ 4885157642Spsstatic void 4886157642Spsbce_set_mac_addr(struct bce_softc *sc) 4887157642Sps{ 4888157642Sps u32 val; 4889157642Sps u8 *mac_addr = sc->eaddr; 4890157642Sps 4891179771Sdavidch /* ToDo: Add support for setting multiple MAC addresses. */ 4892179771Sdavidch 4893179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4894207411Sdavidch DBPRINT(sc, BCE_INFO_MISC, "Setting Ethernet address = " 4895207411Sdavidch "%6D\n", sc->eaddr, ":"); 4896157642Sps 4897157642Sps val = (mac_addr[0] << 8) | mac_addr[1]; 4898157642Sps 4899157642Sps REG_WR(sc, BCE_EMAC_MAC_MATCH0, val); 4900157642Sps 4901157642Sps val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | 4902207411Sdavidch (mac_addr[4] << 8) | mac_addr[5]; 4903157642Sps 4904157642Sps REG_WR(sc, BCE_EMAC_MAC_MATCH1, val); 4905179771Sdavidch 4906179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4907157642Sps} 4908157642Sps 4909157642Sps 4910157642Sps/****************************************************************************/ 4911157642Sps/* Stop the controller. */ 4912157642Sps/* */ 4913157642Sps/* Returns: */ 4914157642Sps/* Nothing. */ 4915157642Sps/****************************************************************************/ 4916157642Spsstatic void 4917157642Spsbce_stop(struct bce_softc *sc) 4918157642Sps{ 4919157642Sps struct ifnet *ifp; 4920157642Sps 4921179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4922157642Sps 4923157642Sps BCE_LOCK_ASSERT(sc); 4924157642Sps 4925157642Sps ifp = sc->bce_ifp; 4926157642Sps 4927170810Sdavidch callout_stop(&sc->bce_tick_callout); 4928157642Sps 4929157642Sps /* Disable the transmit/receive blocks. */ 4930179771Sdavidch REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS, BCE_MISC_ENABLE_CLR_DEFAULT); 4931157642Sps REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS); 4932157642Sps DELAY(20); 4933157642Sps 4934157642Sps bce_disable_intr(sc); 4935157642Sps 4936171667Sdavidch /* Free RX buffers. */ 4937218423Sdavidch if (bce_hdr_split == TRUE) { 4938218423Sdavidch bce_free_pg_chain(sc); 4939218423Sdavidch } 4940157642Sps bce_free_rx_chain(sc); 4941157642Sps 4942157642Sps /* Free TX buffers. */ 4943157642Sps bce_free_tx_chain(sc); 4944157642Sps 4945165933Sdelphij sc->watchdog_timer = 0; 4946157642Sps 4947206268Sdavidch sc->bce_link_up = FALSE; 4948157642Sps 4949157642Sps ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 4950157642Sps 4951179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 4952157642Sps} 4953157642Sps 4954157642Sps 4955157642Spsstatic int 4956157642Spsbce_reset(struct bce_softc *sc, u32 reset_code) 4957157642Sps{ 4958235816Syongari u32 emac_mode_save, val; 4959157642Sps int i, rc = 0; 4960235816Syongari static const u32 emac_mode_mask = BCE_EMAC_MODE_PORT | 4961235816Syongari BCE_EMAC_MODE_HALF_DUPLEX | BCE_EMAC_MODE_25G; 4962157642Sps 4963179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 4964179771Sdavidch 4965179771Sdavidch DBPRINT(sc, BCE_VERBOSE_RESET, "%s(): reset_code = 0x%08X\n", 4966207411Sdavidch __FUNCTION__, reset_code); 4967157642Sps 4968235816Syongari /* 4969235816Syongari * If ASF/IPMI is operational, then the EMAC Mode register already 4970235816Syongari * contains appropriate values for the link settings that have 4971235816Syongari * been auto-negotiated. Resetting the chip will clobber those 4972235816Syongari * values. Save the important bits so we can restore them after 4973235816Syongari * the reset. 4974235816Syongari */ 4975235816Syongari emac_mode_save = REG_RD(sc, BCE_EMAC_MODE) & emac_mode_mask; 4976235816Syongari 4977157642Sps /* Wait for pending PCI transactions to complete. */ 4978157642Sps REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS, 4979207411Sdavidch BCE_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE | 4980207411Sdavidch BCE_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE | 4981207411Sdavidch BCE_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE | 4982207411Sdavidch BCE_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE); 4983157642Sps val = REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS); 4984157642Sps DELAY(5); 4985157642Sps 4986179771Sdavidch /* Disable DMA */ 4987226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 4988179771Sdavidch val = REG_RD(sc, BCE_MISC_NEW_CORE_CTL); 4989179771Sdavidch val &= ~BCE_MISC_NEW_CORE_CTL_DMA_ENABLE; 4990179771Sdavidch REG_WR(sc, BCE_MISC_NEW_CORE_CTL, val); 4991179771Sdavidch } 4992179771Sdavidch 4993157642Sps /* Assume bootcode is running. */ 4994206268Sdavidch sc->bce_fw_timed_out = FALSE; 4995206268Sdavidch sc->bce_drv_cardiac_arrest = FALSE; 4996157642Sps 4997157642Sps /* Give the firmware a chance to prepare for the reset. */ 4998157642Sps rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT0 | reset_code); 4999157642Sps if (rc) 5000157642Sps goto bce_reset_exit; 5001157642Sps 5002157642Sps /* Set a firmware reminder that this is a soft reset. */ 5003194781Sdavidch bce_shmem_wr(sc, BCE_DRV_RESET_SIGNATURE, BCE_DRV_RESET_SIGNATURE_MAGIC); 5004157642Sps 5005157642Sps /* Dummy read to force the chip to complete all current transactions. */ 5006157642Sps val = REG_RD(sc, BCE_MISC_ID); 5007157642Sps 5008157642Sps /* Chip reset. */ 5009226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 5010179771Sdavidch REG_WR(sc, BCE_MISC_COMMAND, BCE_MISC_COMMAND_SW_RESET); 5011179771Sdavidch REG_RD(sc, BCE_MISC_COMMAND); 5012179771Sdavidch DELAY(5); 5013157642Sps 5014179771Sdavidch val = BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA | 5015207411Sdavidch BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP; 5016179771Sdavidch 5017179771Sdavidch pci_write_config(sc->bce_dev, BCE_PCICFG_MISC_CONFIG, val, 4); 5018179771Sdavidch } else { 5019179771Sdavidch val = BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ | 5020207411Sdavidch BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA | 5021207411Sdavidch BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP; 5022179771Sdavidch REG_WR(sc, BCE_PCICFG_MISC_CONFIG, val); 5023179771Sdavidch 5024179771Sdavidch /* Allow up to 30us for reset to complete. */ 5025179771Sdavidch for (i = 0; i < 10; i++) { 5026179771Sdavidch val = REG_RD(sc, BCE_PCICFG_MISC_CONFIG); 5027179771Sdavidch if ((val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ | 5028207411Sdavidch BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0) { 5029179771Sdavidch break; 5030179771Sdavidch } 5031179771Sdavidch DELAY(10); 5032157642Sps } 5033157642Sps 5034179771Sdavidch /* Check that reset completed successfully. */ 5035179771Sdavidch if (val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ | 5036207411Sdavidch BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) { 5037179771Sdavidch BCE_PRINTF("%s(%d): Reset failed!\n", 5038207411Sdavidch __FILE__, __LINE__); 5039179771Sdavidch rc = EBUSY; 5040179771Sdavidch goto bce_reset_exit; 5041179771Sdavidch } 5042157642Sps } 5043157642Sps 5044157642Sps /* Make sure byte swapping is properly configured. */ 5045157642Sps val = REG_RD(sc, BCE_PCI_SWAP_DIAG0); 5046157642Sps if (val != 0x01020304) { 5047179771Sdavidch BCE_PRINTF("%s(%d): Byte swap is incorrect!\n", 5048207411Sdavidch __FILE__, __LINE__); 5049157642Sps rc = ENODEV; 5050157642Sps goto bce_reset_exit; 5051157642Sps } 5052157642Sps 5053157642Sps /* Just completed a reset, assume that firmware is running again. */ 5054206268Sdavidch sc->bce_fw_timed_out = FALSE; 5055206268Sdavidch sc->bce_drv_cardiac_arrest = FALSE; 5056157642Sps 5057157642Sps /* Wait for the firmware to finish its initialization. */ 5058157642Sps rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT1 | reset_code); 5059157642Sps if (rc) 5060207411Sdavidch BCE_PRINTF("%s(%d): Firmware did not complete " 5061207411Sdavidch "initialization!\n", __FILE__, __LINE__); 5062235151Syongari /* Get firmware capabilities. */ 5063235151Syongari bce_fw_cap_init(sc); 5064157642Sps 5065157642Spsbce_reset_exit: 5066235816Syongari /* Restore EMAC Mode bits needed to keep ASF/IPMI running. */ 5067257623Syongari if (reset_code == BCE_DRV_MSG_CODE_RESET) { 5068257623Syongari val = REG_RD(sc, BCE_EMAC_MODE); 5069257623Syongari val = (val & ~emac_mode_mask) | emac_mode_save; 5070257623Syongari REG_WR(sc, BCE_EMAC_MODE, val); 5071257623Syongari } 5072235816Syongari 5073179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 5074157642Sps return (rc); 5075157642Sps} 5076157642Sps 5077157642Sps 5078157642Spsstatic int 5079157642Spsbce_chipinit(struct bce_softc *sc) 5080157642Sps{ 5081157642Sps u32 val; 5082157642Sps int rc = 0; 5083157642Sps 5084179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 5085157642Sps 5086179771Sdavidch bce_disable_intr(sc); 5087157642Sps 5088179771Sdavidch /* 5089169632Sdavidch * Initialize DMA byte/word swapping, configure the number of DMA 5090170392Sdavidch * channels and PCI clock compensation delay. 5091169632Sdavidch */ 5092157642Sps val = BCE_DMA_CONFIG_DATA_BYTE_SWAP | 5093207411Sdavidch BCE_DMA_CONFIG_DATA_WORD_SWAP | 5094157642Sps#if BYTE_ORDER == BIG_ENDIAN 5095207411Sdavidch BCE_DMA_CONFIG_CNTL_BYTE_SWAP | 5096157642Sps#endif 5097207411Sdavidch BCE_DMA_CONFIG_CNTL_WORD_SWAP | 5098207411Sdavidch DMA_READ_CHANS << 12 | 5099207411Sdavidch DMA_WRITE_CHANS << 16; 5100157642Sps 5101157642Sps val |= (0x2 << 20) | BCE_DMA_CONFIG_CNTL_PCI_COMP_DLY; 5102157642Sps 5103157642Sps if ((sc->bce_flags & BCE_PCIX_FLAG) && (sc->bus_speed_mhz == 133)) 5104157642Sps val |= BCE_DMA_CONFIG_PCI_FAST_CLK_CMP; 5105157642Sps 5106157642Sps /* 5107157642Sps * This setting resolves a problem observed on certain Intel PCI 5108157642Sps * chipsets that cannot handle multiple outstanding DMA operations. 5109157642Sps * See errata E9_5706A1_65. 5110157642Sps */ 5111157642Sps if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) && 5112157642Sps (BCE_CHIP_ID(sc) != BCE_CHIP_ID_5706_A0) && 5113157642Sps !(sc->bce_flags & BCE_PCIX_FLAG)) 5114157642Sps val |= BCE_DMA_CONFIG_CNTL_PING_PONG_DMA; 5115157642Sps 5116157642Sps REG_WR(sc, BCE_DMA_CONFIG, val); 5117157642Sps 5118157642Sps /* Enable the RX_V2P and Context state machines before access. */ 5119157642Sps REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, 5120206268Sdavidch BCE_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE | 5121206268Sdavidch BCE_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE | 5122206268Sdavidch BCE_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE); 5123157642Sps 5124157642Sps /* Initialize context mapping and zero out the quick contexts. */ 5125210259Syongari if ((rc = bce_init_ctx(sc)) != 0) 5126210259Syongari goto bce_chipinit_exit; 5127157642Sps 5128157642Sps /* Initialize the on-boards CPUs */ 5129157642Sps bce_init_cpus(sc); 5130157642Sps 5131206268Sdavidch /* Enable management frames (NC-SI) to flow to the MCP. */ 5132206268Sdavidch if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) { 5133206268Sdavidch val = REG_RD(sc, BCE_RPM_MGMT_PKT_CTRL) | BCE_RPM_MGMT_PKT_CTRL_MGMT_EN; 5134206268Sdavidch REG_WR(sc, BCE_RPM_MGMT_PKT_CTRL, val); 5135206268Sdavidch } 5136202717Sdavidch 5137157642Sps /* Prepare NVRAM for access. */ 5138210257Syongari if ((rc = bce_init_nvram(sc)) != 0) 5139157642Sps goto bce_chipinit_exit; 5140157642Sps 5141157642Sps /* Set the kernel bypass block size */ 5142157642Sps val = REG_RD(sc, BCE_MQ_CONFIG); 5143157642Sps val &= ~BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE; 5144157642Sps val |= BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE_256; 5145179771Sdavidch 5146182293Sdavidch /* Enable bins used on the 5709. */ 5147226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 5148179771Sdavidch val |= BCE_MQ_CONFIG_BIN_MQ_MODE; 5149179771Sdavidch if (BCE_CHIP_ID(sc) == BCE_CHIP_ID_5709_A1) 5150179771Sdavidch val |= BCE_MQ_CONFIG_HALT_DIS; 5151179771Sdavidch } 5152179771Sdavidch 5153157642Sps REG_WR(sc, BCE_MQ_CONFIG, val); 5154157642Sps 5155157642Sps val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE); 5156157642Sps REG_WR(sc, BCE_MQ_KNL_BYP_WIND_START, val); 5157157642Sps REG_WR(sc, BCE_MQ_KNL_WIND_END, val); 5158170392Sdavidch 5159169271Sdavidch /* Set the page size and clear the RV2P processor stall bits. */ 5160157642Sps val = (BCM_PAGE_BITS - 8) << 24; 5161157642Sps REG_WR(sc, BCE_RV2P_CONFIG, val); 5162157642Sps 5163157642Sps /* Configure page size. */ 5164157642Sps val = REG_RD(sc, BCE_TBDR_CONFIG); 5165157642Sps val &= ~BCE_TBDR_CONFIG_PAGE_SIZE; 5166157642Sps val |= (BCM_PAGE_BITS - 8) << 24 | 0x40; 5167157642Sps REG_WR(sc, BCE_TBDR_CONFIG, val); 5168157642Sps 5169179771Sdavidch /* Set the perfect match control register to default. */ 5170179771Sdavidch REG_WR_IND(sc, BCE_RXP_PM_CTRL, 0); 5171179771Sdavidch 5172157642Spsbce_chipinit_exit: 5173179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 5174157642Sps 5175157642Sps return(rc); 5176157642Sps} 5177157642Sps 5178157642Sps 5179157642Sps/****************************************************************************/ 5180157642Sps/* Initialize the controller in preparation to send/receive traffic. */ 5181157642Sps/* */ 5182157642Sps/* Returns: */ 5183157642Sps/* 0 for success, positive value for failure. */ 5184157642Sps/****************************************************************************/ 5185157642Spsstatic int 5186157642Spsbce_blockinit(struct bce_softc *sc) 5187157642Sps{ 5188157642Sps u32 reg, val; 5189157642Sps int rc = 0; 5190157642Sps 5191179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 5192157642Sps 5193157642Sps /* Load the hardware default MAC address. */ 5194157642Sps bce_set_mac_addr(sc); 5195157642Sps 5196157642Sps /* Set the Ethernet backoff seed value */ 5197157642Sps val = sc->eaddr[0] + (sc->eaddr[1] << 8) + 5198157642Sps (sc->eaddr[2] << 16) + (sc->eaddr[3] ) + 5199157642Sps (sc->eaddr[4] << 8) + (sc->eaddr[5] << 16); 5200157642Sps REG_WR(sc, BCE_EMAC_BACKOFF_SEED, val); 5201157642Sps 5202157642Sps sc->last_status_idx = 0; 5203157642Sps sc->rx_mode = BCE_EMAC_RX_MODE_SORT_MODE; 5204157642Sps 5205157642Sps /* Set up link change interrupt generation. */ 5206157642Sps REG_WR(sc, BCE_EMAC_ATTENTION_ENA, BCE_EMAC_ATTENTION_ENA_LINK); 5207157642Sps 5208157642Sps /* Program the physical address of the status block. */ 5209157642Sps REG_WR(sc, BCE_HC_STATUS_ADDR_L, 5210206268Sdavidch BCE_ADDR_LO(sc->status_block_paddr)); 5211157642Sps REG_WR(sc, BCE_HC_STATUS_ADDR_H, 5212206268Sdavidch BCE_ADDR_HI(sc->status_block_paddr)); 5213157642Sps 5214157642Sps /* Program the physical address of the statistics block. */ 5215157642Sps REG_WR(sc, BCE_HC_STATISTICS_ADDR_L, 5216206268Sdavidch BCE_ADDR_LO(sc->stats_block_paddr)); 5217157642Sps REG_WR(sc, BCE_HC_STATISTICS_ADDR_H, 5218206268Sdavidch BCE_ADDR_HI(sc->stats_block_paddr)); 5219157642Sps 5220251142Smarius /* 5221251142Smarius * Program various host coalescing parameters. 5222251142Smarius * Trip points control how many BDs should be ready before generating 5223251142Smarius * an interrupt while ticks control how long a BD can sit in the chain 5224251142Smarius * before generating an interrupt. 5225251142Smarius */ 5226157642Sps REG_WR(sc, BCE_HC_TX_QUICK_CONS_TRIP, 5227251142Smarius (sc->bce_tx_quick_cons_trip_int << 16) | 5228251142Smarius sc->bce_tx_quick_cons_trip); 5229157642Sps REG_WR(sc, BCE_HC_RX_QUICK_CONS_TRIP, 5230251142Smarius (sc->bce_rx_quick_cons_trip_int << 16) | 5231251142Smarius sc->bce_rx_quick_cons_trip); 5232157642Sps REG_WR(sc, BCE_HC_TX_TICKS, 5233206268Sdavidch (sc->bce_tx_ticks_int << 16) | sc->bce_tx_ticks); 5234157642Sps REG_WR(sc, BCE_HC_RX_TICKS, 5235206268Sdavidch (sc->bce_rx_ticks_int << 16) | sc->bce_rx_ticks); 5236251142Smarius REG_WR(sc, BCE_HC_STATS_TICKS, sc->bce_stats_ticks & 0xffff00); 5237179771Sdavidch REG_WR(sc, BCE_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */ 5238251142Smarius /* Not used for L2. */ 5239251142Smarius REG_WR(sc, BCE_HC_COMP_PROD_TRIP, 0); 5240251142Smarius REG_WR(sc, BCE_HC_COM_TICKS, 0); 5241251142Smarius REG_WR(sc, BCE_HC_CMD_TICKS, 0); 5242157642Sps 5243179771Sdavidch /* Configure the Host Coalescing block. */ 5244179771Sdavidch val = BCE_HC_CONFIG_RX_TMR_MODE | BCE_HC_CONFIG_TX_TMR_MODE | 5245206268Sdavidch BCE_HC_CONFIG_COLLECT_STATS; 5246179771Sdavidch 5247179771Sdavidch#if 0 5248179771Sdavidch /* ToDo: Add MSI-X support. */ 5249179771Sdavidch if (sc->bce_flags & BCE_USING_MSIX_FLAG) { 5250179771Sdavidch u32 base = ((BCE_TX_VEC - 1) * BCE_HC_SB_CONFIG_SIZE) + 5251206268Sdavidch BCE_HC_SB_CONFIG_1; 5252179771Sdavidch 5253179771Sdavidch REG_WR(sc, BCE_HC_MSIX_BIT_VECTOR, BCE_HC_MSIX_BIT_VECTOR_VAL); 5254179771Sdavidch 5255179771Sdavidch REG_WR(sc, base, BCE_HC_SB_CONFIG_1_TX_TMR_MODE | 5256206268Sdavidch BCE_HC_SB_CONFIG_1_ONE_SHOT); 5257179771Sdavidch 5258179771Sdavidch REG_WR(sc, base + BCE_HC_TX_QUICK_CONS_TRIP_OFF, 5259206268Sdavidch (sc->tx_quick_cons_trip_int << 16) | 5260206268Sdavidch sc->tx_quick_cons_trip); 5261179771Sdavidch 5262179771Sdavidch REG_WR(sc, base + BCE_HC_TX_TICKS_OFF, 5263206268Sdavidch (sc->tx_ticks_int << 16) | sc->tx_ticks); 5264179771Sdavidch 5265179771Sdavidch val |= BCE_HC_CONFIG_SB_ADDR_INC_128B; 5266179771Sdavidch } 5267179771Sdavidch 5268179771Sdavidch /* 5269179771Sdavidch * Tell the HC block to automatically set the 5270179771Sdavidch * INT_MASK bit after an MSI/MSI-X interrupt 5271179771Sdavidch * is generated so the driver doesn't have to. 5272179771Sdavidch */ 5273179771Sdavidch if (sc->bce_flags & BCE_ONE_SHOT_MSI_FLAG) 5274179771Sdavidch val |= BCE_HC_CONFIG_ONE_SHOT; 5275179771Sdavidch 5276179771Sdavidch /* Set the MSI-X status blocks to 128 byte boundaries. */ 5277179771Sdavidch if (sc->bce_flags & BCE_USING_MSIX_FLAG) 5278179771Sdavidch val |= BCE_HC_CONFIG_SB_ADDR_INC_128B; 5279179771Sdavidch#endif 5280179771Sdavidch 5281179771Sdavidch REG_WR(sc, BCE_HC_CONFIG, val); 5282179771Sdavidch 5283157642Sps /* Clear the internal statistics counters. */ 5284157642Sps REG_WR(sc, BCE_HC_COMMAND, BCE_HC_COMMAND_CLR_STAT_NOW); 5285157642Sps 5286157642Sps /* Verify that bootcode is running. */ 5287194781Sdavidch reg = bce_shmem_rd(sc, BCE_DEV_INFO_SIGNATURE); 5288157642Sps 5289189325Sdavidch DBRUNIF(DB_RANDOMTRUE(bootcode_running_failure_sim_control), 5290206268Sdavidch BCE_PRINTF("%s(%d): Simulating bootcode failure.\n", 5291206268Sdavidch __FILE__, __LINE__); 5292206268Sdavidch reg = 0); 5293157642Sps 5294157642Sps if ((reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK) != 5295157642Sps BCE_DEV_INFO_SIGNATURE_MAGIC) { 5296169271Sdavidch BCE_PRINTF("%s(%d): Bootcode not running! Found: 0x%08X, " 5297206268Sdavidch "Expected: 08%08X\n", __FILE__, __LINE__, 5298206268Sdavidch (reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK), 5299206268Sdavidch BCE_DEV_INFO_SIGNATURE_MAGIC); 5300157642Sps rc = ENODEV; 5301157642Sps goto bce_blockinit_exit; 5302157642Sps } 5303157642Sps 5304179771Sdavidch /* Enable DMA */ 5305226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 5306179771Sdavidch val = REG_RD(sc, BCE_MISC_NEW_CORE_CTL); 5307179771Sdavidch val |= BCE_MISC_NEW_CORE_CTL_DMA_ENABLE; 5308179771Sdavidch REG_WR(sc, BCE_MISC_NEW_CORE_CTL, val); 5309179771Sdavidch } 5310179771Sdavidch 5311206268Sdavidch /* Allow bootcode to apply additional fixes before enabling MAC. */ 5312207411Sdavidch rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT2 | 5313206268Sdavidch BCE_DRV_MSG_CODE_RESET); 5314157642Sps 5315157642Sps /* Enable link state change interrupt generation. */ 5316157642Sps REG_WR(sc, BCE_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE); 5317157642Sps 5318206268Sdavidch /* Enable the RXP. */ 5319206268Sdavidch bce_start_rxp_cpu(sc); 5320202717Sdavidch 5321206268Sdavidch /* Disable management frames (NC-SI) from flowing to the MCP. */ 5322206268Sdavidch if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) { 5323207411Sdavidch val = REG_RD(sc, BCE_RPM_MGMT_PKT_CTRL) & 5324206268Sdavidch ~BCE_RPM_MGMT_PKT_CTRL_MGMT_EN; 5325206268Sdavidch REG_WR(sc, BCE_RPM_MGMT_PKT_CTRL, val); 5326206268Sdavidch } 5327202717Sdavidch 5328157642Sps /* Enable all remaining blocks in the MAC. */ 5329226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) 5330207411Sdavidch REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, 5331206268Sdavidch BCE_MISC_ENABLE_DEFAULT_XI); 5332182293Sdavidch else 5333207411Sdavidch REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, 5334206268Sdavidch BCE_MISC_ENABLE_DEFAULT); 5335182293Sdavidch 5336157642Sps REG_RD(sc, BCE_MISC_ENABLE_SET_BITS); 5337157642Sps DELAY(20); 5338157642Sps 5339179771Sdavidch /* Save the current host coalescing block settings. */ 5340179771Sdavidch sc->hc_command = REG_RD(sc, BCE_HC_COMMAND); 5341179771Sdavidch 5342157642Spsbce_blockinit_exit: 5343179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 5344157642Sps 5345157642Sps return (rc); 5346157642Sps} 5347157642Sps 5348157642Sps 5349157642Sps/****************************************************************************/ 5350176448Sdavidch/* Encapsulate an mbuf into the rx_bd chain. */ 5351157642Sps/* */ 5352157642Sps/* Returns: */ 5353157642Sps/* 0 for success, positive value for failure. */ 5354157642Sps/****************************************************************************/ 5355157642Spsstatic int 5356251146Smariusbce_get_rx_buf(struct bce_softc *sc, u16 prod, u16 chain_prod, u32 *prod_bseq) 5357157642Sps{ 5358251146Smarius bus_dma_segment_t segs[1]; 5359157642Sps struct mbuf *m_new = NULL; 5360171667Sdavidch struct rx_bd *rxbd; 5361176448Sdavidch int nsegs, error, rc = 0; 5362157642Sps#ifdef BCE_DEBUG 5363251146Smarius u16 debug_chain_prod = chain_prod; 5364157642Sps#endif 5365157642Sps 5366179771Sdavidch DBENTER(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD); 5367157642Sps 5368157642Sps /* Make sure the inputs are valid. */ 5369251146Smarius DBRUNIF((chain_prod > MAX_RX_BD_ALLOC), 5370207411Sdavidch BCE_PRINTF("%s(%d): RX producer out of range: " 5371207411Sdavidch "0x%04X > 0x%04X\n", __FILE__, __LINE__, 5372251146Smarius chain_prod, (u16)MAX_RX_BD_ALLOC)); 5373157642Sps 5374206268Sdavidch DBPRINT(sc, BCE_EXTREME_RECV, "%s(enter): prod = 0x%04X, " 5375206268Sdavidch "chain_prod = 0x%04X, prod_bseq = 0x%08X\n", __FUNCTION__, 5376251146Smarius prod, chain_prod, *prod_bseq); 5377157642Sps 5378176448Sdavidch /* Update some debug statistic counters */ 5379179771Sdavidch DBRUNIF((sc->free_rx_bd < sc->rx_low_watermark), 5380207411Sdavidch sc->rx_low_watermark = sc->free_rx_bd); 5381207411Sdavidch DBRUNIF((sc->free_rx_bd == sc->max_rx_bd), 5382207411Sdavidch sc->rx_empty_count++); 5383176448Sdavidch 5384251146Smarius /* Simulate an mbuf allocation failure. */ 5385251146Smarius DBRUNIF(DB_RANDOMTRUE(mbuf_alloc_failed_sim_control), 5386251146Smarius sc->mbuf_alloc_failed_count++; 5387251146Smarius sc->mbuf_alloc_failed_sim_count++; 5388251146Smarius rc = ENOBUFS; 5389251146Smarius goto bce_get_rx_buf_exit); 5390157642Sps 5391251146Smarius /* This is a new mbuf allocation. */ 5392251146Smarius if (bce_hdr_split == TRUE) 5393251146Smarius MGETHDR(m_new, M_NOWAIT, MT_DATA); 5394251146Smarius else 5395251146Smarius m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 5396251146Smarius sc->rx_bd_mbuf_alloc_size); 5397157642Sps 5398251146Smarius if (m_new == NULL) { 5399251146Smarius sc->mbuf_alloc_failed_count++; 5400251146Smarius rc = ENOBUFS; 5401251146Smarius goto bce_get_rx_buf_exit; 5402251146Smarius } 5403179771Sdavidch 5404251146Smarius DBRUN(sc->debug_rx_mbuf_alloc++); 5405157642Sps 5406179771Sdavidch /* Make sure we have a valid packet header. */ 5407176448Sdavidch M_ASSERTPKTHDR(m_new); 5408176448Sdavidch 5409179771Sdavidch /* Initialize the mbuf size and pad if necessary for alignment. */ 5410179771Sdavidch m_new->m_pkthdr.len = m_new->m_len = sc->rx_bd_mbuf_alloc_size; 5411179695Sdavidch m_adj(m_new, sc->rx_bd_mbuf_align_pad); 5412176448Sdavidch 5413176448Sdavidch /* ToDo: Consider calling m_fragment() to test error handling. */ 5414176448Sdavidch 5415157642Sps /* Map the mbuf cluster into device memory. */ 5416251146Smarius error = bus_dmamap_load_mbuf_sg(sc->rx_mbuf_tag, 5417251146Smarius sc->rx_mbuf_map[chain_prod], m_new, segs, &nsegs, BUS_DMA_NOWAIT); 5418157642Sps 5419171667Sdavidch /* Handle any mapping errors. */ 5420157642Sps if (error) { 5421207411Sdavidch BCE_PRINTF("%s(%d): Error mapping mbuf into RX " 5422207411Sdavidch "chain (%d)!\n", __FILE__, __LINE__, error); 5423157642Sps 5424189325Sdavidch sc->dma_map_addr_rx_failed_count++; 5425157642Sps m_freem(m_new); 5426189325Sdavidch 5427176448Sdavidch DBRUN(sc->debug_rx_mbuf_alloc--); 5428157642Sps 5429157642Sps rc = ENOBUFS; 5430176448Sdavidch goto bce_get_rx_buf_exit; 5431157642Sps } 5432179771Sdavidch 5433176448Sdavidch /* All mbufs must map to a single segment. */ 5434176448Sdavidch KASSERT(nsegs == 1, ("%s(): Too many segments returned (%d)!", 5435206268Sdavidch __FUNCTION__, nsegs)); 5436157642Sps 5437176448Sdavidch /* Setup the rx_bd for the segment. */ 5438251146Smarius rxbd = &sc->rx_bd_chain[RX_PAGE(chain_prod)][RX_IDX(chain_prod)]; 5439157642Sps 5440157642Sps rxbd->rx_bd_haddr_lo = htole32(BCE_ADDR_LO(segs[0].ds_addr)); 5441157642Sps rxbd->rx_bd_haddr_hi = htole32(BCE_ADDR_HI(segs[0].ds_addr)); 5442157642Sps rxbd->rx_bd_len = htole32(segs[0].ds_len); 5443176448Sdavidch rxbd->rx_bd_flags = htole32(RX_BD_FLAGS_START | RX_BD_FLAGS_END); 5444179771Sdavidch *prod_bseq += segs[0].ds_len; 5445157642Sps 5446176448Sdavidch /* Save the mbuf and update our counter. */ 5447251146Smarius sc->rx_mbuf_ptr[chain_prod] = m_new; 5448176448Sdavidch sc->free_rx_bd -= nsegs; 5449182293Sdavidch 5450207411Sdavidch DBRUNMSG(BCE_INSANE_RECV, 5451206268Sdavidch bce_dump_rx_mbuf_chain(sc, debug_chain_prod, nsegs)); 5452157642Sps 5453206268Sdavidch DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): prod = 0x%04X, " 5454251146Smarius "chain_prod = 0x%04X, prod_bseq = 0x%08X\n", __FUNCTION__, prod, 5455251146Smarius chain_prod, *prod_bseq); 5456157642Sps 5457176448Sdavidchbce_get_rx_buf_exit: 5458179771Sdavidch DBEXIT(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD); 5459176448Sdavidch 5460176448Sdavidch return(rc); 5461176448Sdavidch} 5462176448Sdavidch 5463176448Sdavidch 5464176448Sdavidch/****************************************************************************/ 5465206268Sdavidch/* Encapsulate an mbuf cluster into the page chain. */ 5466176448Sdavidch/* */ 5467176448Sdavidch/* Returns: */ 5468176448Sdavidch/* 0 for success, positive value for failure. */ 5469176448Sdavidch/****************************************************************************/ 5470176448Sdavidchstatic int 5471251146Smariusbce_get_pg_buf(struct bce_softc *sc, u16 prod, u16 prod_idx) 5472176448Sdavidch{ 5473251146Smarius bus_dma_segment_t segs[1]; 5474176448Sdavidch struct mbuf *m_new = NULL; 5475176448Sdavidch struct rx_bd *pgbd; 5476251146Smarius int error, nsegs, rc = 0; 5477176448Sdavidch#ifdef BCE_DEBUG 5478251146Smarius u16 debug_prod_idx = prod_idx; 5479176448Sdavidch#endif 5480176448Sdavidch 5481179771Sdavidch DBENTER(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD); 5482176448Sdavidch 5483176448Sdavidch /* Make sure the inputs are valid. */ 5484251146Smarius DBRUNIF((prod_idx > MAX_PG_BD_ALLOC), 5485207411Sdavidch BCE_PRINTF("%s(%d): page producer out of range: " 5486207411Sdavidch "0x%04X > 0x%04X\n", __FILE__, __LINE__, 5487251146Smarius prod_idx, (u16)MAX_PG_BD_ALLOC)); 5488176448Sdavidch 5489179771Sdavidch DBPRINT(sc, BCE_EXTREME_RECV, "%s(enter): prod = 0x%04X, " 5490251146Smarius "chain_prod = 0x%04X\n", __FUNCTION__, prod, prod_idx); 5491176448Sdavidch 5492176448Sdavidch /* Update counters if we've hit a new low or run out of pages. */ 5493179771Sdavidch DBRUNIF((sc->free_pg_bd < sc->pg_low_watermark), 5494206268Sdavidch sc->pg_low_watermark = sc->free_pg_bd); 5495176448Sdavidch DBRUNIF((sc->free_pg_bd == sc->max_pg_bd), sc->pg_empty_count++); 5496176448Sdavidch 5497251146Smarius /* Simulate an mbuf allocation failure. */ 5498251146Smarius DBRUNIF(DB_RANDOMTRUE(mbuf_alloc_failed_sim_control), 5499251146Smarius sc->mbuf_alloc_failed_count++; 5500251146Smarius sc->mbuf_alloc_failed_sim_count++; 5501251146Smarius rc = ENOBUFS; 5502251146Smarius goto bce_get_pg_buf_exit); 5503176448Sdavidch 5504251146Smarius /* This is a new mbuf allocation. */ 5505251146Smarius m_new = m_getcl(M_NOWAIT, MT_DATA, 0); 5506251146Smarius if (m_new == NULL) { 5507251146Smarius sc->mbuf_alloc_failed_count++; 5508251146Smarius rc = ENOBUFS; 5509251146Smarius goto bce_get_pg_buf_exit; 5510251146Smarius } 5511176448Sdavidch 5512251146Smarius DBRUN(sc->debug_pg_mbuf_alloc++); 5513176448Sdavidch 5514251142Smarius m_new->m_len = MCLBYTES; 5515157642Sps 5516176448Sdavidch /* ToDo: Consider calling m_fragment() to test error handling. */ 5517176448Sdavidch 5518176448Sdavidch /* Map the mbuf cluster into device memory. */ 5519251146Smarius error = bus_dmamap_load_mbuf_sg(sc->pg_mbuf_tag, 5520251146Smarius sc->pg_mbuf_map[prod_idx], m_new, segs, &nsegs, BUS_DMA_NOWAIT); 5521176448Sdavidch 5522176448Sdavidch /* Handle any mapping errors. */ 5523176448Sdavidch if (error) { 5524176448Sdavidch BCE_PRINTF("%s(%d): Error mapping mbuf into page chain!\n", 5525206268Sdavidch __FILE__, __LINE__); 5526176448Sdavidch 5527176448Sdavidch m_freem(m_new); 5528176448Sdavidch DBRUN(sc->debug_pg_mbuf_alloc--); 5529176448Sdavidch 5530176448Sdavidch rc = ENOBUFS; 5531176448Sdavidch goto bce_get_pg_buf_exit; 5532176448Sdavidch } 5533176448Sdavidch 5534251146Smarius /* All mbufs must map to a single segment. */ 5535251146Smarius KASSERT(nsegs == 1, ("%s(): Too many segments returned (%d)!", 5536251146Smarius __FUNCTION__, nsegs)); 5537251146Smarius 5538192281Sdelphij /* ToDo: Do we need bus_dmamap_sync(,,BUS_DMASYNC_PREREAD) here? */ 5539176448Sdavidch 5540179771Sdavidch /* 5541176448Sdavidch * The page chain uses the same rx_bd data structure 5542176448Sdavidch * as the receive chain but doesn't require a byte sequence (bseq). 5543176448Sdavidch */ 5544251146Smarius pgbd = &sc->pg_bd_chain[PG_PAGE(prod_idx)][PG_IDX(prod_idx)]; 5545176448Sdavidch 5546251146Smarius pgbd->rx_bd_haddr_lo = htole32(BCE_ADDR_LO(segs[0].ds_addr)); 5547251146Smarius pgbd->rx_bd_haddr_hi = htole32(BCE_ADDR_HI(segs[0].ds_addr)); 5548251142Smarius pgbd->rx_bd_len = htole32(MCLBYTES); 5549176448Sdavidch pgbd->rx_bd_flags = htole32(RX_BD_FLAGS_START | RX_BD_FLAGS_END); 5550176448Sdavidch 5551157642Sps /* Save the mbuf and update our counter. */ 5552251146Smarius sc->pg_mbuf_ptr[prod_idx] = m_new; 5553176448Sdavidch sc->free_pg_bd--; 5554157642Sps 5555207411Sdavidch DBRUNMSG(BCE_INSANE_RECV, 5556206268Sdavidch bce_dump_pg_mbuf_chain(sc, debug_prod_idx, 1)); 5557157642Sps 5558179771Sdavidch DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): prod = 0x%04X, " 5559251146Smarius "prod_idx = 0x%04X\n", __FUNCTION__, prod, prod_idx); 5560157642Sps 5561176448Sdavidchbce_get_pg_buf_exit: 5562179771Sdavidch DBEXIT(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD); 5563157642Sps 5564157642Sps return(rc); 5565157642Sps} 5566157642Sps 5567206268Sdavidch 5568179771Sdavidch/****************************************************************************/ 5569179771Sdavidch/* Initialize the TX context memory. */ 5570179771Sdavidch/* */ 5571179771Sdavidch/* Returns: */ 5572179771Sdavidch/* Nothing */ 5573179771Sdavidch/****************************************************************************/ 5574179771Sdavidchstatic void 5575179771Sdavidchbce_init_tx_context(struct bce_softc *sc) 5576179771Sdavidch{ 5577179771Sdavidch u32 val; 5578157642Sps 5579179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_CTX); 5580179771Sdavidch 5581179771Sdavidch /* Initialize the context ID for an L2 TX chain. */ 5582226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 5583179771Sdavidch /* Set the CID type to support an L2 connection. */ 5584207411Sdavidch val = BCE_L2CTX_TX_TYPE_TYPE_L2_XI | 5585206268Sdavidch BCE_L2CTX_TX_TYPE_SIZE_L2_XI; 5586182293Sdavidch CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TYPE_XI, val); 5587182293Sdavidch val = BCE_L2CTX_TX_CMD_TYPE_TYPE_L2_XI | (8 << 16); 5588207411Sdavidch CTX_WR(sc, GET_CID_ADDR(TX_CID), 5589206268Sdavidch BCE_L2CTX_TX_CMD_TYPE_XI, val); 5590179771Sdavidch 5591179771Sdavidch /* Point the hardware to the first page in the chain. */ 5592179771Sdavidch val = BCE_ADDR_HI(sc->tx_bd_chain_paddr[0]); 5593207411Sdavidch CTX_WR(sc, GET_CID_ADDR(TX_CID), 5594206268Sdavidch BCE_L2CTX_TX_TBDR_BHADDR_HI_XI, val); 5595179771Sdavidch val = BCE_ADDR_LO(sc->tx_bd_chain_paddr[0]); 5596207411Sdavidch CTX_WR(sc, GET_CID_ADDR(TX_CID), 5597206268Sdavidch BCE_L2CTX_TX_TBDR_BHADDR_LO_XI, val); 5598179771Sdavidch } else { 5599179771Sdavidch /* Set the CID type to support an L2 connection. */ 5600182293Sdavidch val = BCE_L2CTX_TX_TYPE_TYPE_L2 | BCE_L2CTX_TX_TYPE_SIZE_L2; 5601182293Sdavidch CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TYPE, val); 5602182293Sdavidch val = BCE_L2CTX_TX_CMD_TYPE_TYPE_L2 | (8 << 16); 5603182293Sdavidch CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_CMD_TYPE, val); 5604179771Sdavidch 5605179771Sdavidch /* Point the hardware to the first page in the chain. */ 5606179771Sdavidch val = BCE_ADDR_HI(sc->tx_bd_chain_paddr[0]); 5607207411Sdavidch CTX_WR(sc, GET_CID_ADDR(TX_CID), 5608206268Sdavidch BCE_L2CTX_TX_TBDR_BHADDR_HI, val); 5609179771Sdavidch val = BCE_ADDR_LO(sc->tx_bd_chain_paddr[0]); 5610207411Sdavidch CTX_WR(sc, GET_CID_ADDR(TX_CID), 5611206268Sdavidch BCE_L2CTX_TX_TBDR_BHADDR_LO, val); 5612179771Sdavidch } 5613179771Sdavidch 5614179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_CTX); 5615179771Sdavidch} 5616179771Sdavidch 5617182293Sdavidch 5618157642Sps/****************************************************************************/ 5619157642Sps/* Allocate memory and initialize the TX data structures. */ 5620157642Sps/* */ 5621157642Sps/* Returns: */ 5622157642Sps/* 0 for success, positive value for failure. */ 5623157642Sps/****************************************************************************/ 5624157642Spsstatic int 5625157642Spsbce_init_tx_chain(struct bce_softc *sc) 5626157642Sps{ 5627157642Sps struct tx_bd *txbd; 5628157642Sps int i, rc = 0; 5629157642Sps 5630179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_LOAD); 5631157642Sps 5632157642Sps /* Set the initial TX producer/consumer indices. */ 5633157642Sps sc->tx_prod = 0; 5634157642Sps sc->tx_cons = 0; 5635157642Sps sc->tx_prod_bseq = 0; 5636170392Sdavidch sc->used_tx_bd = 0; 5637218423Sdavidch sc->max_tx_bd = USABLE_TX_BD_ALLOC; 5638206268Sdavidch DBRUN(sc->tx_hi_watermark = 0); 5639176448Sdavidch DBRUN(sc->tx_full_count = 0); 5640157642Sps 5641157642Sps /* 5642157642Sps * The NetXtreme II supports a linked-list structre called 5643157642Sps * a Buffer Descriptor Chain (or BD chain). A BD chain 5644157642Sps * consists of a series of 1 or more chain pages, each of which 5645157642Sps * consists of a fixed number of BD entries. 5646157642Sps * The last BD entry on each page is a pointer to the next page 5647157642Sps * in the chain, and the last pointer in the BD chain 5648157642Sps * points back to the beginning of the chain. 5649157642Sps */ 5650157642Sps 5651157642Sps /* Set the TX next pointer chain entries. */ 5652218423Sdavidch for (i = 0; i < sc->tx_pages; i++) { 5653157642Sps int j; 5654157642Sps 5655157642Sps txbd = &sc->tx_bd_chain[i][USABLE_TX_BD_PER_PAGE]; 5656157642Sps 5657157642Sps /* Check if we've reached the last page. */ 5658218423Sdavidch if (i == (sc->tx_pages - 1)) 5659157642Sps j = 0; 5660157642Sps else 5661157642Sps j = i + 1; 5662157642Sps 5663218423Sdavidch txbd->tx_bd_haddr_hi = 5664218423Sdavidch htole32(BCE_ADDR_HI(sc->tx_bd_chain_paddr[j])); 5665218423Sdavidch txbd->tx_bd_haddr_lo = 5666218423Sdavidch htole32(BCE_ADDR_LO(sc->tx_bd_chain_paddr[j])); 5667157642Sps } 5668157642Sps 5669179771Sdavidch bce_init_tx_context(sc); 5670157642Sps 5671218423Sdavidch DBRUNMSG(BCE_INSANE_SEND, bce_dump_tx_chain(sc, 0, TOTAL_TX_BD_ALLOC)); 5672179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_LOAD); 5673157642Sps 5674157642Sps return(rc); 5675157642Sps} 5676157642Sps 5677157642Sps 5678157642Sps/****************************************************************************/ 5679157642Sps/* Free memory and clear the TX data structures. */ 5680157642Sps/* */ 5681157642Sps/* Returns: */ 5682157642Sps/* Nothing. */ 5683157642Sps/****************************************************************************/ 5684157642Spsstatic void 5685157642Spsbce_free_tx_chain(struct bce_softc *sc) 5686157642Sps{ 5687157642Sps int i; 5688157642Sps 5689179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_UNLOAD); 5690157642Sps 5691157642Sps /* Unmap, unload, and free any mbufs still in the TX mbuf chain. */ 5692218423Sdavidch for (i = 0; i < MAX_TX_BD_AVAIL; i++) { 5693157642Sps if (sc->tx_mbuf_ptr[i] != NULL) { 5694186168Sdelphij if (sc->tx_mbuf_map[i] != NULL) 5695207411Sdavidch bus_dmamap_sync(sc->tx_mbuf_tag, 5696206268Sdavidch sc->tx_mbuf_map[i], 5697206268Sdavidch BUS_DMASYNC_POSTWRITE); 5698157642Sps m_freem(sc->tx_mbuf_ptr[i]); 5699157642Sps sc->tx_mbuf_ptr[i] = NULL; 5700176448Sdavidch DBRUN(sc->debug_tx_mbuf_alloc--); 5701179771Sdavidch } 5702157642Sps } 5703157642Sps 5704157642Sps /* Clear each TX chain page. */ 5705218423Sdavidch for (i = 0; i < sc->tx_pages; i++) 5706157642Sps bzero((char *)sc->tx_bd_chain[i], BCE_TX_CHAIN_PAGE_SZ); 5707157642Sps 5708206268Sdavidch sc->used_tx_bd = 0; 5709171667Sdavidch 5710157642Sps /* Check if we lost any mbufs in the process. */ 5711176448Sdavidch DBRUNIF((sc->debug_tx_mbuf_alloc), 5712206268Sdavidch BCE_PRINTF("%s(%d): Memory leak! Lost %d mbufs " 5713207411Sdavidch "from tx chain!\n", __FILE__, __LINE__, 5714206268Sdavidch sc->debug_tx_mbuf_alloc)); 5715157642Sps 5716179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_UNLOAD); 5717157642Sps} 5718157642Sps 5719157642Sps 5720157642Sps/****************************************************************************/ 5721179771Sdavidch/* Initialize the RX context memory. */ 5722179771Sdavidch/* */ 5723179771Sdavidch/* Returns: */ 5724179771Sdavidch/* Nothing */ 5725179771Sdavidch/****************************************************************************/ 5726179771Sdavidchstatic void 5727179771Sdavidchbce_init_rx_context(struct bce_softc *sc) 5728179771Sdavidch{ 5729179771Sdavidch u32 val; 5730179771Sdavidch 5731179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_CTX); 5732179771Sdavidch 5733206268Sdavidch /* Init the type, size, and BD cache levels for the RX context. */ 5734182293Sdavidch val = BCE_L2CTX_RX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE | 5735206268Sdavidch BCE_L2CTX_RX_CTX_TYPE_SIZE_L2 | 5736206268Sdavidch (0x02 << BCE_L2CTX_RX_BD_PRE_READ_SHIFT); 5737179771Sdavidch 5738182293Sdavidch /* 5739182293Sdavidch * Set the level for generating pause frames 5740182293Sdavidch * when the number of available rx_bd's gets 5741182293Sdavidch * too low (the low watermark) and the level 5742182293Sdavidch * when pause frames can be stopped (the high 5743182293Sdavidch * watermark). 5744182293Sdavidch */ 5745226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 5746179771Sdavidch u32 lo_water, hi_water; 5747179771Sdavidch 5748210522Sjkim if (sc->bce_flags & BCE_USING_TX_FLOW_CONTROL) { 5749207411Sdavidch lo_water = BCE_L2CTX_RX_LO_WATER_MARK_DEFAULT; 5750207411Sdavidch } else { 5751207411Sdavidch lo_water = 0; 5752207411Sdavidch } 5753207411Sdavidch 5754218423Sdavidch if (lo_water >= USABLE_RX_BD_ALLOC) { 5755207411Sdavidch lo_water = 0; 5756207411Sdavidch } 5757207411Sdavidch 5758218423Sdavidch hi_water = USABLE_RX_BD_ALLOC / 4; 5759179771Sdavidch 5760207411Sdavidch if (hi_water <= lo_water) { 5761207411Sdavidch lo_water = 0; 5762207411Sdavidch } 5763207411Sdavidch 5764182293Sdavidch lo_water /= BCE_L2CTX_RX_LO_WATER_MARK_SCALE; 5765182293Sdavidch hi_water /= BCE_L2CTX_RX_HI_WATER_MARK_SCALE; 5766179771Sdavidch 5767179771Sdavidch if (hi_water > 0xf) 5768179771Sdavidch hi_water = 0xf; 5769179771Sdavidch else if (hi_water == 0) 5770179771Sdavidch lo_water = 0; 5771207411Sdavidch 5772182293Sdavidch val |= (lo_water << BCE_L2CTX_RX_LO_WATER_MARK_SHIFT) | 5773207411Sdavidch (hi_water << BCE_L2CTX_RX_HI_WATER_MARK_SHIFT); 5774182293Sdavidch } 5775179771Sdavidch 5776207411Sdavidch CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_CTX_TYPE, val); 5777179771Sdavidch 5778182293Sdavidch /* Setup the MQ BIN mapping for l2_ctx_host_bseq. */ 5779226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 5780179771Sdavidch val = REG_RD(sc, BCE_MQ_MAP_L2_5); 5781179771Sdavidch REG_WR(sc, BCE_MQ_MAP_L2_5, val | BCE_MQ_MAP_L2_5_ARM); 5782179771Sdavidch } 5783182293Sdavidch 5784179771Sdavidch /* Point the hardware to the first page in the chain. */ 5785179771Sdavidch val = BCE_ADDR_HI(sc->rx_bd_chain_paddr[0]); 5786182293Sdavidch CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_BDHADDR_HI, val); 5787179771Sdavidch val = BCE_ADDR_LO(sc->rx_bd_chain_paddr[0]); 5788182293Sdavidch CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_BDHADDR_LO, val); 5789179771Sdavidch 5790179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_CTX); 5791179771Sdavidch} 5792179771Sdavidch 5793179771Sdavidch 5794179771Sdavidch/****************************************************************************/ 5795157642Sps/* Allocate memory and initialize the RX data structures. */ 5796157642Sps/* */ 5797157642Sps/* Returns: */ 5798157642Sps/* 0 for success, positive value for failure. */ 5799157642Sps/****************************************************************************/ 5800157642Spsstatic int 5801157642Spsbce_init_rx_chain(struct bce_softc *sc) 5802157642Sps{ 5803157642Sps struct rx_bd *rxbd; 5804157642Sps int i, rc = 0; 5805157642Sps 5806179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD | 5807206268Sdavidch BCE_VERBOSE_CTX); 5808157642Sps 5809157642Sps /* Initialize the RX producer and consumer indices. */ 5810157642Sps sc->rx_prod = 0; 5811157642Sps sc->rx_cons = 0; 5812157642Sps sc->rx_prod_bseq = 0; 5813218423Sdavidch sc->free_rx_bd = USABLE_RX_BD_ALLOC; 5814218423Sdavidch sc->max_rx_bd = USABLE_RX_BD_ALLOC; 5815157642Sps 5816157642Sps /* Initialize the RX next pointer chain entries. */ 5817218423Sdavidch for (i = 0; i < sc->rx_pages; i++) { 5818157642Sps int j; 5819157642Sps 5820157642Sps rxbd = &sc->rx_bd_chain[i][USABLE_RX_BD_PER_PAGE]; 5821157642Sps 5822157642Sps /* Check if we've reached the last page. */ 5823218423Sdavidch if (i == (sc->rx_pages - 1)) 5824157642Sps j = 0; 5825157642Sps else 5826157642Sps j = i + 1; 5827157642Sps 5828157642Sps /* Setup the chain page pointers. */ 5829207411Sdavidch rxbd->rx_bd_haddr_hi = 5830206268Sdavidch htole32(BCE_ADDR_HI(sc->rx_bd_chain_paddr[j])); 5831207411Sdavidch rxbd->rx_bd_haddr_lo = 5832206268Sdavidch htole32(BCE_ADDR_LO(sc->rx_bd_chain_paddr[j])); 5833157642Sps } 5834157642Sps 5835192281Sdelphij /* Fill up the RX chain. */ 5836171667Sdavidch bce_fill_rx_chain(sc); 5837157642Sps 5838218423Sdavidch DBRUN(sc->rx_low_watermark = USABLE_RX_BD_ALLOC); 5839206268Sdavidch DBRUN(sc->rx_empty_count = 0); 5840218423Sdavidch for (i = 0; i < sc->rx_pages; i++) { 5841192281Sdelphij bus_dmamap_sync(sc->rx_bd_chain_tag, sc->rx_bd_chain_map[i], 5842157642Sps BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 5843157642Sps } 5844157642Sps 5845179771Sdavidch bce_init_rx_context(sc); 5846157642Sps 5847218423Sdavidch DBRUNMSG(BCE_EXTREME_RECV, 5848218423Sdavidch bce_dump_rx_bd_chain(sc, 0, TOTAL_RX_BD_ALLOC)); 5849179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD | 5850206268Sdavidch BCE_VERBOSE_CTX); 5851206268Sdavidch 5852179771Sdavidch /* ToDo: Are there possible failure modes here? */ 5853206268Sdavidch 5854157642Sps return(rc); 5855157642Sps} 5856157642Sps 5857157642Sps 5858157642Sps/****************************************************************************/ 5859176448Sdavidch/* Add mbufs to the RX chain until its full or an mbuf allocation error */ 5860176448Sdavidch/* occurs. */ 5861176448Sdavidch/* */ 5862176448Sdavidch/* Returns: */ 5863176448Sdavidch/* Nothing */ 5864176448Sdavidch/****************************************************************************/ 5865176448Sdavidchstatic void 5866176448Sdavidchbce_fill_rx_chain(struct bce_softc *sc) 5867176448Sdavidch{ 5868176448Sdavidch u16 prod, prod_idx; 5869176448Sdavidch u32 prod_bseq; 5870176448Sdavidch 5871179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD | 5872206268Sdavidch BCE_VERBOSE_CTX); 5873176448Sdavidch 5874179771Sdavidch /* Get the RX chain producer indices. */ 5875176448Sdavidch prod = sc->rx_prod; 5876176448Sdavidch prod_bseq = sc->rx_prod_bseq; 5877176448Sdavidch 5878176448Sdavidch /* Keep filling the RX chain until it's full. */ 5879176448Sdavidch while (sc->free_rx_bd > 0) { 5880176448Sdavidch prod_idx = RX_CHAIN_IDX(prod); 5881251146Smarius if (bce_get_rx_buf(sc, prod, prod_idx, &prod_bseq)) { 5882176448Sdavidch /* Bail out if we can't add an mbuf to the chain. */ 5883176448Sdavidch break; 5884176448Sdavidch } 5885176448Sdavidch prod = NEXT_RX_BD(prod); 5886176448Sdavidch } 5887176448Sdavidch 5888179771Sdavidch /* Save the RX chain producer indices. */ 5889176448Sdavidch sc->rx_prod = prod; 5890176448Sdavidch sc->rx_prod_bseq = prod_bseq; 5891176448Sdavidch 5892206268Sdavidch /* We should never end up pointing to a next page pointer. */ 5893178132Sdavidch DBRUNIF(((prod & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE), 5894207411Sdavidch BCE_PRINTF("%s(): Invalid rx_prod value: 0x%04X\n", 5895251146Smarius __FUNCTION__, rx_prod)); 5896178132Sdavidch 5897179771Sdavidch /* Write the mailbox and tell the chip about the waiting rx_bd's. */ 5898251146Smarius REG_WR16(sc, MB_GET_CID_ADDR(RX_CID) + BCE_L2MQ_RX_HOST_BDIDX, prod); 5899251146Smarius REG_WR(sc, MB_GET_CID_ADDR(RX_CID) + BCE_L2MQ_RX_HOST_BSEQ, prod_bseq); 5900176448Sdavidch 5901179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD | 5902206268Sdavidch BCE_VERBOSE_CTX); 5903176448Sdavidch} 5904176448Sdavidch 5905176448Sdavidch 5906176448Sdavidch/****************************************************************************/ 5907157642Sps/* Free memory and clear the RX data structures. */ 5908157642Sps/* */ 5909157642Sps/* Returns: */ 5910157642Sps/* Nothing. */ 5911157642Sps/****************************************************************************/ 5912157642Spsstatic void 5913157642Spsbce_free_rx_chain(struct bce_softc *sc) 5914157642Sps{ 5915157642Sps int i; 5916157642Sps 5917179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD); 5918182293Sdavidch 5919157642Sps /* Free any mbufs still in the RX mbuf chain. */ 5920218423Sdavidch for (i = 0; i < MAX_RX_BD_AVAIL; i++) { 5921157642Sps if (sc->rx_mbuf_ptr[i] != NULL) { 5922157642Sps if (sc->rx_mbuf_map[i] != NULL) 5923207411Sdavidch bus_dmamap_sync(sc->rx_mbuf_tag, 5924206268Sdavidch sc->rx_mbuf_map[i], 5925206268Sdavidch BUS_DMASYNC_POSTREAD); 5926157642Sps m_freem(sc->rx_mbuf_ptr[i]); 5927157642Sps sc->rx_mbuf_ptr[i] = NULL; 5928176448Sdavidch DBRUN(sc->debug_rx_mbuf_alloc--); 5929157642Sps } 5930157642Sps } 5931157642Sps 5932157642Sps /* Clear each RX chain page. */ 5933218423Sdavidch for (i = 0; i < sc->rx_pages; i++) 5934251142Smarius if (sc->rx_bd_chain[i] != NULL) 5935207411Sdavidch bzero((char *)sc->rx_bd_chain[i], 5936206268Sdavidch BCE_RX_CHAIN_PAGE_SZ); 5937157642Sps 5938171667Sdavidch sc->free_rx_bd = sc->max_rx_bd; 5939171667Sdavidch 5940157642Sps /* Check if we lost any mbufs in the process. */ 5941176448Sdavidch DBRUNIF((sc->debug_rx_mbuf_alloc), 5942206268Sdavidch BCE_PRINTF("%s(): Memory leak! Lost %d mbufs from rx chain!\n", 5943206268Sdavidch __FUNCTION__, sc->debug_rx_mbuf_alloc)); 5944157642Sps 5945179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD); 5946157642Sps} 5947157642Sps 5948157642Sps 5949157642Sps/****************************************************************************/ 5950176448Sdavidch/* Allocate memory and initialize the page data structures. */ 5951176448Sdavidch/* Assumes that bce_init_rx_chain() has not already been called. */ 5952176448Sdavidch/* */ 5953176448Sdavidch/* Returns: */ 5954176448Sdavidch/* 0 for success, positive value for failure. */ 5955176448Sdavidch/****************************************************************************/ 5956176448Sdavidchstatic int 5957176448Sdavidchbce_init_pg_chain(struct bce_softc *sc) 5958176448Sdavidch{ 5959176448Sdavidch struct rx_bd *pgbd; 5960176448Sdavidch int i, rc = 0; 5961176448Sdavidch u32 val; 5962176448Sdavidch 5963179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD | 5964179771Sdavidch BCE_VERBOSE_CTX); 5965176448Sdavidch 5966176448Sdavidch /* Initialize the page producer and consumer indices. */ 5967176448Sdavidch sc->pg_prod = 0; 5968176448Sdavidch sc->pg_cons = 0; 5969218423Sdavidch sc->free_pg_bd = USABLE_PG_BD_ALLOC; 5970218423Sdavidch sc->max_pg_bd = USABLE_PG_BD_ALLOC; 5971176448Sdavidch DBRUN(sc->pg_low_watermark = sc->max_pg_bd); 5972176448Sdavidch DBRUN(sc->pg_empty_count = 0); 5973176448Sdavidch 5974176448Sdavidch /* Initialize the page next pointer chain entries. */ 5975218423Sdavidch for (i = 0; i < sc->pg_pages; i++) { 5976176448Sdavidch int j; 5977176448Sdavidch 5978176448Sdavidch pgbd = &sc->pg_bd_chain[i][USABLE_PG_BD_PER_PAGE]; 5979176448Sdavidch 5980176448Sdavidch /* Check if we've reached the last page. */ 5981218423Sdavidch if (i == (sc->pg_pages - 1)) 5982176448Sdavidch j = 0; 5983176448Sdavidch else 5984176448Sdavidch j = i + 1; 5985176448Sdavidch 5986176448Sdavidch /* Setup the chain page pointers. */ 5987218423Sdavidch pgbd->rx_bd_haddr_hi = 5988218423Sdavidch htole32(BCE_ADDR_HI(sc->pg_bd_chain_paddr[j])); 5989218423Sdavidch pgbd->rx_bd_haddr_lo = 5990218423Sdavidch htole32(BCE_ADDR_LO(sc->pg_bd_chain_paddr[j])); 5991176448Sdavidch } 5992176448Sdavidch 5993182293Sdavidch /* Setup the MQ BIN mapping for host_pg_bidx. */ 5994226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) 5995179771Sdavidch REG_WR(sc, BCE_MQ_MAP_L2_3, BCE_MQ_MAP_L2_3_DEFAULT); 5996176448Sdavidch 5997182293Sdavidch CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_PG_BUF_SIZE, 0); 5998179771Sdavidch 5999176448Sdavidch /* Configure the rx_bd and page chain mbuf cluster size. */ 6000251142Smarius val = (sc->rx_bd_mbuf_data_len << 16) | MCLBYTES; 6001182293Sdavidch CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_PG_BUF_SIZE, val); 6002176448Sdavidch 6003176448Sdavidch /* Configure the context reserved for jumbo support. */ 6004182293Sdavidch CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_RBDC_KEY, 6005182293Sdavidch BCE_L2CTX_RX_RBDC_JUMBO_KEY); 6006176448Sdavidch 6007179771Sdavidch /* Point the hardware to the first page in the page chain. */ 6008179771Sdavidch val = BCE_ADDR_HI(sc->pg_bd_chain_paddr[0]); 6009182293Sdavidch CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_PG_BDHADDR_HI, val); 6010179771Sdavidch val = BCE_ADDR_LO(sc->pg_bd_chain_paddr[0]); 6011182293Sdavidch CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_PG_BDHADDR_LO, val); 6012179771Sdavidch 6013176448Sdavidch /* Fill up the page chain. */ 6014176448Sdavidch bce_fill_pg_chain(sc); 6015176448Sdavidch 6016218423Sdavidch for (i = 0; i < sc->pg_pages; i++) { 6017192281Sdelphij bus_dmamap_sync(sc->pg_bd_chain_tag, sc->pg_bd_chain_map[i], 6018176448Sdavidch BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 6019176448Sdavidch } 6020176448Sdavidch 6021218423Sdavidch DBRUNMSG(BCE_EXTREME_RECV, 6022218423Sdavidch bce_dump_pg_chain(sc, 0, TOTAL_PG_BD_ALLOC)); 6023179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD | 6024179771Sdavidch BCE_VERBOSE_CTX); 6025176448Sdavidch return(rc); 6026176448Sdavidch} 6027176448Sdavidch 6028179771Sdavidch 6029176448Sdavidch/****************************************************************************/ 6030176448Sdavidch/* Add mbufs to the page chain until its full or an mbuf allocation error */ 6031176448Sdavidch/* occurs. */ 6032176448Sdavidch/* */ 6033176448Sdavidch/* Returns: */ 6034176448Sdavidch/* Nothing */ 6035176448Sdavidch/****************************************************************************/ 6036176448Sdavidchstatic void 6037176448Sdavidchbce_fill_pg_chain(struct bce_softc *sc) 6038176448Sdavidch{ 6039178132Sdavidch u16 prod, prod_idx; 6040176448Sdavidch 6041179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD | 6042207411Sdavidch BCE_VERBOSE_CTX); 6043176448Sdavidch 6044179771Sdavidch /* Get the page chain prodcuer index. */ 6045176448Sdavidch prod = sc->pg_prod; 6046176448Sdavidch 6047176448Sdavidch /* Keep filling the page chain until it's full. */ 6048176448Sdavidch while (sc->free_pg_bd > 0) { 6049176448Sdavidch prod_idx = PG_CHAIN_IDX(prod); 6050251146Smarius if (bce_get_pg_buf(sc, prod, prod_idx)) { 6051176448Sdavidch /* Bail out if we can't add an mbuf to the chain. */ 6052176448Sdavidch break; 6053178132Sdavidch } 6054176448Sdavidch prod = NEXT_PG_BD(prod); 6055176448Sdavidch } 6056176448Sdavidch 6057176448Sdavidch /* Save the page chain producer index. */ 6058176448Sdavidch sc->pg_prod = prod; 6059176448Sdavidch 6060178132Sdavidch DBRUNIF(((prod & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE), 6061207411Sdavidch BCE_PRINTF("%s(): Invalid pg_prod value: 0x%04X\n", 6062251146Smarius __FUNCTION__, pg_prod)); 6063176448Sdavidch 6064179771Sdavidch /* 6065179771Sdavidch * Write the mailbox and tell the chip about 6066179771Sdavidch * the new rx_bd's in the page chain. 6067179771Sdavidch */ 6068251146Smarius REG_WR16(sc, MB_GET_CID_ADDR(RX_CID) + BCE_L2MQ_RX_HOST_PG_BDIDX, 6069251146Smarius prod); 6070178132Sdavidch 6071179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD | 6072207411Sdavidch BCE_VERBOSE_CTX); 6073176448Sdavidch} 6074176448Sdavidch 6075176448Sdavidch 6076176448Sdavidch/****************************************************************************/ 6077176448Sdavidch/* Free memory and clear the RX data structures. */ 6078176448Sdavidch/* */ 6079176448Sdavidch/* Returns: */ 6080176448Sdavidch/* Nothing. */ 6081176448Sdavidch/****************************************************************************/ 6082176448Sdavidchstatic void 6083176448Sdavidchbce_free_pg_chain(struct bce_softc *sc) 6084176448Sdavidch{ 6085176448Sdavidch int i; 6086176448Sdavidch 6087179771Sdavidch DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD); 6088176448Sdavidch 6089176448Sdavidch /* Free any mbufs still in the mbuf page chain. */ 6090218423Sdavidch for (i = 0; i < MAX_PG_BD_AVAIL; i++) { 6091176448Sdavidch if (sc->pg_mbuf_ptr[i] != NULL) { 6092176448Sdavidch if (sc->pg_mbuf_map[i] != NULL) 6093207411Sdavidch bus_dmamap_sync(sc->pg_mbuf_tag, 6094207411Sdavidch sc->pg_mbuf_map[i], 6095207411Sdavidch BUS_DMASYNC_POSTREAD); 6096176448Sdavidch m_freem(sc->pg_mbuf_ptr[i]); 6097176448Sdavidch sc->pg_mbuf_ptr[i] = NULL; 6098178132Sdavidch DBRUN(sc->debug_pg_mbuf_alloc--); 6099176448Sdavidch } 6100176448Sdavidch } 6101176448Sdavidch 6102176448Sdavidch /* Clear each page chain pages. */ 6103218423Sdavidch for (i = 0; i < sc->pg_pages; i++) 6104176448Sdavidch bzero((char *)sc->pg_bd_chain[i], BCE_PG_CHAIN_PAGE_SZ); 6105176448Sdavidch 6106176448Sdavidch sc->free_pg_bd = sc->max_pg_bd; 6107176448Sdavidch 6108176448Sdavidch /* Check if we lost any mbufs in the process. */ 6109176448Sdavidch DBRUNIF((sc->debug_pg_mbuf_alloc), 6110207411Sdavidch BCE_PRINTF("%s(): Memory leak! Lost %d mbufs from page chain!\n", 6111207411Sdavidch __FUNCTION__, sc->debug_pg_mbuf_alloc)); 6112176448Sdavidch 6113179771Sdavidch DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD); 6114176448Sdavidch} 6115176448Sdavidch 6116176448Sdavidch 6117235151Syongaristatic u32 6118235151Syongaribce_get_rphy_link(struct bce_softc *sc) 6119235151Syongari{ 6120235151Syongari u32 advertise, link; 6121235151Syongari int fdpx; 6122235151Syongari 6123235151Syongari advertise = 0; 6124235151Syongari fdpx = 0; 6125235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) != 0) 6126235151Syongari link = bce_shmem_rd(sc, BCE_RPHY_SERDES_LINK); 6127235151Syongari else 6128235151Syongari link = bce_shmem_rd(sc, BCE_RPHY_COPPER_LINK); 6129235151Syongari if (link & BCE_NETLINK_ANEG_ENB) 6130235151Syongari advertise |= BCE_NETLINK_ANEG_ENB; 6131235151Syongari if (link & BCE_NETLINK_SPEED_10HALF) 6132235151Syongari advertise |= BCE_NETLINK_SPEED_10HALF; 6133235151Syongari if (link & BCE_NETLINK_SPEED_10FULL) { 6134235151Syongari advertise |= BCE_NETLINK_SPEED_10FULL; 6135235151Syongari fdpx++; 6136235151Syongari } 6137235151Syongari if (link & BCE_NETLINK_SPEED_100HALF) 6138235151Syongari advertise |= BCE_NETLINK_SPEED_100HALF; 6139235151Syongari if (link & BCE_NETLINK_SPEED_100FULL) { 6140235151Syongari advertise |= BCE_NETLINK_SPEED_100FULL; 6141235151Syongari fdpx++; 6142235151Syongari } 6143235151Syongari if (link & BCE_NETLINK_SPEED_1000HALF) 6144235151Syongari advertise |= BCE_NETLINK_SPEED_1000HALF; 6145235151Syongari if (link & BCE_NETLINK_SPEED_1000FULL) { 6146235151Syongari advertise |= BCE_NETLINK_SPEED_1000FULL; 6147235151Syongari fdpx++; 6148235151Syongari } 6149235151Syongari if (link & BCE_NETLINK_SPEED_2500HALF) 6150235151Syongari advertise |= BCE_NETLINK_SPEED_2500HALF; 6151235151Syongari if (link & BCE_NETLINK_SPEED_2500FULL) { 6152235151Syongari advertise |= BCE_NETLINK_SPEED_2500FULL; 6153235151Syongari fdpx++; 6154235151Syongari } 6155235151Syongari if (fdpx) 6156235151Syongari advertise |= BCE_NETLINK_FC_PAUSE_SYM | 6157235151Syongari BCE_NETLINK_FC_PAUSE_ASYM; 6158235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) 6159235151Syongari advertise |= BCE_NETLINK_PHY_APP_REMOTE | 6160235151Syongari BCE_NETLINK_ETH_AT_WIRESPEED; 6161235151Syongari 6162235151Syongari return (advertise); 6163235151Syongari} 6164235151Syongari 6165235151Syongari 6166176448Sdavidch/****************************************************************************/ 6167157642Sps/* Set media options. */ 6168157642Sps/* */ 6169157642Sps/* Returns: */ 6170157642Sps/* 0 for success, positive value for failure. */ 6171157642Sps/****************************************************************************/ 6172157642Spsstatic int 6173157642Spsbce_ifmedia_upd(struct ifnet *ifp) 6174157642Sps{ 6175179771Sdavidch struct bce_softc *sc = ifp->if_softc; 6176210261Syongari int error; 6177165994Sjhb 6178179771Sdavidch DBENTER(BCE_VERBOSE); 6179179771Sdavidch 6180165994Sjhb BCE_LOCK(sc); 6181210261Syongari error = bce_ifmedia_upd_locked(ifp); 6182165994Sjhb BCE_UNLOCK(sc); 6183179771Sdavidch 6184179771Sdavidch DBEXIT(BCE_VERBOSE); 6185210261Syongari return (error); 6186165994Sjhb} 6187165994Sjhb 6188170392Sdavidch 6189169632Sdavidch/****************************************************************************/ 6190169632Sdavidch/* Set media options. */ 6191169632Sdavidch/* */ 6192169632Sdavidch/* Returns: */ 6193169632Sdavidch/* Nothing. */ 6194169632Sdavidch/****************************************************************************/ 6195210261Syongaristatic int 6196165994Sjhbbce_ifmedia_upd_locked(struct ifnet *ifp) 6197165994Sjhb{ 6198179771Sdavidch struct bce_softc *sc = ifp->if_softc; 6199157642Sps struct mii_data *mii; 6200221407Smarius struct mii_softc *miisc; 6201235151Syongari struct ifmedia *ifm; 6202235151Syongari u32 link; 6203235151Syongari int error, fdx; 6204170392Sdavidch 6205207411Sdavidch DBENTER(BCE_VERBOSE_PHY); 6206179771Sdavidch 6207210261Syongari error = 0; 6208165994Sjhb BCE_LOCK_ASSERT(sc); 6209157642Sps 6210235151Syongari sc->bce_link_up = FALSE; 6211235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { 6212235151Syongari ifm = &sc->bce_ifmedia; 6213235151Syongari if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 6214235151Syongari return (EINVAL); 6215235151Syongari link = 0; 6216235151Syongari fdx = IFM_OPTIONS(ifm->ifm_media) & IFM_FDX; 6217235151Syongari switch(IFM_SUBTYPE(ifm->ifm_media)) { 6218235151Syongari case IFM_AUTO: 6219235151Syongari /* 6220235151Syongari * Check advertised link of remote PHY by reading 6221235151Syongari * BCE_RPHY_SERDES_LINK or BCE_RPHY_COPPER_LINK. 6222235151Syongari * Always use the same link type of remote PHY. 6223235151Syongari */ 6224235151Syongari link = bce_get_rphy_link(sc); 6225235151Syongari break; 6226235151Syongari case IFM_2500_SX: 6227235151Syongari if ((sc->bce_phy_flags & 6228235151Syongari (BCE_PHY_REMOTE_PORT_FIBER_FLAG | 6229235151Syongari BCE_PHY_2_5G_CAPABLE_FLAG)) == 0) 6230235151Syongari return (EINVAL); 6231235151Syongari /* 6232235151Syongari * XXX 6233235151Syongari * Have to enable forced 2.5Gbps configuration. 6234235151Syongari */ 6235235151Syongari if (fdx != 0) 6236235151Syongari link |= BCE_NETLINK_SPEED_2500FULL; 6237235151Syongari else 6238235151Syongari link |= BCE_NETLINK_SPEED_2500HALF; 6239235151Syongari break; 6240235151Syongari case IFM_1000_SX: 6241235151Syongari if ((sc->bce_phy_flags & 6242235151Syongari BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) 6243235151Syongari return (EINVAL); 6244235151Syongari /* 6245235151Syongari * XXX 6246235151Syongari * Have to disable 2.5Gbps configuration. 6247235151Syongari */ 6248235151Syongari if (fdx != 0) 6249235151Syongari link = BCE_NETLINK_SPEED_1000FULL; 6250235151Syongari else 6251235151Syongari link = BCE_NETLINK_SPEED_1000HALF; 6252235151Syongari break; 6253235151Syongari case IFM_1000_T: 6254235151Syongari if (sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) 6255235151Syongari return (EINVAL); 6256235151Syongari if (fdx != 0) 6257235151Syongari link = BCE_NETLINK_SPEED_1000FULL; 6258235151Syongari else 6259235151Syongari link = BCE_NETLINK_SPEED_1000HALF; 6260235151Syongari break; 6261235151Syongari case IFM_100_TX: 6262235151Syongari if (sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) 6263235151Syongari return (EINVAL); 6264235151Syongari if (fdx != 0) 6265235151Syongari link = BCE_NETLINK_SPEED_100FULL; 6266235151Syongari else 6267235151Syongari link = BCE_NETLINK_SPEED_100HALF; 6268235151Syongari break; 6269235151Syongari case IFM_10_T: 6270235151Syongari if (sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) 6271235151Syongari return (EINVAL); 6272235151Syongari if (fdx != 0) 6273235151Syongari link = BCE_NETLINK_SPEED_10FULL; 6274235151Syongari else 6275235151Syongari link = BCE_NETLINK_SPEED_10HALF; 6276235151Syongari break; 6277235151Syongari default: 6278235151Syongari return (EINVAL); 6279235151Syongari } 6280235151Syongari if (IFM_SUBTYPE(ifm->ifm_media) != IFM_AUTO) { 6281235151Syongari /* 6282235151Syongari * XXX 6283235151Syongari * Advertise pause capability for full-duplex media. 6284235151Syongari */ 6285235151Syongari if (fdx != 0) 6286235151Syongari link |= BCE_NETLINK_FC_PAUSE_SYM | 6287235151Syongari BCE_NETLINK_FC_PAUSE_ASYM; 6288235151Syongari if ((sc->bce_phy_flags & 6289235151Syongari BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) 6290235151Syongari link |= BCE_NETLINK_PHY_APP_REMOTE | 6291235151Syongari BCE_NETLINK_ETH_AT_WIRESPEED; 6292235151Syongari } 6293170392Sdavidch 6294235151Syongari bce_shmem_wr(sc, BCE_MB_ARGS_0, link); 6295235151Syongari error = bce_fw_sync(sc, BCE_DRV_MSG_CODE_CMD_SET_LINK); 6296235151Syongari } else { 6297235151Syongari mii = device_get_softc(sc->bce_miibus); 6298235151Syongari 6299235151Syongari /* Make sure the MII bus has been enumerated. */ 6300235151Syongari if (mii) { 6301235151Syongari LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 6302235151Syongari PHY_RESET(miisc); 6303235151Syongari error = mii_mediachg(mii); 6304235151Syongari } 6305157642Sps } 6306179771Sdavidch 6307207411Sdavidch DBEXIT(BCE_VERBOSE_PHY); 6308210261Syongari return (error); 6309157642Sps} 6310157642Sps 6311157642Sps 6312235151Syongaristatic void 6313235151Syongaribce_ifmedia_sts_rphy(struct bce_softc *sc, struct ifmediareq *ifmr) 6314235151Syongari{ 6315235151Syongari struct ifnet *ifp; 6316235151Syongari u32 link; 6317235151Syongari 6318235151Syongari ifp = sc->bce_ifp; 6319235151Syongari BCE_LOCK_ASSERT(sc); 6320235151Syongari 6321235151Syongari ifmr->ifm_status = IFM_AVALID; 6322235151Syongari ifmr->ifm_active = IFM_ETHER; 6323235151Syongari link = bce_shmem_rd(sc, BCE_LINK_STATUS); 6324235151Syongari /* XXX Handle heart beat status? */ 6325235151Syongari if ((link & BCE_LINK_STATUS_LINK_UP) != 0) 6326235151Syongari ifmr->ifm_status |= IFM_ACTIVE; 6327235151Syongari else { 6328235151Syongari ifmr->ifm_active |= IFM_NONE; 6329235151Syongari ifp->if_baudrate = 0; 6330235151Syongari return; 6331235151Syongari } 6332235151Syongari switch (link & BCE_LINK_STATUS_SPEED_MASK) { 6333235151Syongari case BCE_LINK_STATUS_10HALF: 6334235151Syongari ifmr->ifm_active |= IFM_10_T | IFM_HDX; 6335235151Syongari ifp->if_baudrate = IF_Mbps(10UL); 6336235151Syongari break; 6337235151Syongari case BCE_LINK_STATUS_10FULL: 6338235151Syongari ifmr->ifm_active |= IFM_10_T | IFM_FDX; 6339235151Syongari ifp->if_baudrate = IF_Mbps(10UL); 6340235151Syongari break; 6341235151Syongari case BCE_LINK_STATUS_100HALF: 6342235151Syongari ifmr->ifm_active |= IFM_100_TX | IFM_HDX; 6343235151Syongari ifp->if_baudrate = IF_Mbps(100UL); 6344235151Syongari break; 6345235151Syongari case BCE_LINK_STATUS_100FULL: 6346235151Syongari ifmr->ifm_active |= IFM_100_TX | IFM_FDX; 6347235151Syongari ifp->if_baudrate = IF_Mbps(100UL); 6348235151Syongari break; 6349235151Syongari case BCE_LINK_STATUS_1000HALF: 6350235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) 6351235151Syongari ifmr->ifm_active |= IFM_1000_T | IFM_HDX; 6352235151Syongari else 6353235151Syongari ifmr->ifm_active |= IFM_1000_SX | IFM_HDX; 6354235151Syongari ifp->if_baudrate = IF_Mbps(1000UL); 6355235151Syongari break; 6356235151Syongari case BCE_LINK_STATUS_1000FULL: 6357235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) 6358235151Syongari ifmr->ifm_active |= IFM_1000_T | IFM_FDX; 6359235151Syongari else 6360235151Syongari ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; 6361235151Syongari ifp->if_baudrate = IF_Mbps(1000UL); 6362235151Syongari break; 6363235151Syongari case BCE_LINK_STATUS_2500HALF: 6364235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) { 6365235151Syongari ifmr->ifm_active |= IFM_NONE; 6366235151Syongari return; 6367235151Syongari } else 6368235151Syongari ifmr->ifm_active |= IFM_2500_SX | IFM_HDX; 6369235151Syongari ifp->if_baudrate = IF_Mbps(2500UL); 6370235151Syongari break; 6371235151Syongari case BCE_LINK_STATUS_2500FULL: 6372235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) { 6373235151Syongari ifmr->ifm_active |= IFM_NONE; 6374235151Syongari return; 6375235151Syongari } else 6376235151Syongari ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; 6377235151Syongari ifp->if_baudrate = IF_Mbps(2500UL); 6378235151Syongari break; 6379235151Syongari default: 6380235151Syongari ifmr->ifm_active |= IFM_NONE; 6381235151Syongari return; 6382235151Syongari } 6383235151Syongari 6384235151Syongari if ((link & BCE_LINK_STATUS_RX_FC_ENABLED) != 0) 6385235151Syongari ifmr->ifm_active |= IFM_ETH_RXPAUSE; 6386235151Syongari if ((link & BCE_LINK_STATUS_TX_FC_ENABLED) != 0) 6387235151Syongari ifmr->ifm_active |= IFM_ETH_TXPAUSE; 6388235151Syongari} 6389235151Syongari 6390235151Syongari 6391157642Sps/****************************************************************************/ 6392157642Sps/* Reports current media status. */ 6393157642Sps/* */ 6394157642Sps/* Returns: */ 6395157642Sps/* Nothing. */ 6396157642Sps/****************************************************************************/ 6397157642Spsstatic void 6398157642Spsbce_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 6399157642Sps{ 6400179771Sdavidch struct bce_softc *sc = ifp->if_softc; 6401157642Sps struct mii_data *mii; 6402157642Sps 6403207411Sdavidch DBENTER(BCE_VERBOSE_PHY); 6404157642Sps 6405157642Sps BCE_LOCK(sc); 6406157642Sps 6407210263Syongari if ((ifp->if_flags & IFF_UP) == 0) { 6408210263Syongari BCE_UNLOCK(sc); 6409210263Syongari return; 6410210263Syongari } 6411157642Sps 6412235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) 6413235151Syongari bce_ifmedia_sts_rphy(sc, ifmr); 6414235151Syongari else { 6415235151Syongari mii = device_get_softc(sc->bce_miibus); 6416235151Syongari mii_pollstat(mii); 6417235151Syongari ifmr->ifm_active = mii->mii_media_active; 6418235151Syongari ifmr->ifm_status = mii->mii_media_status; 6419235151Syongari } 6420157642Sps 6421157642Sps BCE_UNLOCK(sc); 6422179771Sdavidch 6423207411Sdavidch DBEXIT(BCE_VERBOSE_PHY); 6424157642Sps} 6425157642Sps 6426157642Sps 6427157642Sps/****************************************************************************/ 6428157642Sps/* Handles PHY generated interrupt events. */ 6429157642Sps/* */ 6430157642Sps/* Returns: */ 6431157642Sps/* Nothing. */ 6432157642Sps/****************************************************************************/ 6433157642Spsstatic void 6434157642Spsbce_phy_intr(struct bce_softc *sc) 6435157642Sps{ 6436157642Sps u32 new_link_state, old_link_state; 6437157642Sps 6438179771Sdavidch DBENTER(BCE_VERBOSE_PHY | BCE_VERBOSE_INTR); 6439179771Sdavidch 6440206268Sdavidch DBRUN(sc->phy_interrupts++); 6441206268Sdavidch 6442157642Sps new_link_state = sc->status_block->status_attn_bits & 6443206268Sdavidch STATUS_ATTN_BITS_LINK_STATE; 6444157642Sps old_link_state = sc->status_block->status_attn_bits_ack & 6445206268Sdavidch STATUS_ATTN_BITS_LINK_STATE; 6446157642Sps 6447157642Sps /* Handle any changes if the link state has changed. */ 6448157642Sps if (new_link_state != old_link_state) { 6449157642Sps 6450206268Sdavidch /* Update the status_attn_bits_ack field. */ 6451157642Sps if (new_link_state) { 6452157642Sps REG_WR(sc, BCE_PCICFG_STATUS_BIT_SET_CMD, 6453206268Sdavidch STATUS_ATTN_BITS_LINK_STATE); 6454179771Sdavidch DBPRINT(sc, BCE_INFO_PHY, "%s(): Link is now UP.\n", 6455206268Sdavidch __FUNCTION__); 6456235151Syongari } else { 6457157642Sps REG_WR(sc, BCE_PCICFG_STATUS_BIT_CLEAR_CMD, 6458206268Sdavidch STATUS_ATTN_BITS_LINK_STATE); 6459179771Sdavidch DBPRINT(sc, BCE_INFO_PHY, "%s(): Link is now DOWN.\n", 6460206268Sdavidch __FUNCTION__); 6461157642Sps } 6462234121Syongari 6463235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { 6464235151Syongari if (new_link_state) { 6465235151Syongari if (bootverbose) 6466235151Syongari if_printf(sc->bce_ifp, "link UP\n"); 6467235151Syongari if_link_state_change(sc->bce_ifp, 6468235151Syongari LINK_STATE_UP); 6469235151Syongari } else { 6470235151Syongari if (bootverbose) 6471235151Syongari if_printf(sc->bce_ifp, "link DOWN\n"); 6472235151Syongari if_link_state_change(sc->bce_ifp, 6473235151Syongari LINK_STATE_DOWN); 6474235151Syongari } 6475235151Syongari } 6476179771Sdavidch /* 6477234121Syongari * Assume link is down and allow 6478234121Syongari * tick routine to update the state 6479234121Syongari * based on the actual media state. 6480179771Sdavidch */ 6481234121Syongari sc->bce_link_up = FALSE; 6482234121Syongari callout_stop(&sc->bce_tick_callout); 6483234121Syongari bce_tick(sc); 6484157642Sps } 6485157642Sps 6486157642Sps /* Acknowledge the link change interrupt. */ 6487157642Sps REG_WR(sc, BCE_EMAC_STATUS, BCE_EMAC_STATUS_LINK_CHANGE); 6488179771Sdavidch 6489179771Sdavidch DBEXIT(BCE_VERBOSE_PHY | BCE_VERBOSE_INTR); 6490157642Sps} 6491157642Sps 6492157642Sps 6493157642Sps/****************************************************************************/ 6494178132Sdavidch/* Reads the receive consumer value from the status block (skipping over */ 6495176448Sdavidch/* chain page pointer if necessary). */ 6496176448Sdavidch/* */ 6497176448Sdavidch/* Returns: */ 6498176448Sdavidch/* hw_cons */ 6499176448Sdavidch/****************************************************************************/ 6500176448Sdavidchstatic inline u16 6501176448Sdavidchbce_get_hw_rx_cons(struct bce_softc *sc) 6502176448Sdavidch{ 6503182293Sdavidch u16 hw_cons; 6504176448Sdavidch 6505182293Sdavidch rmb(); 6506182293Sdavidch hw_cons = sc->status_block->status_rx_quick_consumer_index0; 6507176448Sdavidch if ((hw_cons & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE) 6508176448Sdavidch hw_cons++; 6509176448Sdavidch 6510176448Sdavidch return hw_cons; 6511176448Sdavidch} 6512176448Sdavidch 6513176448Sdavidch/****************************************************************************/ 6514157642Sps/* Handles received frame interrupt events. */ 6515157642Sps/* */ 6516157642Sps/* Returns: */ 6517157642Sps/* Nothing. */ 6518157642Sps/****************************************************************************/ 6519157642Spsstatic void 6520157642Spsbce_rx_intr(struct bce_softc *sc) 6521157642Sps{ 6522178132Sdavidch struct ifnet *ifp = sc->bce_ifp; 6523178132Sdavidch struct l2_fhdr *l2fhdr; 6524204368Syongari struct ether_vlan_header *vh; 6525179695Sdavidch unsigned int pkt_len; 6526179771Sdavidch u16 sw_rx_cons, sw_rx_cons_idx, hw_rx_cons; 6527178132Sdavidch u32 status; 6528179771Sdavidch unsigned int rem_len; 6529179771Sdavidch u16 sw_pg_cons, sw_pg_cons_idx; 6530178132Sdavidch 6531179771Sdavidch DBENTER(BCE_VERBOSE_RECV | BCE_VERBOSE_INTR); 6532207411Sdavidch DBRUN(sc->interrupts_rx++); 6533179771Sdavidch DBPRINT(sc, BCE_EXTREME_RECV, "%s(enter): rx_prod = 0x%04X, " 6534206268Sdavidch "rx_cons = 0x%04X, rx_prod_bseq = 0x%08X\n", 6535206268Sdavidch __FUNCTION__, sc->rx_prod, sc->rx_cons, sc->rx_prod_bseq); 6536178132Sdavidch 6537157642Sps /* Prepare the RX chain pages to be accessed by the host CPU. */ 6538218423Sdavidch for (int i = 0; i < sc->rx_pages; i++) 6539157642Sps bus_dmamap_sync(sc->rx_bd_chain_tag, 6540192281Sdelphij sc->rx_bd_chain_map[i], BUS_DMASYNC_POSTREAD); 6541157642Sps 6542176448Sdavidch /* Prepare the page chain pages to be accessed by the host CPU. */ 6543218423Sdavidch if (bce_hdr_split == TRUE) { 6544218423Sdavidch for (int i = 0; i < sc->pg_pages; i++) 6545218423Sdavidch bus_dmamap_sync(sc->pg_bd_chain_tag, 6546218423Sdavidch sc->pg_bd_chain_map[i], BUS_DMASYNC_POSTREAD); 6547218423Sdavidch } 6548176448Sdavidch 6549157642Sps /* Get the hardware's view of the RX consumer index. */ 6550176448Sdavidch hw_rx_cons = sc->hw_rx_cons = bce_get_hw_rx_cons(sc); 6551157642Sps 6552176448Sdavidch /* Get working copies of the driver's view of the consumer indices. */ 6553176448Sdavidch sw_rx_cons = sc->rx_cons; 6554179771Sdavidch sw_pg_cons = sc->pg_cons; 6555157642Sps 6556170392Sdavidch /* Update some debug statistics counters */ 6557157642Sps DBRUNIF((sc->free_rx_bd < sc->rx_low_watermark), 6558207411Sdavidch sc->rx_low_watermark = sc->free_rx_bd); 6559207411Sdavidch DBRUNIF((sc->free_rx_bd == sc->max_rx_bd), 6560207411Sdavidch sc->rx_empty_count++); 6561157642Sps 6562178132Sdavidch /* Scan through the receive chain as long as there is work to do */ 6563176448Sdavidch /* ToDo: Consider setting a limit on the number of packets processed. */ 6564182293Sdavidch rmb(); 6565176448Sdavidch while (sw_rx_cons != hw_rx_cons) { 6566176448Sdavidch struct mbuf *m0; 6567179771Sdavidch 6568157642Sps /* Convert the producer/consumer indices to an actual rx_bd index. */ 6569176448Sdavidch sw_rx_cons_idx = RX_CHAIN_IDX(sw_rx_cons); 6570157642Sps 6571176448Sdavidch /* Unmap the mbuf from DMA space. */ 6572207411Sdavidch bus_dmamap_sync(sc->rx_mbuf_tag, 6573206268Sdavidch sc->rx_mbuf_map[sw_rx_cons_idx], 6574192281Sdelphij BUS_DMASYNC_POSTREAD); 6575176448Sdavidch bus_dmamap_unload(sc->rx_mbuf_tag, 6576176448Sdavidch sc->rx_mbuf_map[sw_rx_cons_idx]); 6577157642Sps 6578176448Sdavidch /* Remove the mbuf from the RX chain. */ 6579176448Sdavidch m0 = sc->rx_mbuf_ptr[sw_rx_cons_idx]; 6580176448Sdavidch sc->rx_mbuf_ptr[sw_rx_cons_idx] = NULL; 6581176448Sdavidch DBRUN(sc->debug_rx_mbuf_alloc--); 6582176448Sdavidch sc->free_rx_bd++; 6583179771Sdavidch 6584206268Sdavidch /* 6585207411Sdavidch * Frames received on the NetXteme II are prepended 6586207411Sdavidch * with an l2_fhdr structure which provides status 6587207411Sdavidch * information about the received frame (including 6588207411Sdavidch * VLAN tags and checksum info). The frames are 6589218423Sdavidch * also automatically adjusted to word align the IP 6590207411Sdavidch * header (i.e. two null bytes are inserted before 6591207411Sdavidch * the Ethernet header). As a result the data 6592207411Sdavidch * DMA'd by the controller into the mbuf looks 6593207411Sdavidch * like this: 6594207411Sdavidch * 6595206268Sdavidch * +---------+-----+---------------------+-----+ 6596206268Sdavidch * | l2_fhdr | pad | packet data | FCS | 6597206268Sdavidch * +---------+-----+---------------------+-----+ 6598207411Sdavidch * 6599207411Sdavidch * The l2_fhdr needs to be checked and skipped and 6600207411Sdavidch * the FCS needs to be stripped before sending the 6601207411Sdavidch * packet up the stack. 6602206268Sdavidch */ 6603176448Sdavidch l2fhdr = mtod(m0, struct l2_fhdr *); 6604157642Sps 6605176448Sdavidch /* Get the packet data + FCS length and the status. */ 6606176448Sdavidch pkt_len = l2fhdr->l2_fhdr_pkt_len; 6607176448Sdavidch status = l2fhdr->l2_fhdr_status; 6608178132Sdavidch 6609176448Sdavidch /* 6610178132Sdavidch * Skip over the l2_fhdr and pad, resulting in the 6611179771Sdavidch * following data in the mbuf: 6612178132Sdavidch * +---------------------+-----+ 6613178132Sdavidch * | packet data | FCS | 6614178132Sdavidch * +---------------------+-----+ 6615178132Sdavidch */ 6616176448Sdavidch m_adj(m0, sizeof(struct l2_fhdr) + ETHER_ALIGN); 6617178132Sdavidch 6618178132Sdavidch /* 6619218423Sdavidch * When split header mode is used, an ethernet frame 6620218423Sdavidch * may be split across the receive chain and the 6621218423Sdavidch * page chain. If that occurs an mbuf cluster must be 6622218423Sdavidch * reassembled from the individual mbuf pieces. 6623176448Sdavidch */ 6624218423Sdavidch if (bce_hdr_split == TRUE) { 6625170392Sdavidch /* 6626218423Sdavidch * Check whether the received frame fits in a single 6627218423Sdavidch * mbuf or not (i.e. packet data + FCS <= 6628218423Sdavidch * sc->rx_bd_mbuf_data_len bytes). 6629169632Sdavidch */ 6630218423Sdavidch if (pkt_len > m0->m_len) { 6631218423Sdavidch /* 6632218423Sdavidch * The received frame is larger than a single mbuf. 6633218423Sdavidch * If the frame was a TCP frame then only the TCP 6634218423Sdavidch * header is placed in the mbuf, the remaining 6635218423Sdavidch * payload (including FCS) is placed in the page 6636218423Sdavidch * chain, the SPLIT flag is set, and the header 6637218423Sdavidch * length is placed in the IP checksum field. 6638218423Sdavidch * If the frame is not a TCP frame then the mbuf 6639218423Sdavidch * is filled and the remaining bytes are placed 6640218423Sdavidch * in the page chain. 6641218423Sdavidch */ 6642178132Sdavidch 6643218423Sdavidch DBPRINT(sc, BCE_INFO_RECV, "%s(): Found a large " 6644218423Sdavidch "packet.\n", __FUNCTION__); 6645218423Sdavidch DBRUN(sc->split_header_frames_rcvd++); 6646178132Sdavidch 6647218423Sdavidch /* 6648218423Sdavidch * When the page chain is enabled and the TCP 6649218423Sdavidch * header has been split from the TCP payload, 6650218423Sdavidch * the ip_xsum structure will reflect the length 6651218423Sdavidch * of the TCP header, not the IP checksum. Set 6652218423Sdavidch * the packet length of the mbuf accordingly. 6653218423Sdavidch */ 6654218423Sdavidch if (status & L2_FHDR_STATUS_SPLIT) { 6655218423Sdavidch m0->m_len = l2fhdr->l2_fhdr_ip_xsum; 6656218423Sdavidch DBRUN(sc->split_header_tcp_frames_rcvd++); 6657218423Sdavidch } 6658178132Sdavidch 6659218423Sdavidch rem_len = pkt_len - m0->m_len; 6660178132Sdavidch 6661218423Sdavidch /* Pull mbufs off the page chain for any remaining data. */ 6662218423Sdavidch while (rem_len > 0) { 6663218423Sdavidch struct mbuf *m_pg; 6664179771Sdavidch 6665218423Sdavidch sw_pg_cons_idx = PG_CHAIN_IDX(sw_pg_cons); 6666178132Sdavidch 6667218423Sdavidch /* Remove the mbuf from the page chain. */ 6668218423Sdavidch m_pg = sc->pg_mbuf_ptr[sw_pg_cons_idx]; 6669218423Sdavidch sc->pg_mbuf_ptr[sw_pg_cons_idx] = NULL; 6670218423Sdavidch DBRUN(sc->debug_pg_mbuf_alloc--); 6671218423Sdavidch sc->free_pg_bd++; 6672157642Sps 6673218423Sdavidch /* Unmap the page chain mbuf from DMA space. */ 6674218423Sdavidch bus_dmamap_sync(sc->pg_mbuf_tag, 6675218423Sdavidch sc->pg_mbuf_map[sw_pg_cons_idx], 6676218423Sdavidch BUS_DMASYNC_POSTREAD); 6677218423Sdavidch bus_dmamap_unload(sc->pg_mbuf_tag, 6678218423Sdavidch sc->pg_mbuf_map[sw_pg_cons_idx]); 6679157642Sps 6680218423Sdavidch /* Adjust the mbuf length. */ 6681218423Sdavidch if (rem_len < m_pg->m_len) { 6682218423Sdavidch /* The mbuf chain is complete. */ 6683218423Sdavidch m_pg->m_len = rem_len; 6684218423Sdavidch rem_len = 0; 6685218423Sdavidch } else { 6686218423Sdavidch /* More packet data is waiting. */ 6687218423Sdavidch rem_len -= m_pg->m_len; 6688218423Sdavidch } 6689178132Sdavidch 6690218423Sdavidch /* Concatenate the mbuf cluster to the mbuf. */ 6691218423Sdavidch m_cat(m0, m_pg); 6692157642Sps 6693218423Sdavidch sw_pg_cons = NEXT_PG_BD(sw_pg_cons); 6694218423Sdavidch } 6695176448Sdavidch 6696218423Sdavidch /* Set the total packet length. */ 6697218423Sdavidch m0->m_pkthdr.len = pkt_len; 6698178132Sdavidch 6699218423Sdavidch } else { 6700218423Sdavidch /* 6701218423Sdavidch * The received packet is small and fits in a 6702218423Sdavidch * single mbuf (i.e. the l2_fhdr + pad + packet + 6703218423Sdavidch * FCS <= MHLEN). In other words, the packet is 6704218423Sdavidch * 154 bytes or less in size. 6705218423Sdavidch */ 6706157642Sps 6707218423Sdavidch DBPRINT(sc, BCE_INFO_RECV, "%s(): Found a small " 6708218423Sdavidch "packet.\n", __FUNCTION__); 6709178132Sdavidch 6710218423Sdavidch /* Set the total packet length. */ 6711218423Sdavidch m0->m_pkthdr.len = m0->m_len = pkt_len; 6712218423Sdavidch } 6713218423Sdavidch } else 6714176448Sdavidch /* Set the total packet length. */ 6715176448Sdavidch m0->m_pkthdr.len = m0->m_len = pkt_len; 6716178132Sdavidch 6717178132Sdavidch /* Remove the trailing Ethernet FCS. */ 6718178132Sdavidch m_adj(m0, -ETHER_CRC_LEN); 6719178132Sdavidch 6720176448Sdavidch /* Check that the resulting mbuf chain is valid. */ 6721176448Sdavidch DBRUN(m_sanity(m0, FALSE)); 6722179771Sdavidch DBRUNIF(((m0->m_len < ETHER_HDR_LEN) | 6723206268Sdavidch (m0->m_pkthdr.len > BCE_MAX_JUMBO_ETHER_MTU_VLAN)), 6724218423Sdavidch BCE_PRINTF("Invalid Ethernet frame size!\n"); 6725218423Sdavidch m_print(m0, 128)); 6726157642Sps 6727189325Sdavidch DBRUNIF(DB_RANDOMTRUE(l2fhdr_error_sim_control), 6728206268Sdavidch sc->l2fhdr_error_sim_count++; 6729206268Sdavidch status = status | L2_FHDR_ERRORS_PHY_DECODE); 6730157642Sps 6731176448Sdavidch /* Check the received frame for errors. */ 6732207411Sdavidch if (status & (L2_FHDR_ERRORS_BAD_CRC | 6733206268Sdavidch L2_FHDR_ERRORS_PHY_DECODE | L2_FHDR_ERRORS_ALIGNMENT | 6734206268Sdavidch L2_FHDR_ERRORS_TOO_SHORT | L2_FHDR_ERRORS_GIANT_FRAME)) { 6735157642Sps 6736176448Sdavidch /* Log the error and release the mbuf. */ 6737176448Sdavidch ifp->if_ierrors++; 6738189325Sdavidch sc->l2fhdr_error_count++; 6739179771Sdavidch 6740176448Sdavidch m_freem(m0); 6741176448Sdavidch m0 = NULL; 6742251146Smarius goto bce_rx_intr_next_rx; 6743176448Sdavidch } 6744157642Sps 6745176448Sdavidch /* Send the packet to the appropriate interface. */ 6746176448Sdavidch m0->m_pkthdr.rcvif = ifp; 6747178132Sdavidch 6748178132Sdavidch /* Assume no hardware checksum. */ 6749176448Sdavidch m0->m_pkthdr.csum_flags = 0; 6750178132Sdavidch 6751176448Sdavidch /* Validate the checksum if offload enabled. */ 6752176448Sdavidch if (ifp->if_capenable & IFCAP_RXCSUM) { 6753176448Sdavidch /* Check for an IP datagram. */ 6754178132Sdavidch if (!(status & L2_FHDR_STATUS_SPLIT) && 6755207411Sdavidch (status & L2_FHDR_STATUS_IP_DATAGRAM)) { 6756176448Sdavidch m0->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 6757207411Sdavidch DBRUN(sc->csum_offload_ip++); 6758176448Sdavidch /* Check if the IP checksum is valid. */ 6759176448Sdavidch if ((l2fhdr->l2_fhdr_ip_xsum ^ 0xffff) == 0) 6760207411Sdavidch m0->m_pkthdr.csum_flags |= 6761206268Sdavidch CSUM_IP_VALID; 6762178132Sdavidch } 6763157642Sps 6764176448Sdavidch /* Check for a valid TCP/UDP frame. */ 6765176448Sdavidch if (status & (L2_FHDR_STATUS_TCP_SEGMENT | 6766206268Sdavidch L2_FHDR_STATUS_UDP_DATAGRAM)) { 6767157642Sps 6768176448Sdavidch /* Check for a good TCP/UDP checksum. */ 6769176448Sdavidch if ((status & (L2_FHDR_ERRORS_TCP_XSUM | 6770206268Sdavidch L2_FHDR_ERRORS_UDP_XSUM)) == 0) { 6771207411Sdavidch DBRUN(sc->csum_offload_tcp_udp++); 6772176448Sdavidch m0->m_pkthdr.csum_data = 6773176448Sdavidch l2fhdr->l2_fhdr_tcp_udp_xsum; 6774207411Sdavidch m0->m_pkthdr.csum_flags |= 6775206268Sdavidch (CSUM_DATA_VALID 6776206268Sdavidch | CSUM_PSEUDO_HDR); 6777157642Sps } 6778176448Sdavidch } 6779179771Sdavidch } 6780157642Sps 6781189325Sdavidch /* Attach the VLAN tag. */ 6782251146Smarius if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && 6783251146Smarius !(sc->rx_mode & BCE_EMAC_RX_MODE_KEEP_VLAN_TAG)) { 6784218423Sdavidch DBRUN(sc->vlan_tagged_frames_rcvd++); 6785204368Syongari if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) { 6786218423Sdavidch DBRUN(sc->vlan_tagged_frames_stripped++); 6787157642Sps#if __FreeBSD_version < 700000 6788204368Syongari VLAN_INPUT_TAG(ifp, m0, 6789204368Syongari l2fhdr->l2_fhdr_vlan_tag, continue); 6790157642Sps#else 6791204368Syongari m0->m_pkthdr.ether_vtag = 6792204368Syongari l2fhdr->l2_fhdr_vlan_tag; 6793204368Syongari m0->m_flags |= M_VLANTAG; 6794179771Sdavidch#endif 6795204368Syongari } else { 6796204368Syongari /* 6797204368Syongari * bce(4) controllers can't disable VLAN 6798204368Syongari * tag stripping if management firmware 6799204368Syongari * (ASF/IPMI/UMP) is running. So we always 6800204368Syongari * strip VLAN tag and manually reconstruct 6801204368Syongari * the VLAN frame by appending stripped 6802204368Syongari * VLAN tag in driver if VLAN tag stripping 6803204368Syongari * was disabled. 6804204368Syongari * 6805204368Syongari * TODO: LLC SNAP handling. 6806204368Syongari */ 6807204368Syongari bcopy(mtod(m0, uint8_t *), 6808204368Syongari mtod(m0, uint8_t *) - ETHER_VLAN_ENCAP_LEN, 6809204368Syongari ETHER_ADDR_LEN * 2); 6810204368Syongari m0->m_data -= ETHER_VLAN_ENCAP_LEN; 6811204368Syongari vh = mtod(m0, struct ether_vlan_header *); 6812204368Syongari vh->evl_encap_proto = htons(ETHERTYPE_VLAN); 6813204368Syongari vh->evl_tag = htons(l2fhdr->l2_fhdr_vlan_tag); 6814204368Syongari m0->m_pkthdr.len += ETHER_VLAN_ENCAP_LEN; 6815204368Syongari m0->m_len += ETHER_VLAN_ENCAP_LEN; 6816204368Syongari } 6817176448Sdavidch } 6818157642Sps 6819189325Sdavidch /* Increment received packet statistics. */ 6820176448Sdavidch ifp->if_ipackets++; 6821157642Sps 6822251146Smariusbce_rx_intr_next_rx: 6823176448Sdavidch sw_rx_cons = NEXT_RX_BD(sw_rx_cons); 6824157642Sps 6825170392Sdavidch /* If we have a packet, pass it up the stack */ 6826176448Sdavidch if (m0) { 6827170392Sdavidch /* Make sure we don't lose our place when we release the lock. */ 6828178132Sdavidch sc->rx_cons = sw_rx_cons; 6829179771Sdavidch sc->pg_cons = sw_pg_cons; 6830170392Sdavidch 6831169271Sdavidch BCE_UNLOCK(sc); 6832176448Sdavidch (*ifp->if_input)(ifp, m0); 6833170392Sdavidch BCE_LOCK(sc); 6834179771Sdavidch 6835170392Sdavidch /* Recover our place. */ 6836178132Sdavidch sw_rx_cons = sc->rx_cons; 6837179771Sdavidch sw_pg_cons = sc->pg_cons; 6838170392Sdavidch } 6839170392Sdavidch 6840157642Sps /* Refresh hw_cons to see if there's new work */ 6841176448Sdavidch if (sw_rx_cons == hw_rx_cons) 6842176448Sdavidch hw_rx_cons = sc->hw_rx_cons = bce_get_hw_rx_cons(sc); 6843157642Sps } 6844157642Sps 6845207411Sdavidch /* No new packets. Refill the page chain. */ 6846218423Sdavidch if (bce_hdr_split == TRUE) { 6847218423Sdavidch sc->pg_cons = sw_pg_cons; 6848218423Sdavidch bce_fill_pg_chain(sc); 6849218423Sdavidch } 6850176448Sdavidch 6851207411Sdavidch /* No new packets. Refill the RX chain. */ 6852176448Sdavidch sc->rx_cons = sw_rx_cons; 6853171667Sdavidch bce_fill_rx_chain(sc); 6854171667Sdavidch 6855192281Sdelphij /* Prepare the page chain pages to be accessed by the NIC. */ 6856218423Sdavidch for (int i = 0; i < sc->rx_pages; i++) 6857157642Sps bus_dmamap_sync(sc->rx_bd_chain_tag, 6858157642Sps sc->rx_bd_chain_map[i], BUS_DMASYNC_PREWRITE); 6859157642Sps 6860218423Sdavidch if (bce_hdr_split == TRUE) { 6861218423Sdavidch for (int i = 0; i < sc->pg_pages; i++) 6862218423Sdavidch bus_dmamap_sync(sc->pg_bd_chain_tag, 6863218423Sdavidch sc->pg_bd_chain_map[i], BUS_DMASYNC_PREWRITE); 6864218423Sdavidch } 6865176448Sdavidch 6866179771Sdavidch DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): rx_prod = 0x%04X, " 6867206268Sdavidch "rx_cons = 0x%04X, rx_prod_bseq = 0x%08X\n", 6868206268Sdavidch __FUNCTION__, sc->rx_prod, sc->rx_cons, sc->rx_prod_bseq); 6869179771Sdavidch DBEXIT(BCE_VERBOSE_RECV | BCE_VERBOSE_INTR); 6870157642Sps} 6871157642Sps 6872157642Sps 6873157642Sps/****************************************************************************/ 6874178132Sdavidch/* Reads the transmit consumer value from the status block (skipping over */ 6875178132Sdavidch/* chain page pointer if necessary). */ 6876178132Sdavidch/* */ 6877178132Sdavidch/* Returns: */ 6878178132Sdavidch/* hw_cons */ 6879178132Sdavidch/****************************************************************************/ 6880178132Sdavidchstatic inline u16 6881178132Sdavidchbce_get_hw_tx_cons(struct bce_softc *sc) 6882178132Sdavidch{ 6883182293Sdavidch u16 hw_cons; 6884178132Sdavidch 6885182293Sdavidch mb(); 6886182293Sdavidch hw_cons = sc->status_block->status_tx_quick_consumer_index0; 6887178132Sdavidch if ((hw_cons & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE) 6888178132Sdavidch hw_cons++; 6889178132Sdavidch 6890178132Sdavidch return hw_cons; 6891178132Sdavidch} 6892178132Sdavidch 6893178132Sdavidch 6894178132Sdavidch/****************************************************************************/ 6895157642Sps/* Handles transmit completion interrupt events. */ 6896157642Sps/* */ 6897157642Sps/* Returns: */ 6898157642Sps/* Nothing. */ 6899157642Sps/****************************************************************************/ 6900157642Spsstatic void 6901157642Spsbce_tx_intr(struct bce_softc *sc) 6902157642Sps{ 6903157642Sps struct ifnet *ifp = sc->bce_ifp; 6904157642Sps u16 hw_tx_cons, sw_tx_cons, sw_tx_chain_cons; 6905178132Sdavidch 6906179771Sdavidch DBENTER(BCE_VERBOSE_SEND | BCE_VERBOSE_INTR); 6907207411Sdavidch DBRUN(sc->interrupts_tx++); 6908179771Sdavidch DBPRINT(sc, BCE_EXTREME_SEND, "%s(enter): tx_prod = 0x%04X, " 6909206268Sdavidch "tx_cons = 0x%04X, tx_prod_bseq = 0x%08X\n", 6910206268Sdavidch __FUNCTION__, sc->tx_prod, sc->tx_cons, sc->tx_prod_bseq); 6911157642Sps 6912157642Sps BCE_LOCK_ASSERT(sc); 6913157642Sps 6914157642Sps /* Get the hardware's view of the TX consumer index. */ 6915178132Sdavidch hw_tx_cons = sc->hw_tx_cons = bce_get_hw_tx_cons(sc); 6916157642Sps sw_tx_cons = sc->tx_cons; 6917157642Sps 6918207411Sdavidch /* Prevent speculative reads of the status block. */ 6919179771Sdavidch bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0, 6920206268Sdavidch BUS_SPACE_BARRIER_READ); 6921157642Sps 6922157642Sps /* Cycle through any completed TX chain page entries. */ 6923157642Sps while (sw_tx_cons != hw_tx_cons) { 6924157642Sps#ifdef BCE_DEBUG 6925157642Sps struct tx_bd *txbd = NULL; 6926157642Sps#endif 6927157642Sps sw_tx_chain_cons = TX_CHAIN_IDX(sw_tx_cons); 6928157642Sps 6929157642Sps DBPRINT(sc, BCE_INFO_SEND, 6930206268Sdavidch "%s(): hw_tx_cons = 0x%04X, sw_tx_cons = 0x%04X, " 6931206268Sdavidch "sw_tx_chain_cons = 0x%04X\n", 6932206268Sdavidch __FUNCTION__, hw_tx_cons, sw_tx_cons, sw_tx_chain_cons); 6933157642Sps 6934218423Sdavidch DBRUNIF((sw_tx_chain_cons > MAX_TX_BD_ALLOC), 6935206268Sdavidch BCE_PRINTF("%s(%d): TX chain consumer out of range! " 6936206268Sdavidch " 0x%04X > 0x%04X\n", __FILE__, __LINE__, sw_tx_chain_cons, 6937218423Sdavidch (int) MAX_TX_BD_ALLOC); 6938206268Sdavidch bce_breakpoint(sc)); 6939157642Sps 6940176448Sdavidch DBRUN(txbd = &sc->tx_bd_chain[TX_PAGE(sw_tx_chain_cons)] 6941206268Sdavidch [TX_IDX(sw_tx_chain_cons)]); 6942179771Sdavidch 6943157642Sps DBRUNIF((txbd == NULL), 6944206268Sdavidch BCE_PRINTF("%s(%d): Unexpected NULL tx_bd[0x%04X]!\n", 6945206268Sdavidch __FILE__, __LINE__, sw_tx_chain_cons); 6946206268Sdavidch bce_breakpoint(sc)); 6947157642Sps 6948176448Sdavidch DBRUNMSG(BCE_INFO_SEND, BCE_PRINTF("%s(): ", __FUNCTION__); 6949206268Sdavidch bce_dump_txbd(sc, sw_tx_chain_cons, txbd)); 6950157642Sps 6951157642Sps /* 6952157642Sps * Free the associated mbuf. Remember 6953157642Sps * that only the last tx_bd of a packet 6954157642Sps * has an mbuf pointer and DMA map. 6955157642Sps */ 6956157642Sps if (sc->tx_mbuf_ptr[sw_tx_chain_cons] != NULL) { 6957157642Sps 6958157642Sps /* Validate that this is the last tx_bd. */ 6959164329Sscottl DBRUNIF((!(txbd->tx_bd_flags & TX_BD_FLAGS_END)), 6960206268Sdavidch BCE_PRINTF("%s(%d): tx_bd END flag not set but " 6961206268Sdavidch "txmbuf == NULL!\n", __FILE__, __LINE__); 6962206268Sdavidch bce_breakpoint(sc)); 6963157642Sps 6964179771Sdavidch DBRUNMSG(BCE_INFO_SEND, 6965206268Sdavidch BCE_PRINTF("%s(): Unloading map/freeing mbuf " 6966207411Sdavidch "from tx_bd[0x%04X]\n", __FUNCTION__, 6967206268Sdavidch sw_tx_chain_cons)); 6968157642Sps 6969157642Sps /* Unmap the mbuf. */ 6970157642Sps bus_dmamap_unload(sc->tx_mbuf_tag, 6971157642Sps sc->tx_mbuf_map[sw_tx_chain_cons]); 6972179771Sdavidch 6973157642Sps /* Free the mbuf. */ 6974157642Sps m_freem(sc->tx_mbuf_ptr[sw_tx_chain_cons]); 6975157642Sps sc->tx_mbuf_ptr[sw_tx_chain_cons] = NULL; 6976176448Sdavidch DBRUN(sc->debug_tx_mbuf_alloc--); 6977157642Sps 6978157642Sps ifp->if_opackets++; 6979157642Sps } 6980157642Sps 6981157642Sps sc->used_tx_bd--; 6982157642Sps sw_tx_cons = NEXT_TX_BD(sw_tx_cons); 6983157642Sps 6984157642Sps /* Refresh hw_cons to see if there's new work. */ 6985178132Sdavidch hw_tx_cons = sc->hw_tx_cons = bce_get_hw_tx_cons(sc); 6986157642Sps 6987206268Sdavidch /* Prevent speculative reads of the status block. */ 6988179771Sdavidch bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0, 6989206268Sdavidch BUS_SPACE_BARRIER_READ); 6990157642Sps } 6991157642Sps 6992157642Sps /* Clear the TX timeout timer. */ 6993165933Sdelphij sc->watchdog_timer = 0; 6994157642Sps 6995157642Sps /* Clear the tx hardware queue full flag. */ 6996169632Sdavidch if (sc->used_tx_bd < sc->max_tx_bd) { 6997169632Sdavidch DBRUNIF((ifp->if_drv_flags & IFF_DRV_OACTIVE), 6998206268Sdavidch DBPRINT(sc, BCE_INFO_SEND, 6999206268Sdavidch "%s(): Open TX chain! %d/%d (used/total)\n", 7000206268Sdavidch __FUNCTION__, sc->used_tx_bd, sc->max_tx_bd)); 7001157642Sps ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 7002157642Sps } 7003157642Sps 7004157642Sps sc->tx_cons = sw_tx_cons; 7005179771Sdavidch 7006179771Sdavidch DBPRINT(sc, BCE_EXTREME_SEND, "%s(exit): tx_prod = 0x%04X, " 7007206268Sdavidch "tx_cons = 0x%04X, tx_prod_bseq = 0x%08X\n", 7008206268Sdavidch __FUNCTION__, sc->tx_prod, sc->tx_cons, sc->tx_prod_bseq); 7009179771Sdavidch DBEXIT(BCE_VERBOSE_SEND | BCE_VERBOSE_INTR); 7010157642Sps} 7011157642Sps 7012157642Sps 7013157642Sps/****************************************************************************/ 7014157642Sps/* Disables interrupt generation. */ 7015157642Sps/* */ 7016157642Sps/* Returns: */ 7017157642Sps/* Nothing. */ 7018157642Sps/****************************************************************************/ 7019157642Spsstatic void 7020157642Spsbce_disable_intr(struct bce_softc *sc) 7021157642Sps{ 7022179771Sdavidch DBENTER(BCE_VERBOSE_INTR); 7023179771Sdavidch 7024179771Sdavidch REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, BCE_PCICFG_INT_ACK_CMD_MASK_INT); 7025157642Sps REG_RD(sc, BCE_PCICFG_INT_ACK_CMD); 7026179771Sdavidch 7027179771Sdavidch DBEXIT(BCE_VERBOSE_INTR); 7028157642Sps} 7029157642Sps 7030157642Sps 7031157642Sps/****************************************************************************/ 7032157642Sps/* Enables interrupt generation. */ 7033157642Sps/* */ 7034157642Sps/* Returns: */ 7035157642Sps/* Nothing. */ 7036157642Sps/****************************************************************************/ 7037157642Spsstatic void 7038179771Sdavidchbce_enable_intr(struct bce_softc *sc, int coal_now) 7039157642Sps{ 7040179771Sdavidch DBENTER(BCE_VERBOSE_INTR); 7041157642Sps 7042157642Sps REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, 7043206268Sdavidch BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | 7044206268Sdavidch BCE_PCICFG_INT_ACK_CMD_MASK_INT | sc->last_status_idx); 7045157642Sps 7046157642Sps REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, 7047206268Sdavidch BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx); 7048157642Sps 7049179771Sdavidch /* Force an immediate interrupt (whether there is new data or not). */ 7050179771Sdavidch if (coal_now) 7051179771Sdavidch REG_WR(sc, BCE_HC_COMMAND, sc->hc_command | BCE_HC_COMMAND_COAL_NOW); 7052179771Sdavidch 7053179771Sdavidch DBEXIT(BCE_VERBOSE_INTR); 7054157642Sps} 7055157642Sps 7056157642Sps 7057157642Sps/****************************************************************************/ 7058157642Sps/* Handles controller initialization. */ 7059157642Sps/* */ 7060157642Sps/* Returns: */ 7061157642Sps/* Nothing. */ 7062157642Sps/****************************************************************************/ 7063157642Spsstatic void 7064157642Spsbce_init_locked(struct bce_softc *sc) 7065157642Sps{ 7066157642Sps struct ifnet *ifp; 7067176448Sdavidch u32 ether_mtu = 0; 7068157642Sps 7069179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 7070157642Sps 7071157642Sps BCE_LOCK_ASSERT(sc); 7072157642Sps 7073157642Sps ifp = sc->bce_ifp; 7074157642Sps 7075157642Sps /* Check if the driver is still running and bail out if it is. */ 7076157642Sps if (ifp->if_drv_flags & IFF_DRV_RUNNING) 7077157642Sps goto bce_init_locked_exit; 7078157642Sps 7079157642Sps bce_stop(sc); 7080157642Sps 7081157642Sps if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) { 7082179771Sdavidch BCE_PRINTF("%s(%d): Controller reset failed!\n", 7083206268Sdavidch __FILE__, __LINE__); 7084157642Sps goto bce_init_locked_exit; 7085157642Sps } 7086157642Sps 7087157642Sps if (bce_chipinit(sc)) { 7088179771Sdavidch BCE_PRINTF("%s(%d): Controller initialization failed!\n", 7089206268Sdavidch __FILE__, __LINE__); 7090157642Sps goto bce_init_locked_exit; 7091157642Sps } 7092157642Sps 7093157642Sps if (bce_blockinit(sc)) { 7094179771Sdavidch BCE_PRINTF("%s(%d): Block initialization failed!\n", 7095206268Sdavidch __FILE__, __LINE__); 7096157642Sps goto bce_init_locked_exit; 7097157642Sps } 7098157642Sps 7099157642Sps /* Load our MAC address. */ 7100157642Sps bcopy(IF_LLADDR(sc->bce_ifp), sc->eaddr, ETHER_ADDR_LEN); 7101157642Sps bce_set_mac_addr(sc); 7102157642Sps 7103235119Syongari if (bce_hdr_split == FALSE) 7104235119Syongari bce_get_rx_buffer_sizes(sc, ifp->if_mtu); 7105182293Sdavidch /* 7106182293Sdavidch * Calculate and program the hardware Ethernet MTU 7107218423Sdavidch * size. Be generous on the receive if we have room 7108218423Sdavidch * and allowed by the user. 7109179695Sdavidch */ 7110218423Sdavidch if (bce_strict_rx_mtu == TRUE) 7111179771Sdavidch ether_mtu = ifp->if_mtu; 7112218423Sdavidch else { 7113218423Sdavidch if (bce_hdr_split == TRUE) { 7114251142Smarius if (ifp->if_mtu <= sc->rx_bd_mbuf_data_len + MCLBYTES) 7115251142Smarius ether_mtu = sc->rx_bd_mbuf_data_len + 7116251142Smarius MCLBYTES; 7117218423Sdavidch else 7118218423Sdavidch ether_mtu = ifp->if_mtu; 7119218423Sdavidch } else { 7120218423Sdavidch if (ifp->if_mtu <= sc->rx_bd_mbuf_data_len) 7121218423Sdavidch ether_mtu = sc->rx_bd_mbuf_data_len; 7122218423Sdavidch else 7123218423Sdavidch ether_mtu = ifp->if_mtu; 7124218423Sdavidch } 7125218423Sdavidch } 7126178132Sdavidch 7127176448Sdavidch ether_mtu += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN; 7128157642Sps 7129207411Sdavidch DBPRINT(sc, BCE_INFO_MISC, "%s(): setting h/w mtu = %d\n", 7130206268Sdavidch __FUNCTION__, ether_mtu); 7131157642Sps 7132176448Sdavidch /* Program the mtu, enabling jumbo frame support if necessary. */ 7133176448Sdavidch if (ether_mtu > (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN)) 7134179771Sdavidch REG_WR(sc, BCE_EMAC_RX_MTU_SIZE, 7135206268Sdavidch min(ether_mtu, BCE_MAX_JUMBO_ETHER_MTU) | 7136206268Sdavidch BCE_EMAC_RX_MTU_SIZE_JUMBO_ENA); 7137176448Sdavidch else 7138157642Sps REG_WR(sc, BCE_EMAC_RX_MTU_SIZE, ether_mtu); 7139157642Sps 7140157642Sps /* Program appropriate promiscuous/multicast filtering. */ 7141157642Sps bce_set_rx_mode(sc); 7142157642Sps 7143218423Sdavidch if (bce_hdr_split == TRUE) { 7144218423Sdavidch /* Init page buffer descriptor chain. */ 7145218423Sdavidch bce_init_pg_chain(sc); 7146218423Sdavidch } 7147176448Sdavidch 7148157642Sps /* Init RX buffer descriptor chain. */ 7149157642Sps bce_init_rx_chain(sc); 7150179771Sdavidch 7151157642Sps /* Init TX buffer descriptor chain. */ 7152157642Sps bce_init_tx_chain(sc); 7153157642Sps 7154157642Sps /* Enable host interrupts. */ 7155179771Sdavidch bce_enable_intr(sc, 1); 7156157642Sps 7157234121Syongari bce_ifmedia_upd_locked(ifp); 7158234121Syongari 7159202717Sdavidch /* Let the OS know the driver is up and running. */ 7160157642Sps ifp->if_drv_flags |= IFF_DRV_RUNNING; 7161157642Sps ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 7162157642Sps 7163170810Sdavidch callout_reset(&sc->bce_tick_callout, hz, bce_tick, sc); 7164157642Sps 7165157642Spsbce_init_locked_exit: 7166179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 7167157642Sps} 7168157642Sps 7169170392Sdavidch 7170169271Sdavidch/****************************************************************************/ 7171170392Sdavidch/* Initialize the controller just enough so that any management firmware */ 7172170810Sdavidch/* running on the device will continue to operate correctly. */ 7173169271Sdavidch/* */ 7174169271Sdavidch/* Returns: */ 7175169271Sdavidch/* Nothing. */ 7176169271Sdavidch/****************************************************************************/ 7177162474Sambriskostatic void 7178162474Sambriskobce_mgmt_init_locked(struct bce_softc *sc) 7179162474Sambrisko{ 7180162474Sambrisko struct ifnet *ifp; 7181157642Sps 7182179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 7183162474Sambrisko 7184162474Sambrisko BCE_LOCK_ASSERT(sc); 7185162474Sambrisko 7186170810Sdavidch /* Bail out if management firmware is not running. */ 7187170810Sdavidch if (!(sc->bce_flags & BCE_MFW_ENABLE_FLAG)) { 7188179771Sdavidch DBPRINT(sc, BCE_VERBOSE_SPECIAL, 7189206268Sdavidch "No management firmware running...\n"); 7190162474Sambrisko goto bce_mgmt_init_locked_exit; 7191170810Sdavidch } 7192162474Sambrisko 7193170810Sdavidch ifp = sc->bce_ifp; 7194162474Sambrisko 7195162474Sambrisko /* Enable all critical blocks in the MAC. */ 7196179771Sdavidch REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, BCE_MISC_ENABLE_DEFAULT); 7197162474Sambrisko REG_RD(sc, BCE_MISC_ENABLE_SET_BITS); 7198162474Sambrisko DELAY(20); 7199162474Sambrisko 7200165994Sjhb bce_ifmedia_upd_locked(ifp); 7201179771Sdavidch 7202162474Sambriskobce_mgmt_init_locked_exit: 7203179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 7204162474Sambrisko} 7205162474Sambrisko 7206162474Sambrisko 7207157642Sps/****************************************************************************/ 7208157642Sps/* Handles controller initialization when called from an unlocked routine. */ 7209157642Sps/* */ 7210157642Sps/* Returns: */ 7211157642Sps/* Nothing. */ 7212157642Sps/****************************************************************************/ 7213157642Spsstatic void 7214157642Spsbce_init(void *xsc) 7215157642Sps{ 7216178132Sdavidch struct bce_softc *sc = xsc; 7217157642Sps 7218179771Sdavidch DBENTER(BCE_VERBOSE_RESET); 7219179771Sdavidch 7220157642Sps BCE_LOCK(sc); 7221157642Sps bce_init_locked(sc); 7222157642Sps BCE_UNLOCK(sc); 7223179771Sdavidch 7224179771Sdavidch DBEXIT(BCE_VERBOSE_RESET); 7225157642Sps} 7226157642Sps 7227157642Sps 7228207411Sdavidch/****************************************************************************/ 7229207411Sdavidch/* Modifies an mbuf for TSO on the hardware. */ 7230207411Sdavidch/* */ 7231207411Sdavidch/* Returns: */ 7232207411Sdavidch/* Pointer to a modified mbuf. */ 7233207411Sdavidch/****************************************************************************/ 7234204373Syongaristatic struct mbuf * 7235204373Syongaribce_tso_setup(struct bce_softc *sc, struct mbuf **m_head, u16 *flags) 7236204373Syongari{ 7237204373Syongari struct mbuf *m; 7238204373Syongari struct ether_header *eh; 7239204373Syongari struct ip *ip; 7240204373Syongari struct tcphdr *th; 7241204373Syongari u16 etype; 7242204373Syongari int hdr_len, ip_hlen = 0, tcp_hlen = 0, ip_len = 0; 7243204373Syongari 7244207411Sdavidch DBRUN(sc->tso_frames_requested++); 7245207411Sdavidch 7246207411Sdavidch /* Controller may modify mbuf chains. */ 7247204373Syongari if (M_WRITABLE(*m_head) == 0) { 7248243857Sglebius m = m_dup(*m_head, M_NOWAIT); 7249204373Syongari m_freem(*m_head); 7250204373Syongari if (m == NULL) { 7251204373Syongari sc->mbuf_alloc_failed_count++; 7252204373Syongari *m_head = NULL; 7253204373Syongari return (NULL); 7254204373Syongari } 7255204373Syongari *m_head = m; 7256204373Syongari } 7257207411Sdavidch 7258204373Syongari /* 7259204373Syongari * For TSO the controller needs two pieces of info, 7260204373Syongari * the MSS and the IP+TCP options length. 7261204373Syongari */ 7262204373Syongari m = m_pullup(*m_head, sizeof(struct ether_header) + sizeof(struct ip)); 7263204373Syongari if (m == NULL) { 7264204373Syongari *m_head = NULL; 7265204373Syongari return (NULL); 7266204373Syongari } 7267204373Syongari eh = mtod(m, struct ether_header *); 7268204373Syongari etype = ntohs(eh->ether_type); 7269204373Syongari 7270204373Syongari /* Check for supported TSO Ethernet types (only IPv4 for now) */ 7271204373Syongari switch (etype) { 7272204373Syongari case ETHERTYPE_IP: 7273204373Syongari ip = (struct ip *)(m->m_data + sizeof(struct ether_header)); 7274204373Syongari /* TSO only supported for TCP protocol. */ 7275204373Syongari if (ip->ip_p != IPPROTO_TCP) { 7276204373Syongari BCE_PRINTF("%s(%d): TSO enabled for non-TCP frame!.\n", 7277204373Syongari __FILE__, __LINE__); 7278204373Syongari m_freem(*m_head); 7279204373Syongari *m_head = NULL; 7280204373Syongari return (NULL); 7281204373Syongari } 7282204373Syongari 7283204373Syongari /* Get IP header length in bytes (min 20) */ 7284204373Syongari ip_hlen = ip->ip_hl << 2; 7285204373Syongari m = m_pullup(*m_head, sizeof(struct ether_header) + ip_hlen + 7286204373Syongari sizeof(struct tcphdr)); 7287204373Syongari if (m == NULL) { 7288204373Syongari *m_head = NULL; 7289204373Syongari return (NULL); 7290204373Syongari } 7291204373Syongari 7292204373Syongari /* Get the TCP header length in bytes (min 20) */ 7293213844Syongari ip = (struct ip *)(m->m_data + sizeof(struct ether_header)); 7294204373Syongari th = (struct tcphdr *)((caddr_t)ip + ip_hlen); 7295204373Syongari tcp_hlen = (th->th_off << 2); 7296204373Syongari 7297204373Syongari /* Make sure all IP/TCP options live in the same buffer. */ 7298204373Syongari m = m_pullup(*m_head, sizeof(struct ether_header)+ ip_hlen + 7299204373Syongari tcp_hlen); 7300204373Syongari if (m == NULL) { 7301204373Syongari *m_head = NULL; 7302204373Syongari return (NULL); 7303204373Syongari } 7304204373Syongari 7305218423Sdavidch /* Clear IP header length and checksum, will be calc'd by h/w. */ 7306213844Syongari ip = (struct ip *)(m->m_data + sizeof(struct ether_header)); 7307204373Syongari ip_len = ip->ip_len; 7308204373Syongari ip->ip_len = 0; 7309204373Syongari ip->ip_sum = 0; 7310204373Syongari break; 7311204373Syongari case ETHERTYPE_IPV6: 7312204373Syongari BCE_PRINTF("%s(%d): TSO over IPv6 not supported!.\n", 7313204373Syongari __FILE__, __LINE__); 7314204373Syongari m_freem(*m_head); 7315204373Syongari *m_head = NULL; 7316204373Syongari return (NULL); 7317204373Syongari /* NOT REACHED */ 7318204373Syongari default: 7319204373Syongari BCE_PRINTF("%s(%d): TSO enabled for unsupported protocol!.\n", 7320204373Syongari __FILE__, __LINE__); 7321204373Syongari m_freem(*m_head); 7322204373Syongari *m_head = NULL; 7323204373Syongari return (NULL); 7324204373Syongari } 7325204373Syongari 7326204373Syongari hdr_len = sizeof(struct ether_header) + ip_hlen + tcp_hlen; 7327204373Syongari 7328204373Syongari DBPRINT(sc, BCE_EXTREME_SEND, "%s(): hdr_len = %d, e_hlen = %d, " 7329204373Syongari "ip_hlen = %d, tcp_hlen = %d, ip_len = %d\n", 7330205300Sdavidch __FUNCTION__, hdr_len, (int) sizeof(struct ether_header), ip_hlen, 7331204373Syongari tcp_hlen, ip_len); 7332204373Syongari 7333204373Syongari /* Set the LSO flag in the TX BD */ 7334204373Syongari *flags |= TX_BD_FLAGS_SW_LSO; 7335207411Sdavidch 7336204373Syongari /* Set the length of IP + TCP options (in 32 bit words) */ 7337204373Syongari *flags |= (((ip_hlen + tcp_hlen - sizeof(struct ip) - 7338204373Syongari sizeof(struct tcphdr)) >> 2) << 8); 7339207411Sdavidch 7340207411Sdavidch DBRUN(sc->tso_frames_completed++); 7341204373Syongari return (*m_head); 7342204373Syongari} 7343204373Syongari 7344204373Syongari 7345157642Sps/****************************************************************************/ 7346157642Sps/* Encapsultes an mbuf cluster into the tx_bd chain structure and makes the */ 7347157642Sps/* memory visible to the controller. */ 7348157642Sps/* */ 7349157642Sps/* Returns: */ 7350157642Sps/* 0 for success, positive value for failure. */ 7351171667Sdavidch/* Modified: */ 7352171667Sdavidch/* m_head: May be set to NULL if MBUF is excessively fragmented. */ 7353157642Sps/****************************************************************************/ 7354157642Spsstatic int 7355163393Sscottlbce_tx_encap(struct bce_softc *sc, struct mbuf **m_head) 7356157642Sps{ 7357163393Sscottl bus_dma_segment_t segs[BCE_MAX_SEGMENTS]; 7358163393Sscottl bus_dmamap_t map; 7359163393Sscottl struct tx_bd *txbd = NULL; 7360163393Sscottl struct mbuf *m0; 7361204373Syongari u16 prod, chain_prod, mss = 0, vlan_tag = 0, flags = 0; 7362170392Sdavidch u32 prod_bseq; 7363157642Sps 7364163393Sscottl#ifdef BCE_DEBUG 7365163393Sscottl u16 debug_prod; 7366163393Sscottl#endif 7367207411Sdavidch 7368163393Sscottl int i, error, nsegs, rc = 0; 7369163393Sscottl 7370179771Sdavidch DBENTER(BCE_VERBOSE_SEND); 7371179771Sdavidch 7372207411Sdavidch /* Make sure we have room in the TX chain. */ 7373207411Sdavidch if (sc->used_tx_bd >= sc->max_tx_bd) 7374207411Sdavidch goto bce_tx_encap_exit; 7375207411Sdavidch 7376157642Sps /* Transfer any checksum offload flags to the bd. */ 7377163393Sscottl m0 = *m_head; 7378163393Sscottl if (m0->m_pkthdr.csum_flags) { 7379170392Sdavidch if (m0->m_pkthdr.csum_flags & CSUM_TSO) { 7380204373Syongari m0 = bce_tso_setup(sc, m_head, &flags); 7381207411Sdavidch if (m0 == NULL) { 7382207411Sdavidch DBRUN(sc->tso_frames_failed++); 7383204373Syongari goto bce_tx_encap_exit; 7384207411Sdavidch } 7385170392Sdavidch mss = htole16(m0->m_pkthdr.tso_segsz); 7386204373Syongari } else { 7387204373Syongari if (m0->m_pkthdr.csum_flags & CSUM_IP) 7388204373Syongari flags |= TX_BD_FLAGS_IP_CKSUM; 7389204373Syongari if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) 7390204373Syongari flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; 7391169632Sdavidch } 7392157642Sps } 7393157642Sps 7394157642Sps /* Transfer any VLAN tags to the bd. */ 7395164329Sscottl if (m0->m_flags & M_VLANTAG) { 7396164329Sscottl flags |= TX_BD_FLAGS_VLAN_TAG; 7397164329Sscottl vlan_tag = m0->m_pkthdr.ether_vtag; 7398164329Sscottl } 7399157642Sps 7400157642Sps /* Map the mbuf into DMAable memory. */ 7401163393Sscottl prod = sc->tx_prod; 7402163393Sscottl chain_prod = TX_CHAIN_IDX(prod); 7403163339Sscottl map = sc->tx_mbuf_map[chain_prod]; 7404157642Sps 7405157642Sps /* Map the mbuf into our DMA address space. */ 7406163393Sscottl error = bus_dmamap_load_mbuf_sg(sc->tx_mbuf_tag, map, m0, 7407163393Sscottl segs, &nsegs, BUS_DMA_NOWAIT); 7408157642Sps 7409170392Sdavidch /* Check if the DMA mapping was successful */ 7410163393Sscottl if (error == EFBIG) { 7411207411Sdavidch sc->mbuf_frag_count++; 7412179771Sdavidch 7413171667Sdavidch /* Try to defrag the mbuf. */ 7414243857Sglebius m0 = m_collapse(*m_head, M_NOWAIT, BCE_MAX_SEGMENTS); 7415171667Sdavidch if (m0 == NULL) { 7416169632Sdavidch /* Defrag was unsuccessful */ 7417163499Sscottl m_freem(*m_head); 7418163499Sscottl *m_head = NULL; 7419189325Sdavidch sc->mbuf_alloc_failed_count++; 7420179771Sdavidch rc = ENOBUFS; 7421179771Sdavidch goto bce_tx_encap_exit; 7422163499Sscottl } 7423159411Sdavidch 7424170392Sdavidch /* Defrag was successful, try mapping again */ 7425163499Sscottl *m_head = m0; 7426207411Sdavidch error = bus_dmamap_load_mbuf_sg(sc->tx_mbuf_tag, 7427207411Sdavidch map, m0, segs, &nsegs, BUS_DMA_NOWAIT); 7428163499Sscottl 7429163393Sscottl /* Still getting an error after a defrag. */ 7430163499Sscottl if (error == ENOMEM) { 7431171667Sdavidch /* Insufficient DMA buffers available. */ 7432189325Sdavidch sc->dma_map_addr_tx_failed_count++; 7433179771Sdavidch rc = error; 7434179771Sdavidch goto bce_tx_encap_exit; 7435163499Sscottl } else if (error != 0) { 7436206268Sdavidch /* Release it and return an error. */ 7437206268Sdavidch BCE_PRINTF("%s(%d): Unknown error mapping mbuf into " 7438206268Sdavidch "TX chain!\n", __FILE__, __LINE__); 7439163499Sscottl m_freem(m0); 7440163499Sscottl *m_head = NULL; 7441189325Sdavidch sc->dma_map_addr_tx_failed_count++; 7442179771Sdavidch rc = ENOBUFS; 7443179771Sdavidch goto bce_tx_encap_exit; 7444163393Sscottl } 7445163499Sscottl } else if (error == ENOMEM) { 7446171667Sdavidch /* Insufficient DMA buffers available. */ 7447189325Sdavidch sc->dma_map_addr_tx_failed_count++; 7448179771Sdavidch rc = error; 7449179771Sdavidch goto bce_tx_encap_exit; 7450163499Sscottl } else if (error != 0) { 7451163499Sscottl m_freem(m0); 7452163499Sscottl *m_head = NULL; 7453189325Sdavidch sc->dma_map_addr_tx_failed_count++; 7454179771Sdavidch rc = error; 7455179771Sdavidch goto bce_tx_encap_exit; 7456163499Sscottl } 7457170392Sdavidch 7458169632Sdavidch /* Make sure there's room in the chain */ 7459169632Sdavidch if (nsegs > (sc->max_tx_bd - sc->used_tx_bd)) { 7460163558Sscottl bus_dmamap_unload(sc->tx_mbuf_tag, map); 7461179771Sdavidch rc = ENOBUFS; 7462179771Sdavidch goto bce_tx_encap_exit; 7463163558Sscottl } 7464163393Sscottl 7465163393Sscottl /* prod points to an empty tx_bd at this point. */ 7466163393Sscottl prod_bseq = sc->tx_prod_bseq; 7467163393Sscottl 7468163393Sscottl#ifdef BCE_DEBUG 7469163393Sscottl debug_prod = chain_prod; 7470163393Sscottl#endif 7471163393Sscottl 7472163393Sscottl DBPRINT(sc, BCE_INFO_SEND, 7473206268Sdavidch "%s(start): prod = 0x%04X, chain_prod = 0x%04X, " 7474206268Sdavidch "prod_bseq = 0x%08X\n", 7475206268Sdavidch __FUNCTION__, prod, chain_prod, prod_bseq); 7476163393Sscottl 7477163393Sscottl /* 7478163393Sscottl * Cycle through each mbuf segment that makes up 7479163393Sscottl * the outgoing frame, gathering the mapping info 7480176448Sdavidch * for that segment and creating a tx_bd for 7481163393Sscottl * the mbuf. 7482163393Sscottl */ 7483163393Sscottl for (i = 0; i < nsegs ; i++) { 7484163393Sscottl 7485163393Sscottl chain_prod = TX_CHAIN_IDX(prod); 7486206268Sdavidch txbd= &sc->tx_bd_chain[TX_PAGE(chain_prod)] 7487206268Sdavidch [TX_IDX(chain_prod)]; 7488163393Sscottl 7489207411Sdavidch txbd->tx_bd_haddr_lo = 7490207411Sdavidch htole32(BCE_ADDR_LO(segs[i].ds_addr)); 7491207411Sdavidch txbd->tx_bd_haddr_hi = 7492207411Sdavidch htole32(BCE_ADDR_HI(segs[i].ds_addr)); 7493207411Sdavidch txbd->tx_bd_mss_nbytes = htole32(mss << 16) | 7494206268Sdavidch htole16(segs[i].ds_len); 7495164329Sscottl txbd->tx_bd_vlan_tag = htole16(vlan_tag); 7496164329Sscottl txbd->tx_bd_flags = htole16(flags); 7497163393Sscottl prod_bseq += segs[i].ds_len; 7498163393Sscottl if (i == 0) 7499170392Sdavidch txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_START); 7500163393Sscottl prod = NEXT_TX_BD(prod); 7501157642Sps } 7502157642Sps 7503163393Sscottl /* Set the END flag on the last TX buffer descriptor. */ 7504164329Sscottl txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_END); 7505163393Sscottl 7506207411Sdavidch DBRUNMSG(BCE_EXTREME_SEND, 7507207411Sdavidch bce_dump_tx_chain(sc, debug_prod, nsegs)); 7508163393Sscottl 7509157642Sps /* 7510164327Sjdp * Ensure that the mbuf pointer for this transmission 7511157642Sps * is placed at the array index of the last 7512157642Sps * descriptor in this chain. This is done 7513179771Sdavidch * because a single map is used for all 7514157642Sps * segments of the mbuf and we don't want to 7515164327Sjdp * unload the map before all of the segments 7516157642Sps * have been freed. 7517157642Sps */ 7518163393Sscottl sc->tx_mbuf_ptr[chain_prod] = m0; 7519163393Sscottl sc->used_tx_bd += nsegs; 7520157642Sps 7521170392Sdavidch /* Update some debug statistic counters */ 7522179771Sdavidch DBRUNIF((sc->used_tx_bd > sc->tx_hi_watermark), 7523206268Sdavidch sc->tx_hi_watermark = sc->used_tx_bd); 7524169632Sdavidch DBRUNIF((sc->used_tx_bd == sc->max_tx_bd), sc->tx_full_count++); 7525176448Sdavidch DBRUNIF(sc->debug_tx_mbuf_alloc++); 7526157642Sps 7527179771Sdavidch DBRUNMSG(BCE_EXTREME_SEND, bce_dump_tx_mbuf_chain(sc, chain_prod, 1)); 7528157642Sps 7529164327Sjdp /* prod points to the next free tx_bd at this point. */ 7530163393Sscottl sc->tx_prod = prod; 7531163393Sscottl sc->tx_prod_bseq = prod_bseq; 7532157642Sps 7533207411Sdavidch /* Tell the chip about the waiting TX frames. */ 7534207411Sdavidch REG_WR16(sc, MB_GET_CID_ADDR(TX_CID) + 7535207411Sdavidch BCE_L2MQ_TX_HOST_BIDX, sc->tx_prod); 7536207411Sdavidch REG_WR(sc, MB_GET_CID_ADDR(TX_CID) + 7537207411Sdavidch BCE_L2MQ_TX_HOST_BSEQ, sc->tx_prod_bseq); 7538179771Sdavidch 7539179771Sdavidchbce_tx_encap_exit: 7540179771Sdavidch DBEXIT(BCE_VERBOSE_SEND); 7541157642Sps return(rc); 7542157642Sps} 7543157642Sps 7544157642Sps 7545157642Sps/****************************************************************************/ 7546157642Sps/* Main transmit routine when called from another routine with a lock. */ 7547157642Sps/* */ 7548157642Sps/* Returns: */ 7549157642Sps/* Nothing. */ 7550157642Sps/****************************************************************************/ 7551157642Spsstatic void 7552157642Spsbce_start_locked(struct ifnet *ifp) 7553157642Sps{ 7554157642Sps struct bce_softc *sc = ifp->if_softc; 7555157642Sps struct mbuf *m_head = NULL; 7556157642Sps int count = 0; 7557157642Sps u16 tx_prod, tx_chain_prod; 7558157642Sps 7559179771Sdavidch DBENTER(BCE_VERBOSE_SEND | BCE_VERBOSE_CTX); 7560179771Sdavidch 7561179771Sdavidch BCE_LOCK_ASSERT(sc); 7562179771Sdavidch 7563157642Sps /* prod points to the next free tx_bd. */ 7564157642Sps tx_prod = sc->tx_prod; 7565157642Sps tx_chain_prod = TX_CHAIN_IDX(tx_prod); 7566157642Sps 7567157642Sps DBPRINT(sc, BCE_INFO_SEND, 7568206268Sdavidch "%s(enter): tx_prod = 0x%04X, tx_chain_prod = 0x%04X, " 7569206268Sdavidch "tx_prod_bseq = 0x%08X\n", 7570206268Sdavidch __FUNCTION__, tx_prod, tx_chain_prod, sc->tx_prod_bseq); 7571157642Sps 7572178132Sdavidch /* If there's no link or the transmit queue is empty then just exit. */ 7573206268Sdavidch if (sc->bce_link_up == FALSE) { 7574179771Sdavidch DBPRINT(sc, BCE_INFO_SEND, "%s(): No link.\n", 7575206268Sdavidch __FUNCTION__); 7576178132Sdavidch goto bce_start_locked_exit; 7577178132Sdavidch } 7578178132Sdavidch 7579178132Sdavidch if (IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 7580179771Sdavidch DBPRINT(sc, BCE_INFO_SEND, "%s(): Transmit queue empty.\n", 7581206268Sdavidch __FUNCTION__); 7582178132Sdavidch goto bce_start_locked_exit; 7583178132Sdavidch } 7584178132Sdavidch 7585164327Sjdp /* 7586169632Sdavidch * Keep adding entries while there is space in the ring. 7587164327Sjdp */ 7588169632Sdavidch while (sc->used_tx_bd < sc->max_tx_bd) { 7589157642Sps 7590157642Sps /* Check for any frames to send. */ 7591157642Sps IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 7592179771Sdavidch 7593179771Sdavidch /* Stop when the transmit queue is empty. */ 7594157642Sps if (m_head == NULL) 7595157642Sps break; 7596157642Sps 7597157642Sps /* 7598157642Sps * Pack the data into the transmit ring. If we 7599157642Sps * don't have room, place the mbuf back at the 7600157642Sps * head of the queue and set the OACTIVE flag 7601157642Sps * to wait for the NIC to drain the chain. 7602157642Sps */ 7603163393Sscottl if (bce_tx_encap(sc, &m_head)) { 7604171667Sdavidch if (m_head != NULL) 7605171667Sdavidch IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 7606157642Sps ifp->if_drv_flags |= IFF_DRV_OACTIVE; 7607157642Sps DBPRINT(sc, BCE_INFO_SEND, 7608206268Sdavidch "TX chain is closed for business! Total " 7609206268Sdavidch "tx_bd used = %d\n", sc->used_tx_bd); 7610157642Sps break; 7611157642Sps } 7612157642Sps 7613157642Sps count++; 7614157642Sps 7615157642Sps /* Send a copy of the frame to any BPF listeners. */ 7616167190Scsjp ETHER_BPF_MTAP(ifp, m_head); 7617157642Sps } 7618157642Sps 7619179771Sdavidch /* Exit if no packets were dequeued. */ 7620157642Sps if (count == 0) { 7621206268Sdavidch DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): No packets were " 7622206268Sdavidch "dequeued\n", __FUNCTION__); 7623157642Sps goto bce_start_locked_exit; 7624157642Sps } 7625157642Sps 7626206268Sdavidch DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): Inserted %d frames into " 7627206268Sdavidch "send queue.\n", __FUNCTION__, count); 7628157642Sps 7629157642Sps /* Set the tx timeout. */ 7630165933Sdelphij sc->watchdog_timer = BCE_TX_TIMEOUT; 7631157642Sps 7632182293Sdavidch DBRUNMSG(BCE_VERBOSE_SEND, bce_dump_ctx(sc, TX_CID)); 7633179771Sdavidch DBRUNMSG(BCE_VERBOSE_SEND, bce_dump_mq_regs(sc)); 7634179771Sdavidch 7635157642Spsbce_start_locked_exit: 7636179771Sdavidch DBEXIT(BCE_VERBOSE_SEND | BCE_VERBOSE_CTX); 7637157642Sps} 7638157642Sps 7639157642Sps 7640157642Sps/****************************************************************************/ 7641157642Sps/* Main transmit routine when called from another routine without a lock. */ 7642157642Sps/* */ 7643157642Sps/* Returns: */ 7644157642Sps/* Nothing. */ 7645157642Sps/****************************************************************************/ 7646157642Spsstatic void 7647157642Spsbce_start(struct ifnet *ifp) 7648157642Sps{ 7649157642Sps struct bce_softc *sc = ifp->if_softc; 7650157642Sps 7651179771Sdavidch DBENTER(BCE_VERBOSE_SEND); 7652179771Sdavidch 7653157642Sps BCE_LOCK(sc); 7654157642Sps bce_start_locked(ifp); 7655157642Sps BCE_UNLOCK(sc); 7656179771Sdavidch 7657179771Sdavidch DBEXIT(BCE_VERBOSE_SEND); 7658157642Sps} 7659157642Sps 7660157642Sps 7661157642Sps/****************************************************************************/ 7662157642Sps/* Handles any IOCTL calls from the operating system. */ 7663157642Sps/* */ 7664157642Sps/* Returns: */ 7665157642Sps/* 0 for success, positive value for failure. */ 7666157642Sps/****************************************************************************/ 7667157642Spsstatic int 7668157642Spsbce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 7669157642Sps{ 7670157642Sps struct bce_softc *sc = ifp->if_softc; 7671157642Sps struct ifreq *ifr = (struct ifreq *) data; 7672157642Sps struct mii_data *mii; 7673218423Sdavidch int mask, error = 0; 7674157642Sps 7675179771Sdavidch DBENTER(BCE_VERBOSE_MISC); 7676179771Sdavidch 7677157642Sps switch(command) { 7678157642Sps 7679206268Sdavidch /* Set the interface MTU. */ 7680206268Sdavidch case SIOCSIFMTU: 7681206268Sdavidch /* Check that the MTU setting is supported. */ 7682206268Sdavidch if ((ifr->ifr_mtu < BCE_MIN_MTU) || 7683206268Sdavidch (ifr->ifr_mtu > BCE_MAX_JUMBO_MTU)) { 7684206268Sdavidch error = EINVAL; 7685206268Sdavidch break; 7686206268Sdavidch } 7687157642Sps 7688206268Sdavidch DBPRINT(sc, BCE_INFO_MISC, 7689206268Sdavidch "SIOCSIFMTU: Changing MTU from %d to %d\n", 7690206268Sdavidch (int) ifp->if_mtu, (int) ifr->ifr_mtu); 7691157642Sps 7692206268Sdavidch BCE_LOCK(sc); 7693206268Sdavidch ifp->if_mtu = ifr->ifr_mtu; 7694235119Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 7695235119Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 7696218423Sdavidch bce_init_locked(sc); 7697206268Sdavidch } 7698206268Sdavidch BCE_UNLOCK(sc); 7699206268Sdavidch break; 7700157642Sps 7701206268Sdavidch /* Set interface flags. */ 7702206268Sdavidch case SIOCSIFFLAGS: 7703206268Sdavidch DBPRINT(sc, BCE_VERBOSE_SPECIAL, "Received SIOCSIFFLAGS\n"); 7704157642Sps 7705206268Sdavidch BCE_LOCK(sc); 7706157642Sps 7707206268Sdavidch /* Check if the interface is up. */ 7708206268Sdavidch if (ifp->if_flags & IFF_UP) { 7709206268Sdavidch if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 7710206268Sdavidch /* Change promiscuous/multicast flags as necessary. */ 7711206268Sdavidch bce_set_rx_mode(sc); 7712157642Sps } else { 7713206268Sdavidch /* Start the HW */ 7714206268Sdavidch bce_init_locked(sc); 7715206268Sdavidch } 7716206268Sdavidch } else { 7717206268Sdavidch /* The interface is down, check if driver is running. */ 7718206268Sdavidch if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 7719206268Sdavidch bce_stop(sc); 7720170810Sdavidch 7721206268Sdavidch /* If MFW is running, restart the controller a bit. */ 7722206268Sdavidch if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) { 7723206268Sdavidch bce_reset(sc, BCE_DRV_MSG_CODE_RESET); 7724206268Sdavidch bce_chipinit(sc); 7725206268Sdavidch bce_mgmt_init_locked(sc); 7726157642Sps } 7727157642Sps } 7728206268Sdavidch } 7729157642Sps 7730206268Sdavidch BCE_UNLOCK(sc); 7731206268Sdavidch break; 7732157642Sps 7733206268Sdavidch /* Add/Delete multicast address */ 7734206268Sdavidch case SIOCADDMULTI: 7735206268Sdavidch case SIOCDELMULTI: 7736207411Sdavidch DBPRINT(sc, BCE_VERBOSE_MISC, 7737206268Sdavidch "Received SIOCADDMULTI/SIOCDELMULTI\n"); 7738157642Sps 7739206268Sdavidch BCE_LOCK(sc); 7740206268Sdavidch if (ifp->if_drv_flags & IFF_DRV_RUNNING) 7741206268Sdavidch bce_set_rx_mode(sc); 7742206268Sdavidch BCE_UNLOCK(sc); 7743157642Sps 7744206268Sdavidch break; 7745157642Sps 7746206268Sdavidch /* Set/Get Interface media */ 7747206268Sdavidch case SIOCSIFMEDIA: 7748206268Sdavidch case SIOCGIFMEDIA: 7749207411Sdavidch DBPRINT(sc, BCE_VERBOSE_MISC, 7750206268Sdavidch "Received SIOCSIFMEDIA/SIOCGIFMEDIA\n"); 7751235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) 7752235151Syongari error = ifmedia_ioctl(ifp, ifr, &sc->bce_ifmedia, 7753235151Syongari command); 7754235151Syongari else { 7755235151Syongari mii = device_get_softc(sc->bce_miibus); 7756235151Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, 7757235151Syongari command); 7758235151Syongari } 7759206268Sdavidch break; 7760157642Sps 7761206268Sdavidch /* Set interface capability */ 7762206268Sdavidch case SIOCSIFCAP: 7763206268Sdavidch mask = ifr->ifr_reqcap ^ ifp->if_capenable; 7764207411Sdavidch DBPRINT(sc, BCE_INFO_MISC, 7765206268Sdavidch "Received SIOCSIFCAP = 0x%08X\n", (u32) mask); 7766157642Sps 7767206268Sdavidch /* Toggle the TX checksum capabilities enable flag. */ 7768206268Sdavidch if (mask & IFCAP_TXCSUM && 7769206268Sdavidch ifp->if_capabilities & IFCAP_TXCSUM) { 7770206268Sdavidch ifp->if_capenable ^= IFCAP_TXCSUM; 7771206268Sdavidch if (IFCAP_TXCSUM & ifp->if_capenable) 7772206268Sdavidch ifp->if_hwassist |= BCE_IF_HWASSIST; 7773206268Sdavidch else 7774206268Sdavidch ifp->if_hwassist &= ~BCE_IF_HWASSIST; 7775206268Sdavidch } 7776157642Sps 7777206268Sdavidch /* Toggle the RX checksum capabilities enable flag. */ 7778206268Sdavidch if (mask & IFCAP_RXCSUM && 7779206268Sdavidch ifp->if_capabilities & IFCAP_RXCSUM) 7780206268Sdavidch ifp->if_capenable ^= IFCAP_RXCSUM; 7781157642Sps 7782206268Sdavidch /* Toggle the TSO capabilities enable flag. */ 7783206268Sdavidch if (bce_tso_enable && (mask & IFCAP_TSO4) && 7784206268Sdavidch ifp->if_capabilities & IFCAP_TSO4) { 7785206268Sdavidch ifp->if_capenable ^= IFCAP_TSO4; 7786206268Sdavidch if (IFCAP_TSO4 & ifp->if_capenable) 7787206268Sdavidch ifp->if_hwassist |= CSUM_TSO; 7788206268Sdavidch else 7789206268Sdavidch ifp->if_hwassist &= ~CSUM_TSO; 7790206268Sdavidch } 7791157642Sps 7792206268Sdavidch if (mask & IFCAP_VLAN_HWCSUM && 7793206268Sdavidch ifp->if_capabilities & IFCAP_VLAN_HWCSUM) 7794206268Sdavidch ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 7795169632Sdavidch 7796206268Sdavidch if ((mask & IFCAP_VLAN_HWTSO) != 0 && 7797206268Sdavidch (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) 7798206268Sdavidch ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 7799206268Sdavidch /* 7800206268Sdavidch * Don't actually disable VLAN tag stripping as 7801206268Sdavidch * management firmware (ASF/IPMI/UMP) requires the 7802206268Sdavidch * feature. If VLAN tag stripping is disabled driver 7803206268Sdavidch * will manually reconstruct the VLAN frame by 7804206268Sdavidch * appending stripped VLAN tag. 7805206268Sdavidch */ 7806206268Sdavidch if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 7807206268Sdavidch (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING)) { 7808206268Sdavidch ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 7809206268Sdavidch if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 7810206268Sdavidch == 0) 7811206268Sdavidch ifp->if_capenable &= ~IFCAP_VLAN_HWTSO; 7812206268Sdavidch } 7813206268Sdavidch VLAN_CAPABILITIES(ifp); 7814206268Sdavidch break; 7815206268Sdavidch default: 7816206268Sdavidch /* We don't know how to handle the IOCTL, pass it on. */ 7817206268Sdavidch error = ether_ioctl(ifp, command, data); 7818206268Sdavidch break; 7819157642Sps } 7820157642Sps 7821179771Sdavidch DBEXIT(BCE_VERBOSE_MISC); 7822157642Sps return(error); 7823157642Sps} 7824157642Sps 7825157642Sps 7826157642Sps/****************************************************************************/ 7827157642Sps/* Transmit timeout handler. */ 7828157642Sps/* */ 7829157642Sps/* Returns: */ 7830157642Sps/* Nothing. */ 7831157642Sps/****************************************************************************/ 7832157642Spsstatic void 7833165933Sdelphijbce_watchdog(struct bce_softc *sc) 7834157642Sps{ 7835252402Syongari uint32_t status; 7836252402Syongari 7837179771Sdavidch DBENTER(BCE_EXTREME_SEND); 7838157642Sps 7839165933Sdelphij BCE_LOCK_ASSERT(sc); 7840165933Sdelphij 7841252402Syongari status = 0; 7842179771Sdavidch /* If the watchdog timer hasn't expired then just exit. */ 7843165933Sdelphij if (sc->watchdog_timer == 0 || --sc->watchdog_timer) 7844179771Sdavidch goto bce_watchdog_exit; 7845165933Sdelphij 7846252402Syongari status = REG_RD(sc, BCE_EMAC_RX_STATUS); 7847179771Sdavidch /* If pause frames are active then don't reset the hardware. */ 7848252402Syongari if ((sc->bce_flags & BCE_USING_RX_FLOW_CONTROL) != 0) { 7849252402Syongari if ((status & BCE_EMAC_RX_STATUS_FFED) != 0) { 7850252402Syongari /* 7851252402Syongari * If link partner has us in XOFF state then wait for 7852252402Syongari * the condition to clear. 7853252402Syongari */ 7854252402Syongari sc->watchdog_timer = BCE_TX_TIMEOUT; 7855252402Syongari goto bce_watchdog_exit; 7856252402Syongari } else if ((status & BCE_EMAC_RX_STATUS_FF_RECEIVED) != 0 && 7857252402Syongari (status & BCE_EMAC_RX_STATUS_N_RECEIVED) != 0) { 7858252402Syongari /* 7859252402Syongari * If we're not currently XOFF'ed but have recently 7860252402Syongari * been XOFF'd/XON'd then assume that's delaying TX 7861252402Syongari * this time around. 7862252402Syongari */ 7863252402Syongari sc->watchdog_timer = BCE_TX_TIMEOUT; 7864252402Syongari goto bce_watchdog_exit; 7865252402Syongari } 7866252402Syongari /* 7867252402Syongari * Any other condition is unexpected and the controller 7868252402Syongari * should be reset. 7869252402Syongari */ 7870252402Syongari } 7871165933Sdelphij 7872179771Sdavidch BCE_PRINTF("%s(%d): Watchdog timeout occurred, resetting!\n", 7873207411Sdavidch __FILE__, __LINE__); 7874157642Sps 7875179771Sdavidch DBRUNMSG(BCE_INFO, 7876206268Sdavidch bce_dump_driver_state(sc); 7877206268Sdavidch bce_dump_status_block(sc); 7878206268Sdavidch bce_dump_stats_block(sc); 7879206268Sdavidch bce_dump_ftqs(sc); 7880206268Sdavidch bce_dump_txp_state(sc, 0); 7881206268Sdavidch bce_dump_rxp_state(sc, 0); 7882206268Sdavidch bce_dump_tpat_state(sc, 0); 7883206268Sdavidch bce_dump_cp_state(sc, 0); 7884206268Sdavidch bce_dump_com_state(sc, 0)); 7885170810Sdavidch 7886179771Sdavidch DBRUN(bce_breakpoint(sc)); 7887157642Sps 7888165933Sdelphij sc->bce_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 7889157642Sps 7890160526Sjhb bce_init_locked(sc); 7891165933Sdelphij sc->bce_ifp->if_oerrors++; 7892157642Sps 7893179771Sdavidchbce_watchdog_exit: 7894252402Syongari REG_WR(sc, BCE_EMAC_RX_STATUS, status); 7895179771Sdavidch DBEXIT(BCE_EXTREME_SEND); 7896157642Sps} 7897157642Sps 7898157642Sps 7899157642Sps/* 7900157642Sps * Interrupt handler. 7901157642Sps */ 7902157642Sps/****************************************************************************/ 7903157642Sps/* Main interrupt entry point. Verifies that the controller generated the */ 7904157642Sps/* interrupt and then calls a separate routine for handle the various */ 7905157642Sps/* interrupt causes (PHY, TX, RX). */ 7906157642Sps/* */ 7907157642Sps/* Returns: */ 7908251159Smarius/* Nothing. */ 7909157642Sps/****************************************************************************/ 7910157642Spsstatic void 7911157642Spsbce_intr(void *xsc) 7912157642Sps{ 7913157642Sps struct bce_softc *sc; 7914157642Sps struct ifnet *ifp; 7915157642Sps u32 status_attn_bits; 7916178132Sdavidch u16 hw_rx_cons, hw_tx_cons; 7917157642Sps 7918157642Sps sc = xsc; 7919157642Sps ifp = sc->bce_ifp; 7920157642Sps 7921179771Sdavidch DBENTER(BCE_VERBOSE_SEND | BCE_VERBOSE_RECV | BCE_VERBOSE_INTR); 7922179771Sdavidch DBRUNMSG(BCE_VERBOSE_INTR, bce_dump_status_block(sc)); 7923206268Sdavidch DBRUNMSG(BCE_VERBOSE_INTR, bce_dump_stats_block(sc)); 7924179771Sdavidch 7925157642Sps BCE_LOCK(sc); 7926157642Sps 7927176448Sdavidch DBRUN(sc->interrupts_generated++); 7928157642Sps 7929192281Sdelphij /* Synchnorize before we read from interface's status block */ 7930251159Smarius bus_dmamap_sync(sc->status_tag, sc->status_map, BUS_DMASYNC_POSTREAD); 7931157642Sps 7932157642Sps /* 7933251159Smarius * If the hardware status block index matches the last value read 7934251159Smarius * by the driver and we haven't asserted our interrupt then there's 7935251159Smarius * nothing to do. This may only happen in case of INTx due to the 7936251159Smarius * interrupt arriving at the CPU before the status block is updated. 7937157642Sps */ 7938251159Smarius if ((sc->bce_flags & (BCE_USING_MSI_FLAG | BCE_USING_MSIX_FLAG)) == 0 && 7939251159Smarius sc->status_block->status_idx == sc->last_status_idx && 7940207411Sdavidch (REG_RD(sc, BCE_PCICFG_MISC_STATUS) & 7941206268Sdavidch BCE_PCICFG_MISC_STATUS_INTA_VALUE)) { 7942206268Sdavidch DBPRINT(sc, BCE_VERBOSE_INTR, "%s(): Spurious interrupt.\n", 7943206268Sdavidch __FUNCTION__); 7944206268Sdavidch goto bce_intr_exit; 7945179771Sdavidch } 7946157642Sps 7947157642Sps /* Ack the interrupt and stop others from occuring. */ 7948157642Sps REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, 7949206268Sdavidch BCE_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM | 7950206268Sdavidch BCE_PCICFG_INT_ACK_CMD_MASK_INT); 7951157642Sps 7952178132Sdavidch /* Check if the hardware has finished any work. */ 7953178132Sdavidch hw_rx_cons = bce_get_hw_rx_cons(sc); 7954178132Sdavidch hw_tx_cons = bce_get_hw_tx_cons(sc); 7955178132Sdavidch 7956157642Sps /* Keep processing data as long as there is work to do. */ 7957157642Sps for (;;) { 7958157642Sps 7959157642Sps status_attn_bits = sc->status_block->status_attn_bits; 7960157642Sps 7961206268Sdavidch DBRUNIF(DB_RANDOMTRUE(unexpected_attention_sim_control), 7962206268Sdavidch BCE_PRINTF("Simulating unexpected status attention " 7963206268Sdavidch "bit set."); 7964206268Sdavidch sc->unexpected_attention_sim_count++; 7965207411Sdavidch status_attn_bits = status_attn_bits | 7966206268Sdavidch STATUS_ATTN_BITS_PARITY_ERROR); 7967157642Sps 7968157642Sps /* Was it a link change interrupt? */ 7969157642Sps if ((status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != 7970207411Sdavidch (sc->status_block->status_attn_bits_ack & 7971206268Sdavidch STATUS_ATTN_BITS_LINK_STATE)) { 7972157642Sps bce_phy_intr(sc); 7973157642Sps 7974206268Sdavidch /* Clear transient updates during link state change. */ 7975207411Sdavidch REG_WR(sc, BCE_HC_COMMAND, sc->hc_command | 7976206268Sdavidch BCE_HC_COMMAND_COAL_NOW_WO_INT); 7977185593Sdelphij REG_RD(sc, BCE_HC_COMMAND); 7978185593Sdelphij } 7979179771Sdavidch 7980206268Sdavidch /* If any other attention is asserted, the chip is toast. */ 7981157642Sps if (((status_attn_bits & ~STATUS_ATTN_BITS_LINK_STATE) != 7982206268Sdavidch (sc->status_block->status_attn_bits_ack & 7983206268Sdavidch ~STATUS_ATTN_BITS_LINK_STATE))) { 7984157642Sps 7985206268Sdavidch sc->unexpected_attention_count++; 7986157642Sps 7987206268Sdavidch BCE_PRINTF("%s(%d): Fatal attention detected: " 7988207411Sdavidch "0x%08X\n", __FILE__, __LINE__, 7989206268Sdavidch sc->status_block->status_attn_bits); 7990157642Sps 7991179771Sdavidch DBRUNMSG(BCE_FATAL, 7992206268Sdavidch if (unexpected_attention_sim_control == 0) 7993206268Sdavidch bce_breakpoint(sc)); 7994157642Sps 7995157642Sps bce_init_locked(sc); 7996157642Sps goto bce_intr_exit; 7997157642Sps } 7998157642Sps 7999157642Sps /* Check for any completed RX frames. */ 8000178132Sdavidch if (hw_rx_cons != sc->hw_rx_cons) 8001157642Sps bce_rx_intr(sc); 8002157642Sps 8003157642Sps /* Check for any completed TX frames. */ 8004178132Sdavidch if (hw_tx_cons != sc->hw_tx_cons) 8005157642Sps bce_tx_intr(sc); 8006157642Sps 8007206268Sdavidch /* Save status block index value for the next interrupt. */ 8008157642Sps sc->last_status_idx = sc->status_block->status_idx; 8009157642Sps 8010206268Sdavidch /* 8011206268Sdavidch * Prevent speculative reads from getting 8012206268Sdavidch * ahead of the status block. 8013206268Sdavidch */ 8014179771Sdavidch bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0, 8015206268Sdavidch BUS_SPACE_BARRIER_READ); 8016157642Sps 8017206268Sdavidch /* 8018206268Sdavidch * If there's no work left then exit the 8019206268Sdavidch * interrupt service routine. 8020206268Sdavidch */ 8021178132Sdavidch hw_rx_cons = bce_get_hw_rx_cons(sc); 8022178132Sdavidch hw_tx_cons = bce_get_hw_tx_cons(sc); 8023178132Sdavidch 8024207411Sdavidch if ((hw_rx_cons == sc->hw_rx_cons) && 8025206268Sdavidch (hw_tx_cons == sc->hw_tx_cons)) 8026157642Sps break; 8027157642Sps } 8028157642Sps 8029251159Smarius bus_dmamap_sync(sc->status_tag, sc->status_map, BUS_DMASYNC_PREREAD); 8030157642Sps 8031157642Sps /* Re-enable interrupts. */ 8032179771Sdavidch bce_enable_intr(sc, 0); 8033157642Sps 8034157642Sps /* Handle any frames that arrived while handling the interrupt. */ 8035207411Sdavidch if (ifp->if_drv_flags & IFF_DRV_RUNNING && 8036206268Sdavidch !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 8037157642Sps bce_start_locked(ifp); 8038157642Sps 8039157642Spsbce_intr_exit: 8040157642Sps BCE_UNLOCK(sc); 8041179771Sdavidch 8042179771Sdavidch DBEXIT(BCE_VERBOSE_SEND | BCE_VERBOSE_RECV | BCE_VERBOSE_INTR); 8043157642Sps} 8044157642Sps 8045157642Sps 8046157642Sps/****************************************************************************/ 8047157642Sps/* Programs the various packet receive modes (broadcast and multicast). */ 8048157642Sps/* */ 8049157642Sps/* Returns: */ 8050157642Sps/* Nothing. */ 8051157642Sps/****************************************************************************/ 8052157642Spsstatic void 8053157642Spsbce_set_rx_mode(struct bce_softc *sc) 8054157642Sps{ 8055157642Sps struct ifnet *ifp; 8056157642Sps struct ifmultiaddr *ifma; 8057166153Sscottl u32 hashes[NUM_MC_HASH_REGISTERS] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 8058157642Sps u32 rx_mode, sort_mode; 8059157642Sps int h, i; 8060157642Sps 8061179771Sdavidch DBENTER(BCE_VERBOSE_MISC); 8062179771Sdavidch 8063157642Sps BCE_LOCK_ASSERT(sc); 8064157642Sps 8065157642Sps ifp = sc->bce_ifp; 8066157642Sps 8067157642Sps /* Initialize receive mode default settings. */ 8068157642Sps rx_mode = sc->rx_mode & ~(BCE_EMAC_RX_MODE_PROMISCUOUS | 8069206268Sdavidch BCE_EMAC_RX_MODE_KEEP_VLAN_TAG); 8070157642Sps sort_mode = 1 | BCE_RPM_SORT_USER0_BC_EN; 8071157642Sps 8072157642Sps /* 8073157642Sps * ASF/IPMI/UMP firmware requires that VLAN tag stripping 8074157642Sps * be enbled. 8075157642Sps */ 8076157642Sps if (!(BCE_IF_CAPABILITIES & IFCAP_VLAN_HWTAGGING) && 8077206268Sdavidch (!(sc->bce_flags & BCE_MFW_ENABLE_FLAG))) 8078157642Sps rx_mode |= BCE_EMAC_RX_MODE_KEEP_VLAN_TAG; 8079157642Sps 8080157642Sps /* 8081157642Sps * Check for promiscuous, all multicast, or selected 8082157642Sps * multicast address filtering. 8083157642Sps */ 8084157642Sps if (ifp->if_flags & IFF_PROMISC) { 8085170810Sdavidch DBPRINT(sc, BCE_INFO_MISC, "Enabling promiscuous mode.\n"); 8086157642Sps 8087157642Sps /* Enable promiscuous mode. */ 8088157642Sps rx_mode |= BCE_EMAC_RX_MODE_PROMISCUOUS; 8089157642Sps sort_mode |= BCE_RPM_SORT_USER0_PROM_EN; 8090157642Sps } else if (ifp->if_flags & IFF_ALLMULTI) { 8091170810Sdavidch DBPRINT(sc, BCE_INFO_MISC, "Enabling all multicast mode.\n"); 8092157642Sps 8093157642Sps /* Enable all multicast addresses. */ 8094157642Sps for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) { 8095251146Smarius REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4), 8096251146Smarius 0xffffffff); 8097251146Smarius } 8098157642Sps sort_mode |= BCE_RPM_SORT_USER0_MC_EN; 8099157642Sps } else { 8100157642Sps /* Accept one or more multicast(s). */ 8101170810Sdavidch DBPRINT(sc, BCE_INFO_MISC, "Enabling selective multicast mode.\n"); 8102157642Sps 8103195049Srwatson if_maddr_rlock(ifp); 8104157642Sps TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 8105157642Sps if (ifma->ifma_addr->sa_family != AF_LINK) 8106157642Sps continue; 8107157642Sps h = ether_crc32_le(LLADDR((struct sockaddr_dl *) 8108166153Sscottl ifma->ifma_addr), ETHER_ADDR_LEN) & 0xFF; 8109166153Sscottl hashes[(h & 0xE0) >> 5] |= 1 << (h & 0x1F); 8110157642Sps } 8111195049Srwatson if_maddr_runlock(ifp); 8112157642Sps 8113166153Sscottl for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) 8114157642Sps REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4), hashes[i]); 8115157642Sps 8116157642Sps sort_mode |= BCE_RPM_SORT_USER0_MC_HSH_EN; 8117157642Sps } 8118157642Sps 8119157642Sps /* Only make changes if the recive mode has actually changed. */ 8120157642Sps if (rx_mode != sc->rx_mode) { 8121206268Sdavidch DBPRINT(sc, BCE_VERBOSE_MISC, "Enabling new receive mode: " 8122206268Sdavidch "0x%08X\n", rx_mode); 8123157642Sps 8124157642Sps sc->rx_mode = rx_mode; 8125157642Sps REG_WR(sc, BCE_EMAC_RX_MODE, rx_mode); 8126157642Sps } 8127157642Sps 8128157642Sps /* Disable and clear the exisitng sort before enabling a new sort. */ 8129157642Sps REG_WR(sc, BCE_RPM_SORT_USER0, 0x0); 8130157642Sps REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode); 8131157642Sps REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode | BCE_RPM_SORT_USER0_ENA); 8132179771Sdavidch 8133179771Sdavidch DBEXIT(BCE_VERBOSE_MISC); 8134157642Sps} 8135157642Sps 8136157642Sps 8137157642Sps/****************************************************************************/ 8138157642Sps/* Called periodically to updates statistics from the controllers */ 8139157642Sps/* statistics block. */ 8140157642Sps/* */ 8141157642Sps/* Returns: */ 8142157642Sps/* Nothing. */ 8143157642Sps/****************************************************************************/ 8144157642Spsstatic void 8145157642Spsbce_stats_update(struct bce_softc *sc) 8146157642Sps{ 8147157642Sps struct ifnet *ifp; 8148157642Sps struct statistics_block *stats; 8149157642Sps 8150179771Sdavidch DBENTER(BCE_EXTREME_MISC); 8151157642Sps 8152157642Sps ifp = sc->bce_ifp; 8153157642Sps 8154251159Smarius bus_dmamap_sync(sc->stats_tag, sc->stats_map, BUS_DMASYNC_POSTREAD); 8155251159Smarius 8156157642Sps stats = (struct statistics_block *) sc->stats_block; 8157157642Sps 8158179771Sdavidch /* 8159179771Sdavidch * Certain controllers don't report 8160157642Sps * carrier sense errors correctly. 8161179771Sdavidch * See errata E11_5708CA0_1165. 8162157642Sps */ 8163157642Sps if (!(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) && 8164157642Sps !(BCE_CHIP_ID(sc) == BCE_CHIP_ID_5708_A0)) 8165207411Sdavidch ifp->if_oerrors += 8166206268Sdavidch (u_long) stats->stat_Dot3StatsCarrierSenseErrors; 8167157642Sps 8168157642Sps /* 8169157642Sps * Update the sysctl statistics from the 8170157642Sps * hardware statistics. 8171157642Sps */ 8172179771Sdavidch sc->stat_IfHCInOctets = 8173206268Sdavidch ((u64) stats->stat_IfHCInOctets_hi << 32) + 8174206268Sdavidch (u64) stats->stat_IfHCInOctets_lo; 8175157642Sps 8176157642Sps sc->stat_IfHCInBadOctets = 8177206268Sdavidch ((u64) stats->stat_IfHCInBadOctets_hi << 32) + 8178206268Sdavidch (u64) stats->stat_IfHCInBadOctets_lo; 8179157642Sps 8180157642Sps sc->stat_IfHCOutOctets = 8181206268Sdavidch ((u64) stats->stat_IfHCOutOctets_hi << 32) + 8182206268Sdavidch (u64) stats->stat_IfHCOutOctets_lo; 8183157642Sps 8184157642Sps sc->stat_IfHCOutBadOctets = 8185206268Sdavidch ((u64) stats->stat_IfHCOutBadOctets_hi << 32) + 8186206268Sdavidch (u64) stats->stat_IfHCOutBadOctets_lo; 8187157642Sps 8188157642Sps sc->stat_IfHCInUcastPkts = 8189206268Sdavidch ((u64) stats->stat_IfHCInUcastPkts_hi << 32) + 8190206268Sdavidch (u64) stats->stat_IfHCInUcastPkts_lo; 8191157642Sps 8192157642Sps sc->stat_IfHCInMulticastPkts = 8193206268Sdavidch ((u64) stats->stat_IfHCInMulticastPkts_hi << 32) + 8194206268Sdavidch (u64) stats->stat_IfHCInMulticastPkts_lo; 8195157642Sps 8196157642Sps sc->stat_IfHCInBroadcastPkts = 8197206268Sdavidch ((u64) stats->stat_IfHCInBroadcastPkts_hi << 32) + 8198206268Sdavidch (u64) stats->stat_IfHCInBroadcastPkts_lo; 8199157642Sps 8200157642Sps sc->stat_IfHCOutUcastPkts = 8201206268Sdavidch ((u64) stats->stat_IfHCOutUcastPkts_hi << 32) + 8202206268Sdavidch (u64) stats->stat_IfHCOutUcastPkts_lo; 8203157642Sps 8204157642Sps sc->stat_IfHCOutMulticastPkts = 8205206268Sdavidch ((u64) stats->stat_IfHCOutMulticastPkts_hi << 32) + 8206206268Sdavidch (u64) stats->stat_IfHCOutMulticastPkts_lo; 8207157642Sps 8208157642Sps sc->stat_IfHCOutBroadcastPkts = 8209206268Sdavidch ((u64) stats->stat_IfHCOutBroadcastPkts_hi << 32) + 8210206268Sdavidch (u64) stats->stat_IfHCOutBroadcastPkts_lo; 8211157642Sps 8212206268Sdavidch /* ToDo: Preserve counters beyond 32 bits? */ 8213206268Sdavidch /* ToDo: Read the statistics from auto-clear regs? */ 8214206268Sdavidch 8215157642Sps sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors = 8216206268Sdavidch stats->stat_emac_tx_stat_dot3statsinternalmactransmiterrors; 8217157642Sps 8218157642Sps sc->stat_Dot3StatsCarrierSenseErrors = 8219206268Sdavidch stats->stat_Dot3StatsCarrierSenseErrors; 8220157642Sps 8221179771Sdavidch sc->stat_Dot3StatsFCSErrors = 8222206268Sdavidch stats->stat_Dot3StatsFCSErrors; 8223157642Sps 8224157642Sps sc->stat_Dot3StatsAlignmentErrors = 8225206268Sdavidch stats->stat_Dot3StatsAlignmentErrors; 8226157642Sps 8227157642Sps sc->stat_Dot3StatsSingleCollisionFrames = 8228206268Sdavidch stats->stat_Dot3StatsSingleCollisionFrames; 8229157642Sps 8230157642Sps sc->stat_Dot3StatsMultipleCollisionFrames = 8231206268Sdavidch stats->stat_Dot3StatsMultipleCollisionFrames; 8232157642Sps 8233157642Sps sc->stat_Dot3StatsDeferredTransmissions = 8234206268Sdavidch stats->stat_Dot3StatsDeferredTransmissions; 8235157642Sps 8236157642Sps sc->stat_Dot3StatsExcessiveCollisions = 8237206268Sdavidch stats->stat_Dot3StatsExcessiveCollisions; 8238157642Sps 8239157642Sps sc->stat_Dot3StatsLateCollisions = 8240206268Sdavidch stats->stat_Dot3StatsLateCollisions; 8241157642Sps 8242157642Sps sc->stat_EtherStatsCollisions = 8243206268Sdavidch stats->stat_EtherStatsCollisions; 8244157642Sps 8245157642Sps sc->stat_EtherStatsFragments = 8246206268Sdavidch stats->stat_EtherStatsFragments; 8247157642Sps 8248157642Sps sc->stat_EtherStatsJabbers = 8249206268Sdavidch stats->stat_EtherStatsJabbers; 8250157642Sps 8251157642Sps sc->stat_EtherStatsUndersizePkts = 8252206268Sdavidch stats->stat_EtherStatsUndersizePkts; 8253157642Sps 8254189325Sdavidch sc->stat_EtherStatsOversizePkts = 8255206268Sdavidch stats->stat_EtherStatsOversizePkts; 8256157642Sps 8257157642Sps sc->stat_EtherStatsPktsRx64Octets = 8258206268Sdavidch stats->stat_EtherStatsPktsRx64Octets; 8259157642Sps 8260157642Sps sc->stat_EtherStatsPktsRx65Octetsto127Octets = 8261206268Sdavidch stats->stat_EtherStatsPktsRx65Octetsto127Octets; 8262157642Sps 8263157642Sps sc->stat_EtherStatsPktsRx128Octetsto255Octets = 8264206268Sdavidch stats->stat_EtherStatsPktsRx128Octetsto255Octets; 8265157642Sps 8266157642Sps sc->stat_EtherStatsPktsRx256Octetsto511Octets = 8267206268Sdavidch stats->stat_EtherStatsPktsRx256Octetsto511Octets; 8268157642Sps 8269157642Sps sc->stat_EtherStatsPktsRx512Octetsto1023Octets = 8270206268Sdavidch stats->stat_EtherStatsPktsRx512Octetsto1023Octets; 8271157642Sps 8272157642Sps sc->stat_EtherStatsPktsRx1024Octetsto1522Octets = 8273206268Sdavidch stats->stat_EtherStatsPktsRx1024Octetsto1522Octets; 8274157642Sps 8275157642Sps sc->stat_EtherStatsPktsRx1523Octetsto9022Octets = 8276206268Sdavidch stats->stat_EtherStatsPktsRx1523Octetsto9022Octets; 8277157642Sps 8278157642Sps sc->stat_EtherStatsPktsTx64Octets = 8279206268Sdavidch stats->stat_EtherStatsPktsTx64Octets; 8280157642Sps 8281157642Sps sc->stat_EtherStatsPktsTx65Octetsto127Octets = 8282206268Sdavidch stats->stat_EtherStatsPktsTx65Octetsto127Octets; 8283157642Sps 8284157642Sps sc->stat_EtherStatsPktsTx128Octetsto255Octets = 8285206268Sdavidch stats->stat_EtherStatsPktsTx128Octetsto255Octets; 8286157642Sps 8287157642Sps sc->stat_EtherStatsPktsTx256Octetsto511Octets = 8288206268Sdavidch stats->stat_EtherStatsPktsTx256Octetsto511Octets; 8289157642Sps 8290157642Sps sc->stat_EtherStatsPktsTx512Octetsto1023Octets = 8291206268Sdavidch stats->stat_EtherStatsPktsTx512Octetsto1023Octets; 8292157642Sps 8293157642Sps sc->stat_EtherStatsPktsTx1024Octetsto1522Octets = 8294206268Sdavidch stats->stat_EtherStatsPktsTx1024Octetsto1522Octets; 8295157642Sps 8296157642Sps sc->stat_EtherStatsPktsTx1523Octetsto9022Octets = 8297206268Sdavidch stats->stat_EtherStatsPktsTx1523Octetsto9022Octets; 8298157642Sps 8299157642Sps sc->stat_XonPauseFramesReceived = 8300206268Sdavidch stats->stat_XonPauseFramesReceived; 8301157642Sps 8302157642Sps sc->stat_XoffPauseFramesReceived = 8303206268Sdavidch stats->stat_XoffPauseFramesReceived; 8304157642Sps 8305157642Sps sc->stat_OutXonSent = 8306206268Sdavidch stats->stat_OutXonSent; 8307157642Sps 8308157642Sps sc->stat_OutXoffSent = 8309206268Sdavidch stats->stat_OutXoffSent; 8310157642Sps 8311157642Sps sc->stat_FlowControlDone = 8312206268Sdavidch stats->stat_FlowControlDone; 8313157642Sps 8314157642Sps sc->stat_MacControlFramesReceived = 8315206268Sdavidch stats->stat_MacControlFramesReceived; 8316157642Sps 8317157642Sps sc->stat_XoffStateEntered = 8318206268Sdavidch stats->stat_XoffStateEntered; 8319157642Sps 8320157642Sps sc->stat_IfInFramesL2FilterDiscards = 8321206268Sdavidch stats->stat_IfInFramesL2FilterDiscards; 8322157642Sps 8323157642Sps sc->stat_IfInRuleCheckerDiscards = 8324206268Sdavidch stats->stat_IfInRuleCheckerDiscards; 8325157642Sps 8326157642Sps sc->stat_IfInFTQDiscards = 8327206268Sdavidch stats->stat_IfInFTQDiscards; 8328157642Sps 8329157642Sps sc->stat_IfInMBUFDiscards = 8330206268Sdavidch stats->stat_IfInMBUFDiscards; 8331157642Sps 8332157642Sps sc->stat_IfInRuleCheckerP4Hit = 8333206268Sdavidch stats->stat_IfInRuleCheckerP4Hit; 8334157642Sps 8335157642Sps sc->stat_CatchupInRuleCheckerDiscards = 8336206268Sdavidch stats->stat_CatchupInRuleCheckerDiscards; 8337157642Sps 8338157642Sps sc->stat_CatchupInFTQDiscards = 8339206268Sdavidch stats->stat_CatchupInFTQDiscards; 8340157642Sps 8341157642Sps sc->stat_CatchupInMBUFDiscards = 8342206268Sdavidch stats->stat_CatchupInMBUFDiscards; 8343157642Sps 8344157642Sps sc->stat_CatchupInRuleCheckerP4Hit = 8345206268Sdavidch stats->stat_CatchupInRuleCheckerP4Hit; 8346157642Sps 8347170392Sdavidch sc->com_no_buffers = REG_RD_IND(sc, 0x120084); 8348170392Sdavidch 8349179771Sdavidch /* 8350179771Sdavidch * Update the interface statistics from the 8351179771Sdavidch * hardware statistics. 8352179771Sdavidch */ 8353182293Sdavidch ifp->if_collisions = 8354206268Sdavidch (u_long) sc->stat_EtherStatsCollisions; 8355179771Sdavidch 8356182293Sdavidch /* ToDo: This method loses soft errors. */ 8357182293Sdavidch ifp->if_ierrors = 8358206268Sdavidch (u_long) sc->stat_EtherStatsUndersizePkts + 8359206268Sdavidch (u_long) sc->stat_EtherStatsOversizePkts + 8360206268Sdavidch (u_long) sc->stat_IfInMBUFDiscards + 8361206268Sdavidch (u_long) sc->stat_Dot3StatsAlignmentErrors + 8362206268Sdavidch (u_long) sc->stat_Dot3StatsFCSErrors + 8363206268Sdavidch (u_long) sc->stat_IfInRuleCheckerDiscards + 8364206268Sdavidch (u_long) sc->stat_IfInFTQDiscards + 8365206268Sdavidch (u_long) sc->com_no_buffers; 8366179771Sdavidch 8367182293Sdavidch /* ToDo: This method loses soft errors. */ 8368182293Sdavidch ifp->if_oerrors = 8369206268Sdavidch (u_long) sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors + 8370206268Sdavidch (u_long) sc->stat_Dot3StatsExcessiveCollisions + 8371206268Sdavidch (u_long) sc->stat_Dot3StatsLateCollisions; 8372179771Sdavidch 8373206268Sdavidch /* ToDo: Add additional statistics? */ 8374182293Sdavidch 8375179771Sdavidch DBEXIT(BCE_EXTREME_MISC); 8376157642Sps} 8377157642Sps 8378157642Sps 8379169271Sdavidch/****************************************************************************/ 8380170810Sdavidch/* Periodic function to notify the bootcode that the driver is still */ 8381170810Sdavidch/* present. */ 8382170810Sdavidch/* */ 8383170810Sdavidch/* Returns: */ 8384170810Sdavidch/* Nothing. */ 8385170810Sdavidch/****************************************************************************/ 8386170810Sdavidchstatic void 8387170810Sdavidchbce_pulse(void *xsc) 8388170810Sdavidch{ 8389170810Sdavidch struct bce_softc *sc = xsc; 8390170810Sdavidch u32 msg; 8391170810Sdavidch 8392179771Sdavidch DBENTER(BCE_EXTREME_MISC); 8393170810Sdavidch 8394170810Sdavidch BCE_LOCK_ASSERT(sc); 8395170810Sdavidch 8396170810Sdavidch /* Tell the firmware that the driver is still running. */ 8397170810Sdavidch msg = (u32) ++sc->bce_fw_drv_pulse_wr_seq; 8398194781Sdavidch bce_shmem_wr(sc, BCE_DRV_PULSE_MB, msg); 8399170810Sdavidch 8400206268Sdavidch /* Update the bootcode condition. */ 8401206268Sdavidch sc->bc_state = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION); 8402206268Sdavidch 8403206268Sdavidch /* Report whether the bootcode still knows the driver is running. */ 8404218423Sdavidch if (bce_verbose || bootverbose) { 8405207411Sdavidch if (sc->bce_drv_cardiac_arrest == FALSE) { 8406207411Sdavidch if (!(sc->bc_state & BCE_CONDITION_DRV_PRESENT)) { 8407207411Sdavidch sc->bce_drv_cardiac_arrest = TRUE; 8408207411Sdavidch BCE_PRINTF("%s(): Warning: bootcode " 8409207411Sdavidch "thinks driver is absent! " 8410207411Sdavidch "(bc_state = 0x%08X)\n", 8411207411Sdavidch __FUNCTION__, sc->bc_state); 8412207411Sdavidch } 8413207411Sdavidch } else { 8414207411Sdavidch /* 8415207411Sdavidch * Not supported by all bootcode versions. 8416207411Sdavidch * (v5.0.11+ and v5.2.1+) Older bootcode 8417207411Sdavidch * will require the driver to reset the 8418207411Sdavidch * controller to clear this condition. 8419207411Sdavidch */ 8420207411Sdavidch if (sc->bc_state & BCE_CONDITION_DRV_PRESENT) { 8421207411Sdavidch sc->bce_drv_cardiac_arrest = FALSE; 8422207411Sdavidch BCE_PRINTF("%s(): Bootcode found the " 8423207411Sdavidch "driver pulse! (bc_state = 0x%08X)\n", 8424207411Sdavidch __FUNCTION__, sc->bc_state); 8425207411Sdavidch } 8426206268Sdavidch } 8427206268Sdavidch } 8428206268Sdavidch 8429206268Sdavidch 8430170810Sdavidch /* Schedule the next pulse. */ 8431170810Sdavidch callout_reset(&sc->bce_pulse_callout, hz, bce_pulse, sc); 8432170810Sdavidch 8433179771Sdavidch DBEXIT(BCE_EXTREME_MISC); 8434170810Sdavidch} 8435170810Sdavidch 8436170810Sdavidch 8437170810Sdavidch/****************************************************************************/ 8438170392Sdavidch/* Periodic function to perform maintenance tasks. */ 8439169271Sdavidch/* */ 8440169271Sdavidch/* Returns: */ 8441169271Sdavidch/* Nothing. */ 8442169271Sdavidch/****************************************************************************/ 8443157642Spsstatic void 8444165933Sdelphijbce_tick(void *xsc) 8445157642Sps{ 8446165933Sdelphij struct bce_softc *sc = xsc; 8447169271Sdavidch struct mii_data *mii; 8448157642Sps struct ifnet *ifp; 8449235151Syongari struct ifmediareq ifmr; 8450157642Sps 8451157642Sps ifp = sc->bce_ifp; 8452157642Sps 8453179771Sdavidch DBENTER(BCE_EXTREME_MISC); 8454179771Sdavidch 8455157642Sps BCE_LOCK_ASSERT(sc); 8456157642Sps 8457176448Sdavidch /* Schedule the next tick. */ 8458176448Sdavidch callout_reset(&sc->bce_tick_callout, hz, bce_tick, sc); 8459176448Sdavidch 8460157642Sps /* Update the statistics from the hardware statistics block. */ 8461157642Sps bce_stats_update(sc); 8462157642Sps 8463251142Smarius /* Ensure page and RX chains get refilled in low-memory situations. */ 8464218423Sdavidch if (bce_hdr_split == TRUE) 8465218423Sdavidch bce_fill_pg_chain(sc); 8466176448Sdavidch bce_fill_rx_chain(sc); 8467176448Sdavidch 8468169271Sdavidch /* Check that chip hasn't hung. */ 8469165933Sdelphij bce_watchdog(sc); 8470165933Sdelphij 8471157642Sps /* If link is up already up then we're done. */ 8472234121Syongari if (sc->bce_link_up == TRUE) 8473179771Sdavidch goto bce_tick_exit; 8474157642Sps 8475182293Sdavidch /* Link is down. Check what the PHY's doing. */ 8476235151Syongari if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) { 8477235151Syongari bzero(&ifmr, sizeof(ifmr)); 8478235151Syongari bce_ifmedia_sts_rphy(sc, &ifmr); 8479235151Syongari if ((ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) == 8480235151Syongari (IFM_ACTIVE | IFM_AVALID)) { 8481235151Syongari sc->bce_link_up = TRUE; 8482235151Syongari bce_miibus_statchg(sc->bce_dev); 8483235151Syongari } 8484235151Syongari } else { 8485235151Syongari mii = device_get_softc(sc->bce_miibus); 8486235151Syongari mii_tick(mii); 8487235151Syongari /* Check if the link has come up. */ 8488235151Syongari if ((mii->mii_media_status & IFM_ACTIVE) && 8489235151Syongari (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)) { 8490235151Syongari DBPRINT(sc, BCE_VERBOSE_MISC, "%s(): Link up!\n", 8491235151Syongari __FUNCTION__); 8492235151Syongari sc->bce_link_up = TRUE; 8493235151Syongari if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 8494235151Syongari IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX || 8495235151Syongari IFM_SUBTYPE(mii->mii_media_active) == IFM_2500_SX) && 8496235151Syongari (bce_verbose || bootverbose)) 8497235151Syongari BCE_PRINTF("Gigabit link up!\n"); 8498235151Syongari } 8499157642Sps 8500235151Syongari } 8501235151Syongari if (sc->bce_link_up == TRUE) { 8502234121Syongari /* Now that link is up, handle any outstanding TX traffic. */ 8503234121Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 8504234121Syongari DBPRINT(sc, BCE_VERBOSE_MISC, "%s(): Found " 8505234121Syongari "pending TX traffic.\n", __FUNCTION__); 8506234121Syongari bce_start_locked(ifp); 8507234121Syongari } 8508157642Sps } 8509157642Sps 8510179771Sdavidchbce_tick_exit: 8511179771Sdavidch DBEXIT(BCE_EXTREME_MISC); 8512157642Sps} 8513157642Sps 8514235151Syongaristatic void 8515235151Syongaribce_fw_cap_init(struct bce_softc *sc) 8516235151Syongari{ 8517235151Syongari u32 ack, cap, link; 8518235151Syongari 8519235151Syongari ack = 0; 8520235151Syongari cap = bce_shmem_rd(sc, BCE_FW_CAP_MB); 8521235151Syongari if ((cap & BCE_FW_CAP_SIGNATURE_MAGIC_MASK) != 8522235151Syongari BCE_FW_CAP_SIGNATURE_MAGIC) 8523235151Syongari return; 8524235151Syongari if ((cap & (BCE_FW_CAP_MFW_KEEP_VLAN | BCE_FW_CAP_BC_KEEP_VLAN)) == 8525235151Syongari (BCE_FW_CAP_MFW_KEEP_VLAN | BCE_FW_CAP_BC_KEEP_VLAN)) 8526235151Syongari ack |= BCE_DRV_ACK_CAP_SIGNATURE_MAGIC | 8527235151Syongari BCE_FW_CAP_MFW_KEEP_VLAN | BCE_FW_CAP_BC_KEEP_VLAN; 8528235151Syongari if ((sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) != 0 && 8529235151Syongari (cap & BCE_FW_CAP_REMOTE_PHY_CAP) != 0) { 8530235151Syongari sc->bce_phy_flags &= ~BCE_PHY_REMOTE_PORT_FIBER_FLAG; 8531235151Syongari sc->bce_phy_flags |= BCE_PHY_REMOTE_CAP_FLAG; 8532235151Syongari link = bce_shmem_rd(sc, BCE_LINK_STATUS); 8533235151Syongari if ((link & BCE_LINK_STATUS_SERDES_LINK) != 0) 8534235151Syongari sc->bce_phy_flags |= BCE_PHY_REMOTE_PORT_FIBER_FLAG; 8535235151Syongari ack |= BCE_DRV_ACK_CAP_SIGNATURE_MAGIC | 8536235151Syongari BCE_FW_CAP_REMOTE_PHY_CAP; 8537235151Syongari } 8538235151Syongari 8539235151Syongari if (ack != 0) 8540235151Syongari bce_shmem_wr(sc, BCE_DRV_ACK_CAP_MB, ack); 8541235151Syongari} 8542235151Syongari 8543235151Syongari 8544157642Sps#ifdef BCE_DEBUG 8545157642Sps/****************************************************************************/ 8546157642Sps/* Allows the driver state to be dumped through the sysctl interface. */ 8547157642Sps/* */ 8548157642Sps/* Returns: */ 8549157642Sps/* 0 for success, positive value for failure. */ 8550157642Sps/****************************************************************************/ 8551157642Spsstatic int 8552157642Spsbce_sysctl_driver_state(SYSCTL_HANDLER_ARGS) 8553157642Sps{ 8554206268Sdavidch int error; 8555206268Sdavidch int result; 8556206268Sdavidch struct bce_softc *sc; 8557157642Sps 8558206268Sdavidch result = -1; 8559206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8560157642Sps 8561206268Sdavidch if (error || !req->newptr) 8562206268Sdavidch return (error); 8563157642Sps 8564206268Sdavidch if (result == 1) { 8565206268Sdavidch sc = (struct bce_softc *)arg1; 8566206268Sdavidch bce_dump_driver_state(sc); 8567206268Sdavidch } 8568157642Sps 8569206268Sdavidch return error; 8570157642Sps} 8571157642Sps 8572157642Sps 8573157642Sps/****************************************************************************/ 8574157642Sps/* Allows the hardware state to be dumped through the sysctl interface. */ 8575157642Sps/* */ 8576157642Sps/* Returns: */ 8577157642Sps/* 0 for success, positive value for failure. */ 8578157642Sps/****************************************************************************/ 8579157642Spsstatic int 8580157642Spsbce_sysctl_hw_state(SYSCTL_HANDLER_ARGS) 8581157642Sps{ 8582206268Sdavidch int error; 8583206268Sdavidch int result; 8584206268Sdavidch struct bce_softc *sc; 8585157642Sps 8586206268Sdavidch result = -1; 8587206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8588157642Sps 8589206268Sdavidch if (error || !req->newptr) 8590206268Sdavidch return (error); 8591157642Sps 8592206268Sdavidch if (result == 1) { 8593206268Sdavidch sc = (struct bce_softc *)arg1; 8594206268Sdavidch bce_dump_hw_state(sc); 8595206268Sdavidch } 8596157642Sps 8597206268Sdavidch return error; 8598157642Sps} 8599157642Sps 8600157642Sps 8601157642Sps/****************************************************************************/ 8602206268Sdavidch/* Allows the status block to be dumped through the sysctl interface. */ 8603206268Sdavidch/* */ 8604206268Sdavidch/* Returns: */ 8605206268Sdavidch/* 0 for success, positive value for failure. */ 8606206268Sdavidch/****************************************************************************/ 8607206268Sdavidchstatic int 8608206268Sdavidchbce_sysctl_status_block(SYSCTL_HANDLER_ARGS) 8609206268Sdavidch{ 8610206268Sdavidch int error; 8611206268Sdavidch int result; 8612206268Sdavidch struct bce_softc *sc; 8613206268Sdavidch 8614206268Sdavidch result = -1; 8615206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8616206268Sdavidch 8617206268Sdavidch if (error || !req->newptr) 8618206268Sdavidch return (error); 8619206268Sdavidch 8620206268Sdavidch if (result == 1) { 8621206268Sdavidch sc = (struct bce_softc *)arg1; 8622206268Sdavidch bce_dump_status_block(sc); 8623206268Sdavidch } 8624206268Sdavidch 8625206268Sdavidch return error; 8626206268Sdavidch} 8627206268Sdavidch 8628206268Sdavidch 8629206268Sdavidch/****************************************************************************/ 8630206268Sdavidch/* Allows the stats block to be dumped through the sysctl interface. */ 8631206268Sdavidch/* */ 8632206268Sdavidch/* Returns: */ 8633206268Sdavidch/* 0 for success, positive value for failure. */ 8634206268Sdavidch/****************************************************************************/ 8635206268Sdavidchstatic int 8636206268Sdavidchbce_sysctl_stats_block(SYSCTL_HANDLER_ARGS) 8637206268Sdavidch{ 8638206268Sdavidch int error; 8639206268Sdavidch int result; 8640206268Sdavidch struct bce_softc *sc; 8641206268Sdavidch 8642206268Sdavidch result = -1; 8643206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8644206268Sdavidch 8645206268Sdavidch if (error || !req->newptr) 8646206268Sdavidch return (error); 8647206268Sdavidch 8648206268Sdavidch if (result == 1) { 8649206268Sdavidch sc = (struct bce_softc *)arg1; 8650206268Sdavidch bce_dump_stats_block(sc); 8651206268Sdavidch } 8652206268Sdavidch 8653206268Sdavidch return error; 8654206268Sdavidch} 8655206268Sdavidch 8656206268Sdavidch 8657206268Sdavidch/****************************************************************************/ 8658207411Sdavidch/* Allows the stat counters to be cleared without unloading/reloading the */ 8659207411Sdavidch/* driver. */ 8660207411Sdavidch/* */ 8661207411Sdavidch/* Returns: */ 8662207411Sdavidch/* 0 for success, positive value for failure. */ 8663207411Sdavidch/****************************************************************************/ 8664207411Sdavidchstatic int 8665207411Sdavidchbce_sysctl_stats_clear(SYSCTL_HANDLER_ARGS) 8666207411Sdavidch{ 8667207411Sdavidch int error; 8668207411Sdavidch int result; 8669207411Sdavidch struct bce_softc *sc; 8670207411Sdavidch 8671207411Sdavidch result = -1; 8672207411Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8673207411Sdavidch 8674207411Sdavidch if (error || !req->newptr) 8675207411Sdavidch return (error); 8676207411Sdavidch 8677207411Sdavidch if (result == 1) { 8678207411Sdavidch sc = (struct bce_softc *)arg1; 8679218423Sdavidch struct statistics_block *stats; 8680207411Sdavidch 8681218423Sdavidch stats = (struct statistics_block *) sc->stats_block; 8682218423Sdavidch bzero(stats, sizeof(struct statistics_block)); 8683251159Smarius bus_dmamap_sync(sc->stats_tag, sc->stats_map, 8684251159Smarius BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 8685218423Sdavidch 8686207411Sdavidch /* Clear the internal H/W statistics counters. */ 8687207411Sdavidch REG_WR(sc, BCE_HC_COMMAND, BCE_HC_COMMAND_CLR_STAT_NOW); 8688207411Sdavidch 8689207411Sdavidch /* Reset the driver maintained statistics. */ 8690207411Sdavidch sc->interrupts_rx = 8691207411Sdavidch sc->interrupts_tx = 0; 8692207411Sdavidch sc->tso_frames_requested = 8693207411Sdavidch sc->tso_frames_completed = 8694207411Sdavidch sc->tso_frames_failed = 0; 8695207411Sdavidch sc->rx_empty_count = 8696207411Sdavidch sc->tx_full_count = 0; 8697218423Sdavidch sc->rx_low_watermark = USABLE_RX_BD_ALLOC; 8698207411Sdavidch sc->tx_hi_watermark = 0; 8699207411Sdavidch sc->l2fhdr_error_count = 8700207411Sdavidch sc->l2fhdr_error_sim_count = 0; 8701207411Sdavidch sc->mbuf_alloc_failed_count = 8702207411Sdavidch sc->mbuf_alloc_failed_sim_count = 0; 8703207411Sdavidch sc->dma_map_addr_rx_failed_count = 8704207411Sdavidch sc->dma_map_addr_tx_failed_count = 0; 8705207411Sdavidch sc->mbuf_frag_count = 0; 8706207411Sdavidch sc->csum_offload_tcp_udp = 8707218423Sdavidch sc->csum_offload_ip = 0; 8708207411Sdavidch sc->vlan_tagged_frames_rcvd = 8709218423Sdavidch sc->vlan_tagged_frames_stripped = 0; 8710218423Sdavidch sc->split_header_frames_rcvd = 8711218423Sdavidch sc->split_header_tcp_frames_rcvd = 0; 8712207411Sdavidch 8713207411Sdavidch /* Clear firmware maintained statistics. */ 8714207411Sdavidch REG_WR_IND(sc, 0x120084, 0); 8715207411Sdavidch } 8716207411Sdavidch 8717207411Sdavidch return error; 8718207411Sdavidch} 8719207411Sdavidch 8720207411Sdavidch 8721207411Sdavidch/****************************************************************************/ 8722218423Sdavidch/* Allows the shared memory contents to be dumped through the sysctl . */ 8723218423Sdavidch/* interface. */ 8724218423Sdavidch/* */ 8725218423Sdavidch/* Returns: */ 8726218423Sdavidch/* 0 for success, positive value for failure. */ 8727218423Sdavidch/****************************************************************************/ 8728218423Sdavidchstatic int 8729218423Sdavidchbce_sysctl_shmem_state(SYSCTL_HANDLER_ARGS) 8730218423Sdavidch{ 8731218423Sdavidch int error; 8732218423Sdavidch int result; 8733218423Sdavidch struct bce_softc *sc; 8734218423Sdavidch 8735218423Sdavidch result = -1; 8736218423Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8737218423Sdavidch 8738218423Sdavidch if (error || !req->newptr) 8739218423Sdavidch return (error); 8740218423Sdavidch 8741218423Sdavidch if (result == 1) { 8742218423Sdavidch sc = (struct bce_softc *)arg1; 8743218423Sdavidch bce_dump_shmem_state(sc); 8744218423Sdavidch } 8745218423Sdavidch 8746218423Sdavidch return error; 8747218423Sdavidch} 8748218423Sdavidch 8749218423Sdavidch 8750218423Sdavidch/****************************************************************************/ 8751170810Sdavidch/* Allows the bootcode state to be dumped through the sysctl interface. */ 8752157642Sps/* */ 8753157642Sps/* Returns: */ 8754157642Sps/* 0 for success, positive value for failure. */ 8755157642Sps/****************************************************************************/ 8756157642Spsstatic int 8757170810Sdavidchbce_sysctl_bc_state(SYSCTL_HANDLER_ARGS) 8758170810Sdavidch{ 8759206268Sdavidch int error; 8760206268Sdavidch int result; 8761206268Sdavidch struct bce_softc *sc; 8762170810Sdavidch 8763206268Sdavidch result = -1; 8764206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8765170810Sdavidch 8766206268Sdavidch if (error || !req->newptr) 8767206268Sdavidch return (error); 8768170810Sdavidch 8769206268Sdavidch if (result == 1) { 8770206268Sdavidch sc = (struct bce_softc *)arg1; 8771206268Sdavidch bce_dump_bc_state(sc); 8772206268Sdavidch } 8773170810Sdavidch 8774206268Sdavidch return error; 8775170810Sdavidch} 8776170810Sdavidch 8777170810Sdavidch 8778170810Sdavidch/****************************************************************************/ 8779206268Sdavidch/* Provides a sysctl interface to allow dumping the RX BD chain. */ 8780170810Sdavidch/* */ 8781170810Sdavidch/* Returns: */ 8782170810Sdavidch/* 0 for success, positive value for failure. */ 8783170810Sdavidch/****************************************************************************/ 8784170810Sdavidchstatic int 8785206268Sdavidchbce_sysctl_dump_rx_bd_chain(SYSCTL_HANDLER_ARGS) 8786157642Sps{ 8787206268Sdavidch int error; 8788206268Sdavidch int result; 8789206268Sdavidch struct bce_softc *sc; 8790157642Sps 8791206268Sdavidch result = -1; 8792206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8793157642Sps 8794206268Sdavidch if (error || !req->newptr) 8795206268Sdavidch return (error); 8796157642Sps 8797206268Sdavidch if (result == 1) { 8798206268Sdavidch sc = (struct bce_softc *)arg1; 8799218423Sdavidch bce_dump_rx_bd_chain(sc, 0, TOTAL_RX_BD_ALLOC); 8800206268Sdavidch } 8801157642Sps 8802206268Sdavidch return error; 8803157642Sps} 8804157642Sps 8805157642Sps 8806157642Sps/****************************************************************************/ 8807206268Sdavidch/* Provides a sysctl interface to allow dumping the RX MBUF chain. */ 8808206268Sdavidch/* */ 8809206268Sdavidch/* Returns: */ 8810206268Sdavidch/* 0 for success, positive value for failure. */ 8811206268Sdavidch/****************************************************************************/ 8812206268Sdavidchstatic int 8813206268Sdavidchbce_sysctl_dump_rx_mbuf_chain(SYSCTL_HANDLER_ARGS) 8814206268Sdavidch{ 8815206268Sdavidch int error; 8816206268Sdavidch int result; 8817206268Sdavidch struct bce_softc *sc; 8818206268Sdavidch 8819206268Sdavidch result = -1; 8820206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8821206268Sdavidch 8822206268Sdavidch if (error || !req->newptr) 8823206268Sdavidch return (error); 8824206268Sdavidch 8825206268Sdavidch if (result == 1) { 8826206268Sdavidch sc = (struct bce_softc *)arg1; 8827218423Sdavidch bce_dump_rx_mbuf_chain(sc, 0, USABLE_RX_BD_ALLOC); 8828206268Sdavidch } 8829206268Sdavidch 8830206268Sdavidch return error; 8831206268Sdavidch} 8832206268Sdavidch 8833206268Sdavidch 8834206268Sdavidch/****************************************************************************/ 8835170810Sdavidch/* Provides a sysctl interface to allow dumping the TX chain. */ 8836157642Sps/* */ 8837169271Sdavidch/* Returns: */ 8838169271Sdavidch/* 0 for success, positive value for failure. */ 8839169271Sdavidch/****************************************************************************/ 8840169271Sdavidchstatic int 8841169271Sdavidchbce_sysctl_dump_tx_chain(SYSCTL_HANDLER_ARGS) 8842169271Sdavidch{ 8843206268Sdavidch int error; 8844206268Sdavidch int result; 8845206268Sdavidch struct bce_softc *sc; 8846169271Sdavidch 8847206268Sdavidch result = -1; 8848206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8849169271Sdavidch 8850206268Sdavidch if (error || !req->newptr) 8851206268Sdavidch return (error); 8852169271Sdavidch 8853206268Sdavidch if (result == 1) { 8854206268Sdavidch sc = (struct bce_softc *)arg1; 8855218423Sdavidch bce_dump_tx_chain(sc, 0, TOTAL_TX_BD_ALLOC); 8856206268Sdavidch } 8857169271Sdavidch 8858206268Sdavidch return error; 8859169271Sdavidch} 8860169271Sdavidch 8861169271Sdavidch 8862169271Sdavidch/****************************************************************************/ 8863176448Sdavidch/* Provides a sysctl interface to allow dumping the page chain. */ 8864176448Sdavidch/* */ 8865176448Sdavidch/* Returns: */ 8866176448Sdavidch/* 0 for success, positive value for failure. */ 8867176448Sdavidch/****************************************************************************/ 8868176448Sdavidchstatic int 8869176448Sdavidchbce_sysctl_dump_pg_chain(SYSCTL_HANDLER_ARGS) 8870176448Sdavidch{ 8871206268Sdavidch int error; 8872206268Sdavidch int result; 8873206268Sdavidch struct bce_softc *sc; 8874176448Sdavidch 8875206268Sdavidch result = -1; 8876206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8877176448Sdavidch 8878206268Sdavidch if (error || !req->newptr) 8879206268Sdavidch return (error); 8880176448Sdavidch 8881206268Sdavidch if (result == 1) { 8882206268Sdavidch sc = (struct bce_softc *)arg1; 8883218423Sdavidch bce_dump_pg_chain(sc, 0, TOTAL_PG_BD_ALLOC); 8884206268Sdavidch } 8885176448Sdavidch 8886206268Sdavidch return error; 8887179771Sdavidch} 8888176448Sdavidch 8889179771Sdavidch/****************************************************************************/ 8890179771Sdavidch/* Provides a sysctl interface to allow reading arbitrary NVRAM offsets in */ 8891179771Sdavidch/* the device. DO NOT ENABLE ON PRODUCTION SYSTEMS! */ 8892179771Sdavidch/* */ 8893179771Sdavidch/* Returns: */ 8894179771Sdavidch/* 0 for success, positive value for failure. */ 8895179771Sdavidch/****************************************************************************/ 8896179771Sdavidchstatic int 8897179771Sdavidchbce_sysctl_nvram_read(SYSCTL_HANDLER_ARGS) 8898179771Sdavidch{ 8899179771Sdavidch struct bce_softc *sc = (struct bce_softc *)arg1; 8900179771Sdavidch int error; 8901182293Sdavidch u32 result; 8902182293Sdavidch u32 val[1]; 8903179771Sdavidch u8 *data = (u8 *) val; 8904176448Sdavidch 8905179771Sdavidch result = -1; 8906179771Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8907179771Sdavidch if (error || (req->newptr == NULL)) 8908179771Sdavidch return (error); 8909179771Sdavidch 8910218527Sdavidch error = bce_nvram_read(sc, result, data, 4); 8911218527Sdavidch 8912179771Sdavidch BCE_PRINTF("offset 0x%08X = 0x%08X\n", result, bce_be32toh(val[0])); 8913182293Sdavidch 8914179771Sdavidch return (error); 8915179771Sdavidch} 8916182293Sdavidch 8917182293Sdavidch 8918176448Sdavidch/****************************************************************************/ 8919170392Sdavidch/* Provides a sysctl interface to allow reading arbitrary registers in the */ 8920170392Sdavidch/* device. DO NOT ENABLE ON PRODUCTION SYSTEMS! */ 8921157642Sps/* */ 8922157642Sps/* Returns: */ 8923157642Sps/* 0 for success, positive value for failure. */ 8924157642Sps/****************************************************************************/ 8925157642Spsstatic int 8926169271Sdavidchbce_sysctl_reg_read(SYSCTL_HANDLER_ARGS) 8927169271Sdavidch{ 8928179771Sdavidch struct bce_softc *sc = (struct bce_softc *)arg1; 8929169271Sdavidch int error; 8930170810Sdavidch u32 val, result; 8931179771Sdavidch 8932169271Sdavidch result = -1; 8933169271Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8934169271Sdavidch if (error || (req->newptr == NULL)) 8935169271Sdavidch return (error); 8936179771Sdavidch 8937170392Sdavidch /* Make sure the register is accessible. */ 8938169271Sdavidch if (result < 0x8000) { 8939169271Sdavidch val = REG_RD(sc, result); 8940169271Sdavidch BCE_PRINTF("reg 0x%08X = 0x%08X\n", result, val); 8941169271Sdavidch } else if (result < 0x0280000) { 8942169271Sdavidch val = REG_RD_IND(sc, result); 8943170392Sdavidch BCE_PRINTF("reg 0x%08X = 0x%08X\n", result, val); 8944169271Sdavidch } 8945179771Sdavidch 8946169271Sdavidch return (error); 8947169271Sdavidch} 8948170392Sdavidch 8949179771Sdavidch 8950169271Sdavidch/****************************************************************************/ 8951170392Sdavidch/* Provides a sysctl interface to allow reading arbitrary PHY registers in */ 8952170392Sdavidch/* the device. DO NOT ENABLE ON PRODUCTION SYSTEMS! */ 8953169632Sdavidch/* */ 8954169632Sdavidch/* Returns: */ 8955169632Sdavidch/* 0 for success, positive value for failure. */ 8956169632Sdavidch/****************************************************************************/ 8957169632Sdavidchstatic int 8958169632Sdavidchbce_sysctl_phy_read(SYSCTL_HANDLER_ARGS) 8959169632Sdavidch{ 8960170392Sdavidch struct bce_softc *sc; 8961169632Sdavidch device_t dev; 8962169632Sdavidch int error, result; 8963169632Sdavidch u16 val; 8964169632Sdavidch 8965169632Sdavidch result = -1; 8966169632Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 8967169632Sdavidch if (error || (req->newptr == NULL)) 8968169632Sdavidch return (error); 8969169632Sdavidch 8970170392Sdavidch /* Make sure the register is accessible. */ 8971169632Sdavidch if (result < 0x20) { 8972170392Sdavidch sc = (struct bce_softc *)arg1; 8973169632Sdavidch dev = sc->bce_dev; 8974169632Sdavidch val = bce_miibus_read_reg(dev, sc->bce_phy_addr, result); 8975169632Sdavidch BCE_PRINTF("phy 0x%02X = 0x%04X\n", result, val); 8976169632Sdavidch } 8977169632Sdavidch return (error); 8978169632Sdavidch} 8979170392Sdavidch 8980170392Sdavidch 8981218527Sdavidch/****************************************************************************/ 8982218527Sdavidch/* Provides a sysctl interface for dumping the nvram contents. */ 8983218527Sdavidch/* DO NOT ENABLE ON PRODUCTION SYSTEMS! */ 8984218527Sdavidch/* */ 8985218527Sdavidch/* Returns: */ 8986218527Sdavidch/* 0 for success, positive errno for failure. */ 8987218527Sdavidch/****************************************************************************/ 8988213489Sambriskostatic int 8989218527Sdavidchbce_sysctl_nvram_dump(SYSCTL_HANDLER_ARGS) 8990213489Sambrisko{ 8991213489Sambrisko struct bce_softc *sc = (struct bce_softc *)arg1; 8992213489Sambrisko int error, i; 8993213489Sambrisko 8994218527Sdavidch if (sc->nvram_buf == NULL) 8995213489Sambrisko sc->nvram_buf = malloc(sc->bce_flash_size, 8996218527Sdavidch M_TEMP, M_ZERO | M_WAITOK); 8997218527Sdavidch 8998218527Sdavidch error = 0; 8999213489Sambrisko if (req->oldlen == sc->bce_flash_size) { 9000218527Sdavidch for (i = 0; i < sc->bce_flash_size && error == 0; i++) 9001218527Sdavidch error = bce_nvram_read(sc, i, &sc->nvram_buf[i], 1); 9002213489Sambrisko } 9003213489Sambrisko 9004218527Sdavidch if (error == 0) 9005218527Sdavidch error = SYSCTL_OUT(req, sc->nvram_buf, sc->bce_flash_size); 9006213489Sambrisko 9007213489Sambrisko return error; 9008213489Sambrisko} 9009213489Sambrisko 9010213489Sambrisko#ifdef BCE_NVRAM_WRITE_SUPPORT 9011218527Sdavidch/****************************************************************************/ 9012218527Sdavidch/* Provides a sysctl interface for writing to nvram. */ 9013218527Sdavidch/* DO NOT ENABLE ON PRODUCTION SYSTEMS! */ 9014218527Sdavidch/* */ 9015218527Sdavidch/* Returns: */ 9016218527Sdavidch/* 0 for success, positive errno for failure. */ 9017218527Sdavidch/****************************************************************************/ 9018213489Sambriskostatic int 9019218527Sdavidchbce_sysctl_nvram_write(SYSCTL_HANDLER_ARGS) 9020213489Sambrisko{ 9021213489Sambrisko struct bce_softc *sc = (struct bce_softc *)arg1; 9022213489Sambrisko int error; 9023213489Sambrisko 9024218527Sdavidch if (sc->nvram_buf == NULL) 9025213489Sambrisko sc->nvram_buf = malloc(sc->bce_flash_size, 9026218527Sdavidch M_TEMP, M_ZERO | M_WAITOK); 9027218527Sdavidch else 9028218527Sdavidch bzero(sc->nvram_buf, sc->bce_flash_size); 9029218527Sdavidch 9030213489Sambrisko error = SYSCTL_IN(req, sc->nvram_buf, sc->bce_flash_size); 9031218527Sdavidch if (error == 0) 9032218527Sdavidch return (error); 9033213489Sambrisko 9034218527Sdavidch if (req->newlen == sc->bce_flash_size) 9035218527Sdavidch error = bce_nvram_write(sc, 0, sc->nvram_buf, 9036218527Sdavidch sc->bce_flash_size); 9037213489Sambrisko 9038213489Sambrisko 9039213489Sambrisko return error; 9040213489Sambrisko} 9041213489Sambrisko#endif 9042213489Sambrisko 9043213489Sambrisko 9044169632Sdavidch/****************************************************************************/ 9045179771Sdavidch/* Provides a sysctl interface to allow reading a CID. */ 9046179771Sdavidch/* */ 9047179771Sdavidch/* Returns: */ 9048179771Sdavidch/* 0 for success, positive value for failure. */ 9049179771Sdavidch/****************************************************************************/ 9050179771Sdavidchstatic int 9051179771Sdavidchbce_sysctl_dump_ctx(SYSCTL_HANDLER_ARGS) 9052179771Sdavidch{ 9053179771Sdavidch struct bce_softc *sc; 9054207411Sdavidch int error, result; 9055179771Sdavidch 9056179771Sdavidch result = -1; 9057179771Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 9058179771Sdavidch if (error || (req->newptr == NULL)) 9059179771Sdavidch return (error); 9060179771Sdavidch 9061179771Sdavidch /* Make sure the register is accessible. */ 9062179771Sdavidch if (result <= TX_CID) { 9063179771Sdavidch sc = (struct bce_softc *)arg1; 9064179771Sdavidch bce_dump_ctx(sc, result); 9065179771Sdavidch } 9066179771Sdavidch 9067179771Sdavidch return (error); 9068179771Sdavidch} 9069179771Sdavidch 9070179771Sdavidch 9071218527Sdavidch/****************************************************************************/ 9072170392Sdavidch/* Provides a sysctl interface to forcing the driver to dump state and */ 9073169271Sdavidch/* enter the debugger. DO NOT ENABLE ON PRODUCTION SYSTEMS! */ 9074169271Sdavidch/* */ 9075169271Sdavidch/* Returns: */ 9076169271Sdavidch/* 0 for success, positive value for failure. */ 9077169271Sdavidch/****************************************************************************/ 9078169271Sdavidchstatic int 9079157642Spsbce_sysctl_breakpoint(SYSCTL_HANDLER_ARGS) 9080157642Sps{ 9081206268Sdavidch int error; 9082206268Sdavidch int result; 9083206268Sdavidch struct bce_softc *sc; 9084157642Sps 9085206268Sdavidch result = -1; 9086206268Sdavidch error = sysctl_handle_int(oidp, &result, 0, req); 9087157642Sps 9088206268Sdavidch if (error || !req->newptr) 9089206268Sdavidch return (error); 9090157642Sps 9091206268Sdavidch if (result == 1) { 9092206268Sdavidch sc = (struct bce_softc *)arg1; 9093206268Sdavidch bce_breakpoint(sc); 9094206268Sdavidch } 9095157642Sps 9096206268Sdavidch return error; 9097157642Sps} 9098157642Sps#endif 9099157642Sps 9100157642Sps/****************************************************************************/ 9101157642Sps/* Adds any sysctl parameters for tuning or debugging purposes. */ 9102157642Sps/* */ 9103157642Sps/* Returns: */ 9104157642Sps/* 0 for success, positive value for failure. */ 9105157642Sps/****************************************************************************/ 9106157642Spsstatic void 9107157642Spsbce_add_sysctls(struct bce_softc *sc) 9108157642Sps{ 9109157642Sps struct sysctl_ctx_list *ctx; 9110157642Sps struct sysctl_oid_list *children; 9111157642Sps 9112179771Sdavidch DBENTER(BCE_VERBOSE_MISC); 9113179771Sdavidch 9114157642Sps ctx = device_get_sysctl_ctx(sc->bce_dev); 9115157642Sps children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bce_dev)); 9116157642Sps 9117157642Sps#ifdef BCE_DEBUG 9118179771Sdavidch SYSCTL_ADD_INT(ctx, children, OID_AUTO, 9119206268Sdavidch "l2fhdr_error_sim_control", 9120206268Sdavidch CTLFLAG_RW, &l2fhdr_error_sim_control, 9121206268Sdavidch 0, "Debug control to force l2fhdr errors"); 9122189325Sdavidch 9123189325Sdavidch SYSCTL_ADD_INT(ctx, children, OID_AUTO, 9124206268Sdavidch "l2fhdr_error_sim_count", 9125206268Sdavidch CTLFLAG_RD, &sc->l2fhdr_error_sim_count, 9126206268Sdavidch 0, "Number of simulated l2_fhdr errors"); 9127189325Sdavidch#endif 9128189325Sdavidch 9129217323Smdf SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9130206268Sdavidch "l2fhdr_error_count", 9131206268Sdavidch CTLFLAG_RD, &sc->l2fhdr_error_count, 9132206268Sdavidch 0, "Number of l2_fhdr errors"); 9133189325Sdavidch 9134189325Sdavidch#ifdef BCE_DEBUG 9135189325Sdavidch SYSCTL_ADD_INT(ctx, children, OID_AUTO, 9136206268Sdavidch "mbuf_alloc_failed_sim_control", 9137206268Sdavidch CTLFLAG_RW, &mbuf_alloc_failed_sim_control, 9138206268Sdavidch 0, "Debug control to force mbuf allocation failures"); 9139189325Sdavidch 9140217323Smdf SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9141206268Sdavidch "mbuf_alloc_failed_sim_count", 9142206268Sdavidch CTLFLAG_RD, &sc->mbuf_alloc_failed_sim_count, 9143206268Sdavidch 0, "Number of simulated mbuf cluster allocation failures"); 9144189325Sdavidch#endif 9145189325Sdavidch 9146217323Smdf SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9147206268Sdavidch "mbuf_alloc_failed_count", 9148206268Sdavidch CTLFLAG_RD, &sc->mbuf_alloc_failed_count, 9149206268Sdavidch 0, "Number of mbuf allocation failures"); 9150189325Sdavidch 9151217323Smdf SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9152207411Sdavidch "mbuf_frag_count", 9153207411Sdavidch CTLFLAG_RD, &sc->mbuf_frag_count, 9154206268Sdavidch 0, "Number of fragmented mbufs"); 9155189325Sdavidch 9156189325Sdavidch#ifdef BCE_DEBUG 9157189325Sdavidch SYSCTL_ADD_INT(ctx, children, OID_AUTO, 9158206268Sdavidch "dma_map_addr_failed_sim_control", 9159206268Sdavidch CTLFLAG_RW, &dma_map_addr_failed_sim_control, 9160206268Sdavidch 0, "Debug control to force DMA mapping failures"); 9161189325Sdavidch 9162189325Sdavidch /* ToDo: Figure out how to update this value in bce_dma_map_addr(). */ 9163217323Smdf SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9164206268Sdavidch "dma_map_addr_failed_sim_count", 9165206268Sdavidch CTLFLAG_RD, &sc->dma_map_addr_failed_sim_count, 9166206268Sdavidch 0, "Number of simulated DMA mapping failures"); 9167207411Sdavidch 9168189325Sdavidch#endif 9169189325Sdavidch 9170217323Smdf SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9171206268Sdavidch "dma_map_addr_rx_failed_count", 9172206268Sdavidch CTLFLAG_RD, &sc->dma_map_addr_rx_failed_count, 9173206268Sdavidch 0, "Number of RX DMA mapping failures"); 9174189325Sdavidch 9175217323Smdf SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9176206268Sdavidch "dma_map_addr_tx_failed_count", 9177206268Sdavidch CTLFLAG_RD, &sc->dma_map_addr_tx_failed_count, 9178206268Sdavidch 0, "Number of TX DMA mapping failures"); 9179189325Sdavidch 9180189325Sdavidch#ifdef BCE_DEBUG 9181189325Sdavidch SYSCTL_ADD_INT(ctx, children, OID_AUTO, 9182206268Sdavidch "unexpected_attention_sim_control", 9183206268Sdavidch CTLFLAG_RW, &unexpected_attention_sim_control, 9184206268Sdavidch 0, "Debug control to simulate unexpected attentions"); 9185189325Sdavidch 9186217323Smdf SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9187206268Sdavidch "unexpected_attention_sim_count", 9188206268Sdavidch CTLFLAG_RW, &sc->unexpected_attention_sim_count, 9189206268Sdavidch 0, "Number of simulated unexpected attentions"); 9190189325Sdavidch#endif 9191189325Sdavidch 9192217323Smdf SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9193206268Sdavidch "unexpected_attention_count", 9194206268Sdavidch CTLFLAG_RW, &sc->unexpected_attention_count, 9195206268Sdavidch 0, "Number of unexpected attentions"); 9196189325Sdavidch 9197189325Sdavidch#ifdef BCE_DEBUG 9198189325Sdavidch SYSCTL_ADD_INT(ctx, children, OID_AUTO, 9199206268Sdavidch "debug_bootcode_running_failure", 9200206268Sdavidch CTLFLAG_RW, &bootcode_running_failure_sim_control, 9201206268Sdavidch 0, "Debug control to force bootcode running failures"); 9202189325Sdavidch 9203189325Sdavidch SYSCTL_ADD_INT(ctx, children, OID_AUTO, 9204206268Sdavidch "rx_low_watermark", 9205206268Sdavidch CTLFLAG_RD, &sc->rx_low_watermark, 9206206268Sdavidch 0, "Lowest level of free rx_bd's"); 9207157642Sps 9208218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9209206268Sdavidch "rx_empty_count", 9210206268Sdavidch CTLFLAG_RD, &sc->rx_empty_count, 9211218423Sdavidch "Number of times the RX chain was empty"); 9212169632Sdavidch 9213179771Sdavidch SYSCTL_ADD_INT(ctx, children, OID_AUTO, 9214206268Sdavidch "tx_hi_watermark", 9215206268Sdavidch CTLFLAG_RD, &sc->tx_hi_watermark, 9216206268Sdavidch 0, "Highest level of used tx_bd's"); 9217157642Sps 9218218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9219206268Sdavidch "tx_full_count", 9220206268Sdavidch CTLFLAG_RD, &sc->tx_full_count, 9221218423Sdavidch "Number of times the TX chain was full"); 9222169632Sdavidch 9223218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9224207411Sdavidch "tso_frames_requested", 9225207411Sdavidch CTLFLAG_RD, &sc->tso_frames_requested, 9226218423Sdavidch "Number of TSO frames requested"); 9227171667Sdavidch 9228218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9229207411Sdavidch "tso_frames_completed", 9230207411Sdavidch CTLFLAG_RD, &sc->tso_frames_completed, 9231218423Sdavidch "Number of TSO frames completed"); 9232207411Sdavidch 9233218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9234207411Sdavidch "tso_frames_failed", 9235207411Sdavidch CTLFLAG_RD, &sc->tso_frames_failed, 9236218423Sdavidch "Number of TSO frames failed"); 9237207411Sdavidch 9238218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9239207411Sdavidch "csum_offload_ip", 9240207411Sdavidch CTLFLAG_RD, &sc->csum_offload_ip, 9241218423Sdavidch "Number of IP checksum offload frames"); 9242207411Sdavidch 9243218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9244207411Sdavidch "csum_offload_tcp_udp", 9245207411Sdavidch CTLFLAG_RD, &sc->csum_offload_tcp_udp, 9246218423Sdavidch "Number of TCP/UDP checksum offload frames"); 9247207411Sdavidch 9248218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9249207411Sdavidch "vlan_tagged_frames_rcvd", 9250207411Sdavidch CTLFLAG_RD, &sc->vlan_tagged_frames_rcvd, 9251218423Sdavidch "Number of VLAN tagged frames received"); 9252207411Sdavidch 9253218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9254207411Sdavidch "vlan_tagged_frames_stripped", 9255207411Sdavidch CTLFLAG_RD, &sc->vlan_tagged_frames_stripped, 9256218423Sdavidch "Number of VLAN tagged frames stripped"); 9257207411Sdavidch 9258218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9259207411Sdavidch "interrupts_rx", 9260207411Sdavidch CTLFLAG_RD, &sc->interrupts_rx, 9261218423Sdavidch "Number of RX interrupts"); 9262171667Sdavidch 9263218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9264207411Sdavidch "interrupts_tx", 9265207411Sdavidch CTLFLAG_RD, &sc->interrupts_tx, 9266218423Sdavidch "Number of TX interrupts"); 9267218423Sdavidch 9268218423Sdavidch if (bce_hdr_split == TRUE) { 9269218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9270218423Sdavidch "split_header_frames_rcvd", 9271218423Sdavidch CTLFLAG_RD, &sc->split_header_frames_rcvd, 9272218423Sdavidch "Number of split header frames received"); 9273218423Sdavidch 9274218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9275218423Sdavidch "split_header_tcp_frames_rcvd", 9276218423Sdavidch CTLFLAG_RD, &sc->split_header_tcp_frames_rcvd, 9277218423Sdavidch "Number of split header TCP frames received"); 9278218423Sdavidch } 9279218423Sdavidch 9280213489Sambrisko SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9281213489Sambrisko "nvram_dump", CTLTYPE_OPAQUE | CTLFLAG_RD, 9282213489Sambrisko (void *)sc, 0, 9283218527Sdavidch bce_sysctl_nvram_dump, "S", ""); 9284218423Sdavidch 9285213489Sambrisko#ifdef BCE_NVRAM_WRITE_SUPPORT 9286213489Sambrisko SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9287213489Sambrisko "nvram_write", CTLTYPE_OPAQUE | CTLFLAG_WR, 9288213489Sambrisko (void *)sc, 0, 9289218527Sdavidch bce_sysctl_nvram_write, "S", ""); 9290179771Sdavidch#endif 9291218423Sdavidch#endif /* BCE_DEBUG */ 9292171667Sdavidch 9293218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9294206268Sdavidch "stat_IfHcInOctets", 9295206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCInOctets, 9296206268Sdavidch "Bytes received"); 9297157642Sps 9298218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9299206268Sdavidch "stat_IfHCInBadOctets", 9300206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCInBadOctets, 9301206268Sdavidch "Bad bytes received"); 9302157642Sps 9303218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9304206268Sdavidch "stat_IfHCOutOctets", 9305206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCOutOctets, 9306206268Sdavidch "Bytes sent"); 9307157642Sps 9308218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9309206268Sdavidch "stat_IfHCOutBadOctets", 9310206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCOutBadOctets, 9311206268Sdavidch "Bad bytes sent"); 9312157642Sps 9313218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9314206268Sdavidch "stat_IfHCInUcastPkts", 9315206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCInUcastPkts, 9316206268Sdavidch "Unicast packets received"); 9317157642Sps 9318218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9319206268Sdavidch "stat_IfHCInMulticastPkts", 9320206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCInMulticastPkts, 9321206268Sdavidch "Multicast packets received"); 9322157642Sps 9323218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9324206268Sdavidch "stat_IfHCInBroadcastPkts", 9325206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCInBroadcastPkts, 9326206268Sdavidch "Broadcast packets received"); 9327157642Sps 9328218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9329206268Sdavidch "stat_IfHCOutUcastPkts", 9330206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCOutUcastPkts, 9331206268Sdavidch "Unicast packets sent"); 9332157642Sps 9333218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9334206268Sdavidch "stat_IfHCOutMulticastPkts", 9335206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCOutMulticastPkts, 9336206268Sdavidch "Multicast packets sent"); 9337157642Sps 9338218423Sdavidch SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, 9339206268Sdavidch "stat_IfHCOutBroadcastPkts", 9340206268Sdavidch CTLFLAG_RD, &sc->stat_IfHCOutBroadcastPkts, 9341206268Sdavidch "Broadcast packets sent"); 9342157642Sps 9343179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9344206268Sdavidch "stat_emac_tx_stat_dot3statsinternalmactransmiterrors", 9345206268Sdavidch CTLFLAG_RD, &sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors, 9346206268Sdavidch 0, "Internal MAC transmit errors"); 9347157642Sps 9348179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9349206268Sdavidch "stat_Dot3StatsCarrierSenseErrors", 9350206268Sdavidch CTLFLAG_RD, &sc->stat_Dot3StatsCarrierSenseErrors, 9351206268Sdavidch 0, "Carrier sense errors"); 9352157642Sps 9353179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9354206268Sdavidch "stat_Dot3StatsFCSErrors", 9355206268Sdavidch CTLFLAG_RD, &sc->stat_Dot3StatsFCSErrors, 9356206268Sdavidch 0, "Frame check sequence errors"); 9357157642Sps 9358179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9359206268Sdavidch "stat_Dot3StatsAlignmentErrors", 9360206268Sdavidch CTLFLAG_RD, &sc->stat_Dot3StatsAlignmentErrors, 9361206268Sdavidch 0, "Alignment errors"); 9362157642Sps 9363179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9364206268Sdavidch "stat_Dot3StatsSingleCollisionFrames", 9365206268Sdavidch CTLFLAG_RD, &sc->stat_Dot3StatsSingleCollisionFrames, 9366206268Sdavidch 0, "Single Collision Frames"); 9367157642Sps 9368179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9369206268Sdavidch "stat_Dot3StatsMultipleCollisionFrames", 9370206268Sdavidch CTLFLAG_RD, &sc->stat_Dot3StatsMultipleCollisionFrames, 9371206268Sdavidch 0, "Multiple Collision Frames"); 9372157642Sps 9373179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9374206268Sdavidch "stat_Dot3StatsDeferredTransmissions", 9375206268Sdavidch CTLFLAG_RD, &sc->stat_Dot3StatsDeferredTransmissions, 9376206268Sdavidch 0, "Deferred Transmissions"); 9377157642Sps 9378179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9379206268Sdavidch "stat_Dot3StatsExcessiveCollisions", 9380206268Sdavidch CTLFLAG_RD, &sc->stat_Dot3StatsExcessiveCollisions, 9381206268Sdavidch 0, "Excessive Collisions"); 9382157642Sps 9383179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9384206268Sdavidch "stat_Dot3StatsLateCollisions", 9385206268Sdavidch CTLFLAG_RD, &sc->stat_Dot3StatsLateCollisions, 9386206268Sdavidch 0, "Late Collisions"); 9387157642Sps 9388179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9389206268Sdavidch "stat_EtherStatsCollisions", 9390206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsCollisions, 9391206268Sdavidch 0, "Collisions"); 9392157642Sps 9393179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9394206268Sdavidch "stat_EtherStatsFragments", 9395206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsFragments, 9396206268Sdavidch 0, "Fragments"); 9397157642Sps 9398179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9399206268Sdavidch "stat_EtherStatsJabbers", 9400206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsJabbers, 9401206268Sdavidch 0, "Jabbers"); 9402157642Sps 9403179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9404206268Sdavidch "stat_EtherStatsUndersizePkts", 9405206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsUndersizePkts, 9406206268Sdavidch 0, "Undersize packets"); 9407157642Sps 9408179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9409206268Sdavidch "stat_EtherStatsOversizePkts", 9410206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsOversizePkts, 9411206268Sdavidch 0, "stat_EtherStatsOversizePkts"); 9412157642Sps 9413179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9414206268Sdavidch "stat_EtherStatsPktsRx64Octets", 9415206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsRx64Octets, 9416206268Sdavidch 0, "Bytes received in 64 byte packets"); 9417157642Sps 9418179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9419206268Sdavidch "stat_EtherStatsPktsRx65Octetsto127Octets", 9420206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsRx65Octetsto127Octets, 9421206268Sdavidch 0, "Bytes received in 65 to 127 byte packets"); 9422157642Sps 9423179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9424206268Sdavidch "stat_EtherStatsPktsRx128Octetsto255Octets", 9425206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsRx128Octetsto255Octets, 9426206268Sdavidch 0, "Bytes received in 128 to 255 byte packets"); 9427157642Sps 9428179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9429206268Sdavidch "stat_EtherStatsPktsRx256Octetsto511Octets", 9430206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsRx256Octetsto511Octets, 9431206268Sdavidch 0, "Bytes received in 256 to 511 byte packets"); 9432157642Sps 9433179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9434206268Sdavidch "stat_EtherStatsPktsRx512Octetsto1023Octets", 9435206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsRx512Octetsto1023Octets, 9436206268Sdavidch 0, "Bytes received in 512 to 1023 byte packets"); 9437157642Sps 9438179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9439206268Sdavidch "stat_EtherStatsPktsRx1024Octetsto1522Octets", 9440206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1024Octetsto1522Octets, 9441206268Sdavidch 0, "Bytes received in 1024 t0 1522 byte packets"); 9442157642Sps 9443179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9444206268Sdavidch "stat_EtherStatsPktsRx1523Octetsto9022Octets", 9445206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1523Octetsto9022Octets, 9446206268Sdavidch 0, "Bytes received in 1523 to 9022 byte packets"); 9447157642Sps 9448179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9449206268Sdavidch "stat_EtherStatsPktsTx64Octets", 9450206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsTx64Octets, 9451206268Sdavidch 0, "Bytes sent in 64 byte packets"); 9452157642Sps 9453179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9454206268Sdavidch "stat_EtherStatsPktsTx65Octetsto127Octets", 9455206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsTx65Octetsto127Octets, 9456206268Sdavidch 0, "Bytes sent in 65 to 127 byte packets"); 9457157642Sps 9458179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9459206268Sdavidch "stat_EtherStatsPktsTx128Octetsto255Octets", 9460206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsTx128Octetsto255Octets, 9461206268Sdavidch 0, "Bytes sent in 128 to 255 byte packets"); 9462157642Sps 9463179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9464206268Sdavidch "stat_EtherStatsPktsTx256Octetsto511Octets", 9465206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsTx256Octetsto511Octets, 9466206268Sdavidch 0, "Bytes sent in 256 to 511 byte packets"); 9467157642Sps 9468179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9469206268Sdavidch "stat_EtherStatsPktsTx512Octetsto1023Octets", 9470206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsTx512Octetsto1023Octets, 9471206268Sdavidch 0, "Bytes sent in 512 to 1023 byte packets"); 9472157642Sps 9473179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9474206268Sdavidch "stat_EtherStatsPktsTx1024Octetsto1522Octets", 9475206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1024Octetsto1522Octets, 9476206268Sdavidch 0, "Bytes sent in 1024 to 1522 byte packets"); 9477157642Sps 9478179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9479206268Sdavidch "stat_EtherStatsPktsTx1523Octetsto9022Octets", 9480206268Sdavidch CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1523Octetsto9022Octets, 9481206268Sdavidch 0, "Bytes sent in 1523 to 9022 byte packets"); 9482157642Sps 9483179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9484206268Sdavidch "stat_XonPauseFramesReceived", 9485206268Sdavidch CTLFLAG_RD, &sc->stat_XonPauseFramesReceived, 9486206268Sdavidch 0, "XON pause frames receved"); 9487157642Sps 9488179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9489206268Sdavidch "stat_XoffPauseFramesReceived", 9490206268Sdavidch CTLFLAG_RD, &sc->stat_XoffPauseFramesReceived, 9491206268Sdavidch 0, "XOFF pause frames received"); 9492157642Sps 9493179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9494206268Sdavidch "stat_OutXonSent", 9495206268Sdavidch CTLFLAG_RD, &sc->stat_OutXonSent, 9496206268Sdavidch 0, "XON pause frames sent"); 9497157642Sps 9498179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9499206268Sdavidch "stat_OutXoffSent", 9500206268Sdavidch CTLFLAG_RD, &sc->stat_OutXoffSent, 9501206268Sdavidch 0, "XOFF pause frames sent"); 9502157642Sps 9503179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9504206268Sdavidch "stat_FlowControlDone", 9505206268Sdavidch CTLFLAG_RD, &sc->stat_FlowControlDone, 9506206268Sdavidch 0, "Flow control done"); 9507157642Sps 9508179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9509206268Sdavidch "stat_MacControlFramesReceived", 9510206268Sdavidch CTLFLAG_RD, &sc->stat_MacControlFramesReceived, 9511206268Sdavidch 0, "MAC control frames received"); 9512157642Sps 9513179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9514206268Sdavidch "stat_XoffStateEntered", 9515206268Sdavidch CTLFLAG_RD, &sc->stat_XoffStateEntered, 9516206268Sdavidch 0, "XOFF state entered"); 9517157642Sps 9518179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9519206268Sdavidch "stat_IfInFramesL2FilterDiscards", 9520206268Sdavidch CTLFLAG_RD, &sc->stat_IfInFramesL2FilterDiscards, 9521206268Sdavidch 0, "Received L2 packets discarded"); 9522157642Sps 9523179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9524206268Sdavidch "stat_IfInRuleCheckerDiscards", 9525206268Sdavidch CTLFLAG_RD, &sc->stat_IfInRuleCheckerDiscards, 9526206268Sdavidch 0, "Received packets discarded by rule"); 9527157642Sps 9528179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9529206268Sdavidch "stat_IfInFTQDiscards", 9530206268Sdavidch CTLFLAG_RD, &sc->stat_IfInFTQDiscards, 9531206268Sdavidch 0, "Received packet FTQ discards"); 9532157642Sps 9533179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9534206268Sdavidch "stat_IfInMBUFDiscards", 9535206268Sdavidch CTLFLAG_RD, &sc->stat_IfInMBUFDiscards, 9536206268Sdavidch 0, "Received packets discarded due to lack " 9537206268Sdavidch "of controller buffer memory"); 9538157642Sps 9539179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9540206268Sdavidch "stat_IfInRuleCheckerP4Hit", 9541206268Sdavidch CTLFLAG_RD, &sc->stat_IfInRuleCheckerP4Hit, 9542206268Sdavidch 0, "Received packets rule checker hits"); 9543157642Sps 9544179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9545206268Sdavidch "stat_CatchupInRuleCheckerDiscards", 9546206268Sdavidch CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerDiscards, 9547206268Sdavidch 0, "Received packets discarded in Catchup path"); 9548157642Sps 9549179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9550206268Sdavidch "stat_CatchupInFTQDiscards", 9551206268Sdavidch CTLFLAG_RD, &sc->stat_CatchupInFTQDiscards, 9552206268Sdavidch 0, "Received packets discarded in FTQ in Catchup path"); 9553157642Sps 9554179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9555206268Sdavidch "stat_CatchupInMBUFDiscards", 9556206268Sdavidch CTLFLAG_RD, &sc->stat_CatchupInMBUFDiscards, 9557206268Sdavidch 0, "Received packets discarded in controller " 9558206268Sdavidch "buffer memory in Catchup path"); 9559157642Sps 9560179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9561206268Sdavidch "stat_CatchupInRuleCheckerP4Hit", 9562206268Sdavidch CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerP4Hit, 9563206268Sdavidch 0, "Received packets rule checker hits in Catchup path"); 9564157642Sps 9565179771Sdavidch SYSCTL_ADD_UINT(ctx, children, OID_AUTO, 9566206268Sdavidch "com_no_buffers", 9567206268Sdavidch CTLFLAG_RD, &sc->com_no_buffers, 9568206268Sdavidch 0, "Valid packets received but no RX buffers available"); 9569169271Sdavidch 9570157642Sps#ifdef BCE_DEBUG 9571157642Sps SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9572206268Sdavidch "driver_state", CTLTYPE_INT | CTLFLAG_RW, 9573206268Sdavidch (void *)sc, 0, 9574206268Sdavidch bce_sysctl_driver_state, "I", "Drive state information"); 9575157642Sps 9576157642Sps SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9577206268Sdavidch "hw_state", CTLTYPE_INT | CTLFLAG_RW, 9578206268Sdavidch (void *)sc, 0, 9579206268Sdavidch bce_sysctl_hw_state, "I", "Hardware state information"); 9580157642Sps 9581157642Sps SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9582206268Sdavidch "status_block", CTLTYPE_INT | CTLFLAG_RW, 9583206268Sdavidch (void *)sc, 0, 9584207411Sdavidch bce_sysctl_status_block, "I", "Dump status block"); 9585170810Sdavidch 9586170810Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9587206268Sdavidch "stats_block", CTLTYPE_INT | CTLFLAG_RW, 9588206268Sdavidch (void *)sc, 0, 9589207411Sdavidch bce_sysctl_stats_block, "I", "Dump statistics block"); 9590157642Sps 9591157642Sps SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9592207411Sdavidch "stats_clear", CTLTYPE_INT | CTLFLAG_RW, 9593207411Sdavidch (void *)sc, 0, 9594207411Sdavidch bce_sysctl_stats_clear, "I", "Clear statistics block"); 9595207411Sdavidch 9596207411Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9597218423Sdavidch "shmem_state", CTLTYPE_INT | CTLFLAG_RW, 9598218423Sdavidch (void *)sc, 0, 9599218423Sdavidch bce_sysctl_shmem_state, "I", "Shared memory state information"); 9600218423Sdavidch 9601218423Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9602206268Sdavidch "bc_state", CTLTYPE_INT | CTLFLAG_RW, 9603206268Sdavidch (void *)sc, 0, 9604206268Sdavidch bce_sysctl_bc_state, "I", "Bootcode state information"); 9605169271Sdavidch 9606206268Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9607206268Sdavidch "dump_rx_bd_chain", CTLTYPE_INT | CTLFLAG_RW, 9608206268Sdavidch (void *)sc, 0, 9609206268Sdavidch bce_sysctl_dump_rx_bd_chain, "I", "Dump RX BD chain"); 9610206268Sdavidch 9611206268Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9612206268Sdavidch "dump_rx_mbuf_chain", CTLTYPE_INT | CTLFLAG_RW, 9613206268Sdavidch (void *)sc, 0, 9614206268Sdavidch bce_sysctl_dump_rx_mbuf_chain, "I", "Dump RX MBUF chain"); 9615206268Sdavidch 9616206268Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9617206268Sdavidch "dump_tx_chain", CTLTYPE_INT | CTLFLAG_RW, 9618206268Sdavidch (void *)sc, 0, 9619206268Sdavidch bce_sysctl_dump_tx_chain, "I", "Dump tx_bd chain"); 9620206268Sdavidch 9621218423Sdavidch if (bce_hdr_split == TRUE) { 9622218423Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9623218423Sdavidch "dump_pg_chain", CTLTYPE_INT | CTLFLAG_RW, 9624218423Sdavidch (void *)sc, 0, 9625218423Sdavidch bce_sysctl_dump_pg_chain, "I", "Dump page chain"); 9626218423Sdavidch } 9627218423Sdavidch 9628169271Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9629206268Sdavidch "dump_ctx", CTLTYPE_INT | CTLFLAG_RW, 9630206268Sdavidch (void *)sc, 0, 9631206268Sdavidch bce_sysctl_dump_ctx, "I", "Dump context memory"); 9632176448Sdavidch 9633176448Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9634206268Sdavidch "breakpoint", CTLTYPE_INT | CTLFLAG_RW, 9635206268Sdavidch (void *)sc, 0, 9636206268Sdavidch bce_sysctl_breakpoint, "I", "Driver breakpoint"); 9637170392Sdavidch 9638179771Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9639206268Sdavidch "reg_read", CTLTYPE_INT | CTLFLAG_RW, 9640206268Sdavidch (void *)sc, 0, 9641206268Sdavidch bce_sysctl_reg_read, "I", "Register read"); 9642169271Sdavidch 9643179771Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9644206268Sdavidch "nvram_read", CTLTYPE_INT | CTLFLAG_RW, 9645206268Sdavidch (void *)sc, 0, 9646206268Sdavidch bce_sysctl_nvram_read, "I", "NVRAM read"); 9647179771Sdavidch 9648179771Sdavidch SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 9649206268Sdavidch "phy_read", CTLTYPE_INT | CTLFLAG_RW, 9650206268Sdavidch (void *)sc, 0, 9651206268Sdavidch bce_sysctl_phy_read, "I", "PHY register read"); 9652169632Sdavidch 9653157642Sps#endif 9654157642Sps 9655179771Sdavidch DBEXIT(BCE_VERBOSE_MISC); 9656157642Sps} 9657157642Sps 9658157642Sps 9659157642Sps/****************************************************************************/ 9660157642Sps/* BCE Debug Routines */ 9661157642Sps/****************************************************************************/ 9662157642Sps#ifdef BCE_DEBUG 9663170392Sdavidch 9664169632Sdavidch/****************************************************************************/ 9665169632Sdavidch/* Freezes the controller to allow for a cohesive state dump. */ 9666169632Sdavidch/* */ 9667169632Sdavidch/* Returns: */ 9668169632Sdavidch/* Nothing. */ 9669169632Sdavidch/****************************************************************************/ 9670205300Sdavidchstatic __attribute__ ((noinline)) void 9671169632Sdavidchbce_freeze_controller(struct bce_softc *sc) 9672169632Sdavidch{ 9673169632Sdavidch u32 val; 9674170392Sdavidch val = REG_RD(sc, BCE_MISC_COMMAND); 9675170392Sdavidch val |= BCE_MISC_COMMAND_DISABLE_ALL; 9676169632Sdavidch REG_WR(sc, BCE_MISC_COMMAND, val); 9677170392Sdavidch} 9678157642Sps 9679170392Sdavidch 9680157642Sps/****************************************************************************/ 9681170392Sdavidch/* Unfreezes the controller after a freeze operation. This may not always */ 9682169632Sdavidch/* work and the controller will require a reset! */ 9683169632Sdavidch/* */ 9684169632Sdavidch/* Returns: */ 9685169632Sdavidch/* Nothing. */ 9686169632Sdavidch/****************************************************************************/ 9687205300Sdavidchstatic __attribute__ ((noinline)) void 9688169632Sdavidchbce_unfreeze_controller(struct bce_softc *sc) 9689169632Sdavidch{ 9690169632Sdavidch u32 val; 9691170392Sdavidch val = REG_RD(sc, BCE_MISC_COMMAND); 9692170392Sdavidch val |= BCE_MISC_COMMAND_ENABLE_ALL; 9693169632Sdavidch REG_WR(sc, BCE_MISC_COMMAND, val); 9694170392Sdavidch} 9695170392Sdavidch 9696182293Sdavidch 9697169632Sdavidch/****************************************************************************/ 9698182293Sdavidch/* Prints out Ethernet frame information from an mbuf. */ 9699182293Sdavidch/* */ 9700182293Sdavidch/* Partially decode an Ethernet frame to look at some important headers. */ 9701182293Sdavidch/* */ 9702182293Sdavidch/* Returns: */ 9703182293Sdavidch/* Nothing. */ 9704182293Sdavidch/****************************************************************************/ 9705205300Sdavidchstatic __attribute__ ((noinline)) void 9706182293Sdavidchbce_dump_enet(struct bce_softc *sc, struct mbuf *m) 9707182293Sdavidch{ 9708182293Sdavidch struct ether_vlan_header *eh; 9709182293Sdavidch u16 etype; 9710182293Sdavidch int ehlen; 9711182293Sdavidch struct ip *ip; 9712182293Sdavidch struct tcphdr *th; 9713182293Sdavidch struct udphdr *uh; 9714182293Sdavidch struct arphdr *ah; 9715182293Sdavidch 9716206268Sdavidch BCE_PRINTF( 9717206268Sdavidch "-----------------------------" 9718206268Sdavidch " Frame Decode " 9719206268Sdavidch "-----------------------------\n"); 9720182293Sdavidch 9721182293Sdavidch eh = mtod(m, struct ether_vlan_header *); 9722182293Sdavidch 9723182293Sdavidch /* Handle VLAN encapsulation if present. */ 9724182293Sdavidch if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 9725182293Sdavidch etype = ntohs(eh->evl_proto); 9726182293Sdavidch ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 9727182293Sdavidch } else { 9728182293Sdavidch etype = ntohs(eh->evl_encap_proto); 9729182293Sdavidch ehlen = ETHER_HDR_LEN; 9730182293Sdavidch } 9731182293Sdavidch 9732182293Sdavidch /* ToDo: Add VLAN output. */ 9733182293Sdavidch BCE_PRINTF("enet: dest = %6D, src = %6D, type = 0x%04X, hlen = %d\n", 9734206268Sdavidch eh->evl_dhost, ":", eh->evl_shost, ":", etype, ehlen); 9735182293Sdavidch 9736182293Sdavidch switch (etype) { 9737206268Sdavidch case ETHERTYPE_IP: 9738206268Sdavidch ip = (struct ip *)(m->m_data + ehlen); 9739206268Sdavidch BCE_PRINTF("--ip: dest = 0x%08X , src = 0x%08X, " 9740206268Sdavidch "len = %d bytes, protocol = 0x%02X, xsum = 0x%04X\n", 9741206268Sdavidch ntohl(ip->ip_dst.s_addr), ntohl(ip->ip_src.s_addr), 9742206268Sdavidch ntohs(ip->ip_len), ip->ip_p, ntohs(ip->ip_sum)); 9743182293Sdavidch 9744206268Sdavidch switch (ip->ip_p) { 9745206268Sdavidch case IPPROTO_TCP: 9746206268Sdavidch th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 9747207411Sdavidch BCE_PRINTF("-tcp: dest = %d, src = %d, hlen = " 9748207411Sdavidch "%d bytes, flags = 0x%b, csum = 0x%04X\n", 9749207411Sdavidch ntohs(th->th_dport), ntohs(th->th_sport), 9750207411Sdavidch (th->th_off << 2), th->th_flags, 9751206268Sdavidch "\20\10CWR\07ECE\06URG\05ACK\04PSH\03RST" 9752206268Sdavidch "\02SYN\01FIN", ntohs(th->th_sum)); 9753182293Sdavidch break; 9754206268Sdavidch case IPPROTO_UDP: 9755206268Sdavidch uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 9756206268Sdavidch BCE_PRINTF("-udp: dest = %d, src = %d, len = %d " 9757207411Sdavidch "bytes, csum = 0x%04X\n", ntohs(uh->uh_dport), 9758207411Sdavidch ntohs(uh->uh_sport), ntohs(uh->uh_ulen), 9759206268Sdavidch ntohs(uh->uh_sum)); 9760182293Sdavidch break; 9761206268Sdavidch case IPPROTO_ICMP: 9762206268Sdavidch BCE_PRINTF("icmp:\n"); 9763206268Sdavidch break; 9764206268Sdavidch default: 9765206268Sdavidch BCE_PRINTF("----: Other IP protocol.\n"); 9766182293Sdavidch } 9767206268Sdavidch break; 9768206268Sdavidch case ETHERTYPE_IPV6: 9769206268Sdavidch BCE_PRINTF("ipv6: No decode supported.\n"); 9770206268Sdavidch break; 9771206268Sdavidch case ETHERTYPE_ARP: 9772206268Sdavidch BCE_PRINTF("-arp: "); 9773206268Sdavidch ah = (struct arphdr *) (m->m_data + ehlen); 9774206268Sdavidch switch (ntohs(ah->ar_op)) { 9775206268Sdavidch case ARPOP_REVREQUEST: 9776206268Sdavidch printf("reverse ARP request\n"); 9777182293Sdavidch break; 9778206268Sdavidch case ARPOP_REVREPLY: 9779206268Sdavidch printf("reverse ARP reply\n"); 9780206268Sdavidch break; 9781206268Sdavidch case ARPOP_REQUEST: 9782206268Sdavidch printf("ARP request\n"); 9783206268Sdavidch break; 9784206268Sdavidch case ARPOP_REPLY: 9785206268Sdavidch printf("ARP reply\n"); 9786206268Sdavidch break; 9787182293Sdavidch default: 9788206268Sdavidch printf("other ARP operation\n"); 9789206268Sdavidch } 9790206268Sdavidch break; 9791206268Sdavidch default: 9792206268Sdavidch BCE_PRINTF("----: Other protocol.\n"); 9793182293Sdavidch } 9794182293Sdavidch 9795182293Sdavidch BCE_PRINTF( 9796182293Sdavidch "-----------------------------" 9797182293Sdavidch "--------------" 9798182293Sdavidch "-----------------------------\n"); 9799182293Sdavidch} 9800182293Sdavidch 9801182293Sdavidch 9802182293Sdavidch/****************************************************************************/ 9803157642Sps/* Prints out information about an mbuf. */ 9804157642Sps/* */ 9805157642Sps/* Returns: */ 9806157642Sps/* Nothing. */ 9807157642Sps/****************************************************************************/ 9808179771Sdavidchstatic __attribute__ ((noinline)) void 9809157642Spsbce_dump_mbuf(struct bce_softc *sc, struct mbuf *m) 9810157642Sps{ 9811157642Sps struct mbuf *mp = m; 9812157642Sps 9813157642Sps if (m == NULL) { 9814169632Sdavidch BCE_PRINTF("mbuf: null pointer\n"); 9815157642Sps return; 9816157642Sps } 9817157642Sps 9818157642Sps while (mp) { 9819206268Sdavidch BCE_PRINTF("mbuf: %p, m_len = %d, m_flags = 0x%b, " 9820206268Sdavidch "m_data = %p\n", mp, mp->m_len, mp->m_flags, 9821206268Sdavidch "\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY", mp->m_data); 9822157642Sps 9823170392Sdavidch if (mp->m_flags & M_PKTHDR) { 9824206268Sdavidch BCE_PRINTF("- m_pkthdr: len = %d, flags = 0x%b, " 9825207411Sdavidch "csum_flags = %b\n", mp->m_pkthdr.len, 9826254516Sandre mp->m_flags, M_FLAG_PRINTF, 9827206268Sdavidch mp->m_pkthdr.csum_flags, 9828243624Sandre "\20\1CSUM_IP\2CSUM_TCP\3CSUM_UDP" 9829206268Sdavidch "\5CSUM_FRAGMENT\6CSUM_TSO\11CSUM_IP_CHECKED" 9830206268Sdavidch "\12CSUM_IP_VALID\13CSUM_DATA_VALID" 9831206268Sdavidch "\14CSUM_PSEUDO_HDR"); 9832170392Sdavidch } 9833169632Sdavidch 9834157642Sps if (mp->m_flags & M_EXT) { 9835179771Sdavidch BCE_PRINTF("- m_ext: %p, ext_size = %d, type = ", 9836206268Sdavidch mp->m_ext.ext_buf, mp->m_ext.ext_size); 9837170392Sdavidch switch (mp->m_ext.ext_type) { 9838206268Sdavidch case EXT_CLUSTER: 9839206268Sdavidch printf("EXT_CLUSTER\n"); break; 9840206268Sdavidch case EXT_SFBUF: 9841206268Sdavidch printf("EXT_SFBUF\n"); break; 9842206268Sdavidch case EXT_JUMBO9: 9843206268Sdavidch printf("EXT_JUMBO9\n"); break; 9844206268Sdavidch case EXT_JUMBO16: 9845206268Sdavidch printf("EXT_JUMBO16\n"); break; 9846206268Sdavidch case EXT_PACKET: 9847206268Sdavidch printf("EXT_PACKET\n"); break; 9848206268Sdavidch case EXT_MBUF: 9849206268Sdavidch printf("EXT_MBUF\n"); break; 9850206268Sdavidch case EXT_NET_DRV: 9851206268Sdavidch printf("EXT_NET_DRV\n"); break; 9852206268Sdavidch case EXT_MOD_TYPE: 9853206268Sdavidch printf("EXT_MDD_TYPE\n"); break; 9854206268Sdavidch case EXT_DISPOSABLE: 9855206268Sdavidch printf("EXT_DISPOSABLE\n"); break; 9856206268Sdavidch case EXT_EXTREF: 9857206268Sdavidch printf("EXT_EXTREF\n"); break; 9858207411Sdavidch default: 9859206268Sdavidch printf("UNKNOWN\n"); 9860170392Sdavidch } 9861157642Sps } 9862157642Sps 9863157642Sps mp = mp->m_next; 9864157642Sps } 9865157642Sps} 9866157642Sps 9867157642Sps 9868157642Sps/****************************************************************************/ 9869157642Sps/* Prints out the mbufs in the TX mbuf chain. */ 9870157642Sps/* */ 9871157642Sps/* Returns: */ 9872157642Sps/* Nothing. */ 9873157642Sps/****************************************************************************/ 9874179771Sdavidchstatic __attribute__ ((noinline)) void 9875176448Sdavidchbce_dump_tx_mbuf_chain(struct bce_softc *sc, u16 chain_prod, int count) 9876157642Sps{ 9877157642Sps struct mbuf *m; 9878157642Sps 9879169271Sdavidch BCE_PRINTF( 9880157642Sps "----------------------------" 9881157642Sps " tx mbuf data " 9882157642Sps "----------------------------\n"); 9883157642Sps 9884157642Sps for (int i = 0; i < count; i++) { 9885157642Sps m = sc->tx_mbuf_ptr[chain_prod]; 9886176448Sdavidch BCE_PRINTF("txmbuf[0x%04X]\n", chain_prod); 9887157642Sps bce_dump_mbuf(sc, m); 9888157642Sps chain_prod = TX_CHAIN_IDX(NEXT_TX_BD(chain_prod)); 9889157642Sps } 9890157642Sps 9891169271Sdavidch BCE_PRINTF( 9892157642Sps "----------------------------" 9893157642Sps "----------------" 9894157642Sps "----------------------------\n"); 9895157642Sps} 9896157642Sps 9897157642Sps 9898169271Sdavidch/****************************************************************************/ 9899169271Sdavidch/* Prints out the mbufs in the RX mbuf chain. */ 9900169271Sdavidch/* */ 9901169271Sdavidch/* Returns: */ 9902169271Sdavidch/* Nothing. */ 9903169271Sdavidch/****************************************************************************/ 9904179771Sdavidchstatic __attribute__ ((noinline)) void 9905176448Sdavidchbce_dump_rx_mbuf_chain(struct bce_softc *sc, u16 chain_prod, int count) 9906157642Sps{ 9907157642Sps struct mbuf *m; 9908157642Sps 9909169271Sdavidch BCE_PRINTF( 9910157642Sps "----------------------------" 9911157642Sps " rx mbuf data " 9912157642Sps "----------------------------\n"); 9913157642Sps 9914157642Sps for (int i = 0; i < count; i++) { 9915157642Sps m = sc->rx_mbuf_ptr[chain_prod]; 9916169271Sdavidch BCE_PRINTF("rxmbuf[0x%04X]\n", chain_prod); 9917157642Sps bce_dump_mbuf(sc, m); 9918157642Sps chain_prod = RX_CHAIN_IDX(NEXT_RX_BD(chain_prod)); 9919157642Sps } 9920157642Sps 9921157642Sps 9922169271Sdavidch BCE_PRINTF( 9923157642Sps "----------------------------" 9924157642Sps "----------------" 9925157642Sps "----------------------------\n"); 9926157642Sps} 9927157642Sps 9928157642Sps 9929169271Sdavidch/****************************************************************************/ 9930176448Sdavidch/* Prints out the mbufs in the mbuf page chain. */ 9931176448Sdavidch/* */ 9932176448Sdavidch/* Returns: */ 9933176448Sdavidch/* Nothing. */ 9934176448Sdavidch/****************************************************************************/ 9935179771Sdavidchstatic __attribute__ ((noinline)) void 9936176448Sdavidchbce_dump_pg_mbuf_chain(struct bce_softc *sc, u16 chain_prod, int count) 9937176448Sdavidch{ 9938176448Sdavidch struct mbuf *m; 9939176448Sdavidch 9940176448Sdavidch BCE_PRINTF( 9941176448Sdavidch "----------------------------" 9942176448Sdavidch " pg mbuf data " 9943176448Sdavidch "----------------------------\n"); 9944176448Sdavidch 9945176448Sdavidch for (int i = 0; i < count; i++) { 9946176448Sdavidch m = sc->pg_mbuf_ptr[chain_prod]; 9947176448Sdavidch BCE_PRINTF("pgmbuf[0x%04X]\n", chain_prod); 9948176448Sdavidch bce_dump_mbuf(sc, m); 9949176448Sdavidch chain_prod = PG_CHAIN_IDX(NEXT_PG_BD(chain_prod)); 9950176448Sdavidch } 9951176448Sdavidch 9952176448Sdavidch 9953176448Sdavidch BCE_PRINTF( 9954176448Sdavidch "----------------------------" 9955176448Sdavidch "----------------" 9956176448Sdavidch "----------------------------\n"); 9957179771Sdavidch} 9958176448Sdavidch 9959176448Sdavidch 9960176448Sdavidch/****************************************************************************/ 9961169271Sdavidch/* Prints out a tx_bd structure. */ 9962169271Sdavidch/* */ 9963169271Sdavidch/* Returns: */ 9964169271Sdavidch/* Nothing. */ 9965169271Sdavidch/****************************************************************************/ 9966179771Sdavidchstatic __attribute__ ((noinline)) void 9967157642Spsbce_dump_txbd(struct bce_softc *sc, int idx, struct tx_bd *txbd) 9968157642Sps{ 9969206268Sdavidch int i = 0; 9970205300Sdavidch 9971218423Sdavidch if (idx > MAX_TX_BD_ALLOC) 9972157642Sps /* Index out of range. */ 9973169271Sdavidch BCE_PRINTF("tx_bd[0x%04X]: Invalid tx_bd index!\n", idx); 9974157642Sps else if ((idx & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE) 9975157642Sps /* TX Chain page pointer. */ 9976206268Sdavidch BCE_PRINTF("tx_bd[0x%04X]: haddr = 0x%08X:%08X, chain page " 9977207411Sdavidch "pointer\n", idx, txbd->tx_bd_haddr_hi, 9978206268Sdavidch txbd->tx_bd_haddr_lo); 9979169271Sdavidch else { 9980205300Sdavidch /* Normal tx_bd entry. */ 9981206268Sdavidch BCE_PRINTF("tx_bd[0x%04X]: haddr = 0x%08X:%08X, " 9982206268Sdavidch "mss_nbytes = 0x%08X, vlan tag = 0x%04X, flags = " 9983207411Sdavidch "0x%04X (", idx, txbd->tx_bd_haddr_hi, 9984207411Sdavidch txbd->tx_bd_haddr_lo, txbd->tx_bd_mss_nbytes, 9985206268Sdavidch txbd->tx_bd_vlan_tag, txbd->tx_bd_flags); 9986170392Sdavidch 9987205300Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_CONN_FAULT) { 9988207411Sdavidch if (i>0) 9989207411Sdavidch printf("|"); 9990207411Sdavidch printf("CONN_FAULT"); 9991206268Sdavidch i++; 9992206268Sdavidch } 9993170392Sdavidch 9994205300Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_TCP_UDP_CKSUM) { 9995207411Sdavidch if (i>0) 9996207411Sdavidch printf("|"); 9997207411Sdavidch printf("TCP_UDP_CKSUM"); 9998206268Sdavidch i++; 9999206268Sdavidch } 10000170392Sdavidch 10001206268Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_IP_CKSUM) { 10002207411Sdavidch if (i>0) 10003207411Sdavidch printf("|"); 10004207411Sdavidch printf("IP_CKSUM"); 10005206268Sdavidch i++; 10006206268Sdavidch } 10007170392Sdavidch 10008205300Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_VLAN_TAG) { 10009207411Sdavidch if (i>0) 10010207411Sdavidch printf("|"); 10011207411Sdavidch printf("VLAN"); 10012206268Sdavidch i++; 10013206268Sdavidch } 10014170392Sdavidch 10015205300Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_COAL_NOW) { 10016207411Sdavidch if (i>0) 10017207411Sdavidch printf("|"); 10018207411Sdavidch printf("COAL_NOW"); 10019206268Sdavidch i++; 10020206268Sdavidch } 10021170392Sdavidch 10022206268Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_DONT_GEN_CRC) { 10023207411Sdavidch if (i>0) 10024207411Sdavidch printf("|"); 10025207411Sdavidch printf("DONT_GEN_CRC"); 10026206268Sdavidch i++; 10027206268Sdavidch } 10028170392Sdavidch 10029206268Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_START) { 10030207411Sdavidch if (i>0) 10031207411Sdavidch printf("|"); 10032207411Sdavidch printf("START"); 10033206268Sdavidch i++; 10034206268Sdavidch } 10035170392Sdavidch 10036205300Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_END) { 10037207411Sdavidch if (i>0) 10038207411Sdavidch printf("|"); 10039207411Sdavidch printf("END"); 10040206268Sdavidch i++; 10041206268Sdavidch } 10042170392Sdavidch 10043205300Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_LSO) { 10044207411Sdavidch if (i>0) 10045207411Sdavidch printf("|"); 10046207411Sdavidch printf("LSO"); 10047206268Sdavidch i++; 10048206268Sdavidch } 10049170392Sdavidch 10050206268Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_OPTION_WORD) { 10051207411Sdavidch if (i>0) 10052207411Sdavidch printf("|"); 10053207411Sdavidch printf("SW_OPTION=%d", ((txbd->tx_bd_flags & 10054206268Sdavidch TX_BD_FLAGS_SW_OPTION_WORD) >> 8)); i++; 10055206268Sdavidch } 10056170392Sdavidch 10057205300Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_FLAGS) { 10058207411Sdavidch if (i>0) 10059207411Sdavidch printf("|"); 10060207411Sdavidch printf("SW_FLAGS"); 10061206268Sdavidch i++; 10062206268Sdavidch } 10063170392Sdavidch 10064205300Sdavidch if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_SNAP) { 10065207411Sdavidch if (i>0) 10066207411Sdavidch printf("|"); 10067206268Sdavidch printf("SNAP)"); 10068206268Sdavidch } else { 10069206268Sdavidch printf(")\n"); 10070206268Sdavidch } 10071206268Sdavidch } 10072157642Sps} 10073157642Sps 10074157642Sps 10075169271Sdavidch/****************************************************************************/ 10076169271Sdavidch/* Prints out a rx_bd structure. */ 10077169271Sdavidch/* */ 10078169271Sdavidch/* Returns: */ 10079169271Sdavidch/* Nothing. */ 10080169271Sdavidch/****************************************************************************/ 10081179771Sdavidchstatic __attribute__ ((noinline)) void 10082157642Spsbce_dump_rxbd(struct bce_softc *sc, int idx, struct rx_bd *rxbd) 10083157642Sps{ 10084218423Sdavidch if (idx > MAX_RX_BD_ALLOC) 10085157642Sps /* Index out of range. */ 10086169271Sdavidch BCE_PRINTF("rx_bd[0x%04X]: Invalid rx_bd index!\n", idx); 10087157642Sps else if ((idx & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE) 10088176448Sdavidch /* RX Chain page pointer. */ 10089206268Sdavidch BCE_PRINTF("rx_bd[0x%04X]: haddr = 0x%08X:%08X, chain page " 10090207411Sdavidch "pointer\n", idx, rxbd->rx_bd_haddr_hi, 10091206268Sdavidch rxbd->rx_bd_haddr_lo); 10092157642Sps else 10093176448Sdavidch /* Normal rx_bd entry. */ 10094206268Sdavidch BCE_PRINTF("rx_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = " 10095207411Sdavidch "0x%08X, flags = 0x%08X\n", idx, rxbd->rx_bd_haddr_hi, 10096207411Sdavidch rxbd->rx_bd_haddr_lo, rxbd->rx_bd_len, 10097206268Sdavidch rxbd->rx_bd_flags); 10098157642Sps} 10099157642Sps 10100157642Sps 10101169271Sdavidch/****************************************************************************/ 10102176448Sdavidch/* Prints out a rx_bd structure in the page chain. */ 10103176448Sdavidch/* */ 10104176448Sdavidch/* Returns: */ 10105176448Sdavidch/* Nothing. */ 10106176448Sdavidch/****************************************************************************/ 10107179771Sdavidchstatic __attribute__ ((noinline)) void 10108176448Sdavidchbce_dump_pgbd(struct bce_softc *sc, int idx, struct rx_bd *pgbd) 10109176448Sdavidch{ 10110218423Sdavidch if (idx > MAX_PG_BD_ALLOC) 10111176448Sdavidch /* Index out of range. */ 10112176448Sdavidch BCE_PRINTF("pg_bd[0x%04X]: Invalid pg_bd index!\n", idx); 10113176448Sdavidch else if ((idx & USABLE_PG_BD_PER_PAGE) == USABLE_PG_BD_PER_PAGE) 10114176448Sdavidch /* Page Chain page pointer. */ 10115179771Sdavidch BCE_PRINTF("px_bd[0x%04X]: haddr = 0x%08X:%08X, chain page pointer\n", 10116176448Sdavidch idx, pgbd->rx_bd_haddr_hi, pgbd->rx_bd_haddr_lo); 10117176448Sdavidch else 10118176448Sdavidch /* Normal rx_bd entry. */ 10119176448Sdavidch BCE_PRINTF("pg_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = 0x%08X, " 10120179771Sdavidch "flags = 0x%08X\n", idx, 10121176448Sdavidch pgbd->rx_bd_haddr_hi, pgbd->rx_bd_haddr_lo, 10122176448Sdavidch pgbd->rx_bd_len, pgbd->rx_bd_flags); 10123179771Sdavidch} 10124176448Sdavidch 10125176448Sdavidch 10126176448Sdavidch/****************************************************************************/ 10127170810Sdavidch/* Prints out a l2_fhdr structure. */ 10128169271Sdavidch/* */ 10129169271Sdavidch/* Returns: */ 10130169271Sdavidch/* Nothing. */ 10131169271Sdavidch/****************************************************************************/ 10132179771Sdavidchstatic __attribute__ ((noinline)) void 10133157642Spsbce_dump_l2fhdr(struct bce_softc *sc, int idx, struct l2_fhdr *l2fhdr) 10134157642Sps{ 10135176448Sdavidch BCE_PRINTF("l2_fhdr[0x%04X]: status = 0x%b, " 10136176448Sdavidch "pkt_len = %d, vlan = 0x%04x, ip_xsum/hdr_len = 0x%04X, " 10137157642Sps "tcp_udp_xsum = 0x%04X\n", idx, 10138179771Sdavidch l2fhdr->l2_fhdr_status, BCE_L2FHDR_PRINTFB, 10139179771Sdavidch l2fhdr->l2_fhdr_pkt_len, l2fhdr->l2_fhdr_vlan_tag, 10140176448Sdavidch l2fhdr->l2_fhdr_ip_xsum, l2fhdr->l2_fhdr_tcp_udp_xsum); 10141157642Sps} 10142157642Sps 10143157642Sps 10144169271Sdavidch/****************************************************************************/ 10145179771Sdavidch/* Prints out context memory info. (Only useful for CID 0 to 16.) */ 10146176448Sdavidch/* */ 10147176448Sdavidch/* Returns: */ 10148176448Sdavidch/* Nothing. */ 10149176448Sdavidch/****************************************************************************/ 10150179771Sdavidchstatic __attribute__ ((noinline)) void 10151176448Sdavidchbce_dump_ctx(struct bce_softc *sc, u16 cid) 10152176448Sdavidch{ 10153206268Sdavidch if (cid > TX_CID) { 10154206268Sdavidch BCE_PRINTF(" Unknown CID\n"); 10155206268Sdavidch return; 10156206268Sdavidch } 10157178132Sdavidch 10158206268Sdavidch BCE_PRINTF( 10159206268Sdavidch "----------------------------" 10160206268Sdavidch " CTX Data " 10161206268Sdavidch "----------------------------\n"); 10162182293Sdavidch 10163206268Sdavidch BCE_PRINTF(" 0x%04X - (CID) Context ID\n", cid); 10164176448Sdavidch 10165206268Sdavidch if (cid == RX_CID) { 10166206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_HOST_BDIDX) host rx " 10167206268Sdavidch "producer index\n", 10168206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_HOST_BDIDX)); 10169206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_HOST_BSEQ) host " 10170206268Sdavidch "byte sequence\n", CTX_RD(sc, GET_CID_ADDR(cid), 10171206268Sdavidch BCE_L2CTX_RX_HOST_BSEQ)); 10172206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BSEQ) h/w byte sequence\n", 10173206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BSEQ)); 10174206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BDHADDR_HI) h/w buffer " 10175206268Sdavidch "descriptor address\n", 10176206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BDHADDR_HI)); 10177206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BDHADDR_LO) h/w buffer " 10178206268Sdavidch "descriptor address\n", 10179206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BDHADDR_LO)); 10180206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BDIDX) h/w rx consumer " 10181206268Sdavidch "index\n", CTX_RD(sc, GET_CID_ADDR(cid), 10182206268Sdavidch BCE_L2CTX_RX_NX_BDIDX)); 10183206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_HOST_PG_BDIDX) host page " 10184207411Sdavidch "producer index\n", CTX_RD(sc, GET_CID_ADDR(cid), 10185206268Sdavidch BCE_L2CTX_RX_HOST_PG_BDIDX)); 10186206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_PG_BUF_SIZE) host rx_bd/page " 10187207411Sdavidch "buffer size\n", CTX_RD(sc, GET_CID_ADDR(cid), 10188206268Sdavidch BCE_L2CTX_RX_PG_BUF_SIZE)); 10189206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_PG_BDHADDR_HI) h/w page " 10190207411Sdavidch "chain address\n", CTX_RD(sc, GET_CID_ADDR(cid), 10191206268Sdavidch BCE_L2CTX_RX_NX_PG_BDHADDR_HI)); 10192206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_PG_BDHADDR_LO) h/w page " 10193207411Sdavidch "chain address\n", CTX_RD(sc, GET_CID_ADDR(cid), 10194206268Sdavidch BCE_L2CTX_RX_NX_PG_BDHADDR_LO)); 10195206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_PG_BDIDX) h/w page " 10196207411Sdavidch "consumer index\n", CTX_RD(sc, GET_CID_ADDR(cid), 10197206268Sdavidch BCE_L2CTX_RX_NX_PG_BDIDX)); 10198206268Sdavidch } else if (cid == TX_CID) { 10199226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 10200206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_TYPE_XI) ctx type\n", 10201207411Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), 10202206268Sdavidch BCE_L2CTX_TX_TYPE_XI)); 10203206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_CMD_TX_TYPE_XI) ctx " 10204207411Sdavidch "cmd\n", CTX_RD(sc, GET_CID_ADDR(cid), 10205206268Sdavidch BCE_L2CTX_TX_CMD_TYPE_XI)); 10206206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BDHADDR_HI_XI) " 10207207411Sdavidch "h/w buffer descriptor address\n", 10208207411Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), 10209206268Sdavidch BCE_L2CTX_TX_TBDR_BHADDR_HI_XI)); 10210206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BHADDR_LO_XI) " 10211207411Sdavidch "h/w buffer descriptor address\n", 10212206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), 10213206268Sdavidch BCE_L2CTX_TX_TBDR_BHADDR_LO_XI)); 10214206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BIDX_XI) " 10215207411Sdavidch "host producer index\n", 10216206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), 10217206268Sdavidch BCE_L2CTX_TX_HOST_BIDX_XI)); 10218206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BSEQ_XI) " 10219207411Sdavidch "host byte sequence\n", 10220206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), 10221206268Sdavidch BCE_L2CTX_TX_HOST_BSEQ_XI)); 10222206268Sdavidch } else { 10223206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_TYPE) ctx type\n", 10224206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_TX_TYPE)); 10225206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_CMD_TYPE) ctx cmd\n", 10226207411Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), 10227206268Sdavidch BCE_L2CTX_TX_CMD_TYPE)); 10228206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BDHADDR_HI) " 10229207411Sdavidch "h/w buffer descriptor address\n", 10230206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), 10231206268Sdavidch BCE_L2CTX_TX_TBDR_BHADDR_HI)); 10232206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BHADDR_LO) " 10233207411Sdavidch "h/w buffer descriptor address\n", 10234206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), 10235206268Sdavidch BCE_L2CTX_TX_TBDR_BHADDR_LO)); 10236206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BIDX) host " 10237206268Sdavidch "producer index\n", CTX_RD(sc, GET_CID_ADDR(cid), 10238206268Sdavidch BCE_L2CTX_TX_HOST_BIDX)); 10239206268Sdavidch BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BSEQ) host byte " 10240206268Sdavidch "sequence\n", CTX_RD(sc, GET_CID_ADDR(cid), 10241206268Sdavidch BCE_L2CTX_TX_HOST_BSEQ)); 10242179771Sdavidch } 10243206268Sdavidch } 10244179771Sdavidch 10245206268Sdavidch BCE_PRINTF( 10246206268Sdavidch "----------------------------" 10247206268Sdavidch " Raw CTX " 10248206268Sdavidch "----------------------------\n"); 10249179771Sdavidch 10250206268Sdavidch for (int i = 0x0; i < 0x300; i += 0x10) { 10251206268Sdavidch BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n", i, 10252206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), i), 10253206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), i + 0x4), 10254206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), i + 0x8), 10255206268Sdavidch CTX_RD(sc, GET_CID_ADDR(cid), i + 0xc)); 10256176448Sdavidch } 10257206268Sdavidch 10258206268Sdavidch 10259206268Sdavidch BCE_PRINTF( 10260206268Sdavidch "----------------------------" 10261206268Sdavidch "----------------" 10262206268Sdavidch "----------------------------\n"); 10263176448Sdavidch} 10264176448Sdavidch 10265176448Sdavidch 10266176448Sdavidch/****************************************************************************/ 10267176448Sdavidch/* Prints out the FTQ data. */ 10268176448Sdavidch/* */ 10269176448Sdavidch/* Returns: */ 10270176448Sdavidch/* Nothing. */ 10271176448Sdavidch/****************************************************************************/ 10272179771Sdavidchstatic __attribute__ ((noinline)) void 10273176448Sdavidchbce_dump_ftqs(struct bce_softc *sc) 10274178132Sdavidch{ 10275179771Sdavidch u32 cmd, ctl, cur_depth, max_depth, valid_cnt, val; 10276176448Sdavidch 10277176448Sdavidch BCE_PRINTF( 10278206268Sdavidch "----------------------------" 10279206268Sdavidch " FTQ Data " 10280206268Sdavidch "----------------------------\n"); 10281176448Sdavidch 10282206268Sdavidch BCE_PRINTF(" FTQ Command Control Depth_Now " 10283206268Sdavidch "Max_Depth Valid_Cnt \n"); 10284206268Sdavidch BCE_PRINTF(" ------- ---------- ---------- ---------- " 10285206268Sdavidch "---------- ----------\n"); 10286178132Sdavidch 10287178132Sdavidch /* Setup the generic statistic counters for the FTQ valid count. */ 10288179771Sdavidch val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PPQ_VALID_CNT << 24) | 10289206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPCQ_VALID_CNT << 16) | 10290206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPQ_VALID_CNT << 8) | 10291206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RLUPQ_VALID_CNT); 10292179771Sdavidch REG_WR(sc, BCE_HC_STAT_GEN_SEL_0, val); 10293182293Sdavidch 10294179771Sdavidch val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TSCHQ_VALID_CNT << 24) | 10295206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RDMAQ_VALID_CNT << 16) | 10296206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PTQ_VALID_CNT << 8) | 10297206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PMQ_VALID_CNT); 10298179771Sdavidch REG_WR(sc, BCE_HC_STAT_GEN_SEL_1, val); 10299182293Sdavidch 10300179771Sdavidch val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPATQ_VALID_CNT << 24) | 10301206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TDMAQ_VALID_CNT << 16) | 10302206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXPQ_VALID_CNT << 8) | 10303206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TBDRQ_VALID_CNT); 10304179771Sdavidch REG_WR(sc, BCE_HC_STAT_GEN_SEL_2, val); 10305182293Sdavidch 10306179771Sdavidch val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMQ_VALID_CNT << 24) | 10307206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMTQ_VALID_CNT << 16) | 10308206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMXQ_VALID_CNT << 8) | 10309206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TASQ_VALID_CNT); 10310179771Sdavidch REG_WR(sc, BCE_HC_STAT_GEN_SEL_3, val); 10311178132Sdavidch 10312182293Sdavidch /* Input queue to the Receive Lookup state machine */ 10313178132Sdavidch cmd = REG_RD(sc, BCE_RLUP_FTQ_CMD); 10314178132Sdavidch ctl = REG_RD(sc, BCE_RLUP_FTQ_CTL); 10315178132Sdavidch cur_depth = (ctl & BCE_RLUP_FTQ_CTL_CUR_DEPTH) >> 22; 10316178132Sdavidch max_depth = (ctl & BCE_RLUP_FTQ_CTL_MAX_DEPTH) >> 12; 10317178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT0); 10318179771Sdavidch BCE_PRINTF(" RLUP 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10319206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10320178132Sdavidch 10321182293Sdavidch /* Input queue to the Receive Processor */ 10322178132Sdavidch cmd = REG_RD_IND(sc, BCE_RXP_FTQ_CMD); 10323178132Sdavidch ctl = REG_RD_IND(sc, BCE_RXP_FTQ_CTL); 10324178132Sdavidch cur_depth = (ctl & BCE_RXP_FTQ_CTL_CUR_DEPTH) >> 22; 10325178132Sdavidch max_depth = (ctl & BCE_RXP_FTQ_CTL_MAX_DEPTH) >> 12; 10326178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT1); 10327179771Sdavidch BCE_PRINTF(" RXP 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10328206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10329178132Sdavidch 10330182293Sdavidch /* Input queue to the Recevie Processor */ 10331178132Sdavidch cmd = REG_RD_IND(sc, BCE_RXP_CFTQ_CMD); 10332178132Sdavidch ctl = REG_RD_IND(sc, BCE_RXP_CFTQ_CTL); 10333178132Sdavidch cur_depth = (ctl & BCE_RXP_CFTQ_CTL_CUR_DEPTH) >> 22; 10334178132Sdavidch max_depth = (ctl & BCE_RXP_CFTQ_CTL_MAX_DEPTH) >> 12; 10335178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT2); 10336179771Sdavidch BCE_PRINTF(" RXPC 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10337206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10338178132Sdavidch 10339182293Sdavidch /* Input queue to the Receive Virtual to Physical state machine */ 10340178132Sdavidch cmd = REG_RD(sc, BCE_RV2P_PFTQ_CMD); 10341178132Sdavidch ctl = REG_RD(sc, BCE_RV2P_PFTQ_CTL); 10342178132Sdavidch cur_depth = (ctl & BCE_RV2P_PFTQ_CTL_CUR_DEPTH) >> 22; 10343178132Sdavidch max_depth = (ctl & BCE_RV2P_PFTQ_CTL_MAX_DEPTH) >> 12; 10344178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT3); 10345179771Sdavidch BCE_PRINTF(" RV2PP 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10346206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10347178132Sdavidch 10348182293Sdavidch /* Input queue to the Recevie Virtual to Physical state machine */ 10349178132Sdavidch cmd = REG_RD(sc, BCE_RV2P_MFTQ_CMD); 10350178132Sdavidch ctl = REG_RD(sc, BCE_RV2P_MFTQ_CTL); 10351178132Sdavidch cur_depth = (ctl & BCE_RV2P_MFTQ_CTL_CUR_DEPTH) >> 22; 10352178132Sdavidch max_depth = (ctl & BCE_RV2P_MFTQ_CTL_MAX_DEPTH) >> 12; 10353178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT4); 10354179771Sdavidch BCE_PRINTF(" RV2PM 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10355206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10356178132Sdavidch 10357182293Sdavidch /* Input queue to the Receive Virtual to Physical state machine */ 10358178132Sdavidch cmd = REG_RD(sc, BCE_RV2P_TFTQ_CMD); 10359178132Sdavidch ctl = REG_RD(sc, BCE_RV2P_TFTQ_CTL); 10360178132Sdavidch cur_depth = (ctl & BCE_RV2P_TFTQ_CTL_CUR_DEPTH) >> 22; 10361178132Sdavidch max_depth = (ctl & BCE_RV2P_TFTQ_CTL_MAX_DEPTH) >> 12; 10362178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT5); 10363179771Sdavidch BCE_PRINTF(" RV2PT 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10364206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10365178132Sdavidch 10366182293Sdavidch /* Input queue to the Receive DMA state machine */ 10367178132Sdavidch cmd = REG_RD(sc, BCE_RDMA_FTQ_CMD); 10368178132Sdavidch ctl = REG_RD(sc, BCE_RDMA_FTQ_CTL); 10369178132Sdavidch cur_depth = (ctl & BCE_RDMA_FTQ_CTL_CUR_DEPTH) >> 22; 10370178132Sdavidch max_depth = (ctl & BCE_RDMA_FTQ_CTL_MAX_DEPTH) >> 12; 10371178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT6); 10372179771Sdavidch BCE_PRINTF(" RDMA 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10373206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10374178132Sdavidch 10375182293Sdavidch /* Input queue to the Transmit Scheduler state machine */ 10376178132Sdavidch cmd = REG_RD(sc, BCE_TSCH_FTQ_CMD); 10377178132Sdavidch ctl = REG_RD(sc, BCE_TSCH_FTQ_CTL); 10378178132Sdavidch cur_depth = (ctl & BCE_TSCH_FTQ_CTL_CUR_DEPTH) >> 22; 10379178132Sdavidch max_depth = (ctl & BCE_TSCH_FTQ_CTL_MAX_DEPTH) >> 12; 10380178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT7); 10381179771Sdavidch BCE_PRINTF(" TSCH 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10382206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10383178132Sdavidch 10384182293Sdavidch /* Input queue to the Transmit Buffer Descriptor state machine */ 10385178132Sdavidch cmd = REG_RD(sc, BCE_TBDR_FTQ_CMD); 10386178132Sdavidch ctl = REG_RD(sc, BCE_TBDR_FTQ_CTL); 10387178132Sdavidch cur_depth = (ctl & BCE_TBDR_FTQ_CTL_CUR_DEPTH) >> 22; 10388178132Sdavidch max_depth = (ctl & BCE_TBDR_FTQ_CTL_MAX_DEPTH) >> 12; 10389178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT8); 10390179771Sdavidch BCE_PRINTF(" TBDR 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10391206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10392178132Sdavidch 10393182293Sdavidch /* Input queue to the Transmit Processor */ 10394178132Sdavidch cmd = REG_RD_IND(sc, BCE_TXP_FTQ_CMD); 10395178132Sdavidch ctl = REG_RD_IND(sc, BCE_TXP_FTQ_CTL); 10396178132Sdavidch cur_depth = (ctl & BCE_TXP_FTQ_CTL_CUR_DEPTH) >> 22; 10397178132Sdavidch max_depth = (ctl & BCE_TXP_FTQ_CTL_MAX_DEPTH) >> 12; 10398178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT9); 10399179771Sdavidch BCE_PRINTF(" TXP 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10400206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10401178132Sdavidch 10402182293Sdavidch /* Input queue to the Transmit DMA state machine */ 10403178132Sdavidch cmd = REG_RD(sc, BCE_TDMA_FTQ_CMD); 10404178132Sdavidch ctl = REG_RD(sc, BCE_TDMA_FTQ_CTL); 10405178132Sdavidch cur_depth = (ctl & BCE_TDMA_FTQ_CTL_CUR_DEPTH) >> 22; 10406178132Sdavidch max_depth = (ctl & BCE_TDMA_FTQ_CTL_MAX_DEPTH) >> 12; 10407178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT10); 10408179771Sdavidch BCE_PRINTF(" TDMA 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10409206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10410178132Sdavidch 10411182293Sdavidch /* Input queue to the Transmit Patch-Up Processor */ 10412178132Sdavidch cmd = REG_RD_IND(sc, BCE_TPAT_FTQ_CMD); 10413178132Sdavidch ctl = REG_RD_IND(sc, BCE_TPAT_FTQ_CTL); 10414178132Sdavidch cur_depth = (ctl & BCE_TPAT_FTQ_CTL_CUR_DEPTH) >> 22; 10415178132Sdavidch max_depth = (ctl & BCE_TPAT_FTQ_CTL_MAX_DEPTH) >> 12; 10416178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT11); 10417179771Sdavidch BCE_PRINTF(" TPAT 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10418206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10419178132Sdavidch 10420182293Sdavidch /* Input queue to the Transmit Assembler state machine */ 10421178132Sdavidch cmd = REG_RD_IND(sc, BCE_TAS_FTQ_CMD); 10422178132Sdavidch ctl = REG_RD_IND(sc, BCE_TAS_FTQ_CTL); 10423178132Sdavidch cur_depth = (ctl & BCE_TAS_FTQ_CTL_CUR_DEPTH) >> 22; 10424178132Sdavidch max_depth = (ctl & BCE_TAS_FTQ_CTL_MAX_DEPTH) >> 12; 10425178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT12); 10426179771Sdavidch BCE_PRINTF(" TAS 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10427206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10428178132Sdavidch 10429182293Sdavidch /* Input queue to the Completion Processor */ 10430178132Sdavidch cmd = REG_RD_IND(sc, BCE_COM_COMXQ_FTQ_CMD); 10431178132Sdavidch ctl = REG_RD_IND(sc, BCE_COM_COMXQ_FTQ_CTL); 10432178132Sdavidch cur_depth = (ctl & BCE_COM_COMXQ_FTQ_CTL_CUR_DEPTH) >> 22; 10433178132Sdavidch max_depth = (ctl & BCE_COM_COMXQ_FTQ_CTL_MAX_DEPTH) >> 12; 10434178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT13); 10435179771Sdavidch BCE_PRINTF(" COMX 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10436206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10437178132Sdavidch 10438182293Sdavidch /* Input queue to the Completion Processor */ 10439178132Sdavidch cmd = REG_RD_IND(sc, BCE_COM_COMTQ_FTQ_CMD); 10440178132Sdavidch ctl = REG_RD_IND(sc, BCE_COM_COMTQ_FTQ_CTL); 10441178132Sdavidch cur_depth = (ctl & BCE_COM_COMTQ_FTQ_CTL_CUR_DEPTH) >> 22; 10442178132Sdavidch max_depth = (ctl & BCE_COM_COMTQ_FTQ_CTL_MAX_DEPTH) >> 12; 10443178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT14); 10444179771Sdavidch BCE_PRINTF(" COMT 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10445206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10446178132Sdavidch 10447182293Sdavidch /* Input queue to the Completion Processor */ 10448178132Sdavidch cmd = REG_RD_IND(sc, BCE_COM_COMQ_FTQ_CMD); 10449178132Sdavidch ctl = REG_RD_IND(sc, BCE_COM_COMQ_FTQ_CTL); 10450178132Sdavidch cur_depth = (ctl & BCE_COM_COMQ_FTQ_CTL_CUR_DEPTH) >> 22; 10451178132Sdavidch max_depth = (ctl & BCE_COM_COMQ_FTQ_CTL_MAX_DEPTH) >> 12; 10452178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT15); 10453179771Sdavidch BCE_PRINTF(" COMX 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10454206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10455178132Sdavidch 10456178132Sdavidch /* Setup the generic statistic counters for the FTQ valid count. */ 10457179771Sdavidch val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_CSQ_VALID_CNT << 16) | 10458206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_CPQ_VALID_CNT << 8) | 10459206268Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_MGMQ_VALID_CNT); 10460182293Sdavidch 10461239110Sdavide if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) 10462207411Sdavidch val = val | 10463207411Sdavidch (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PCSQ_VALID_CNT_XI << 10464206268Sdavidch 24); 10465206268Sdavidch REG_WR(sc, BCE_HC_STAT_GEN_SEL_0, val); 10466182293Sdavidch 10467182293Sdavidch /* Input queue to the Management Control Processor */ 10468178132Sdavidch cmd = REG_RD_IND(sc, BCE_MCP_MCPQ_FTQ_CMD); 10469178132Sdavidch ctl = REG_RD_IND(sc, BCE_MCP_MCPQ_FTQ_CTL); 10470178132Sdavidch cur_depth = (ctl & BCE_MCP_MCPQ_FTQ_CTL_CUR_DEPTH) >> 22; 10471178132Sdavidch max_depth = (ctl & BCE_MCP_MCPQ_FTQ_CTL_MAX_DEPTH) >> 12; 10472178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT0); 10473179771Sdavidch BCE_PRINTF(" MCP 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10474206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10475178132Sdavidch 10476182293Sdavidch /* Input queue to the Command Processor */ 10477178132Sdavidch cmd = REG_RD_IND(sc, BCE_CP_CPQ_FTQ_CMD); 10478178132Sdavidch ctl = REG_RD_IND(sc, BCE_CP_CPQ_FTQ_CTL); 10479178132Sdavidch cur_depth = (ctl & BCE_CP_CPQ_FTQ_CTL_CUR_DEPTH) >> 22; 10480178132Sdavidch max_depth = (ctl & BCE_CP_CPQ_FTQ_CTL_MAX_DEPTH) >> 12; 10481178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT1); 10482179771Sdavidch BCE_PRINTF(" CP 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10483206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10484178132Sdavidch 10485182293Sdavidch /* Input queue to the Completion Scheduler state machine */ 10486178132Sdavidch cmd = REG_RD(sc, BCE_CSCH_CH_FTQ_CMD); 10487178132Sdavidch ctl = REG_RD(sc, BCE_CSCH_CH_FTQ_CTL); 10488178132Sdavidch cur_depth = (ctl & BCE_CSCH_CH_FTQ_CTL_CUR_DEPTH) >> 22; 10489178132Sdavidch max_depth = (ctl & BCE_CSCH_CH_FTQ_CTL_MAX_DEPTH) >> 12; 10490178132Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT2); 10491179771Sdavidch BCE_PRINTF(" CS 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10492206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10493178132Sdavidch 10494226123Syongari if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { 10495206268Sdavidch /* Input queue to the RV2P Command Scheduler */ 10496179771Sdavidch cmd = REG_RD(sc, BCE_RV2PCSR_FTQ_CMD); 10497179771Sdavidch ctl = REG_RD(sc, BCE_RV2PCSR_FTQ_CTL); 10498179771Sdavidch cur_depth = (ctl & 0xFFC00000) >> 22; 10499179771Sdavidch max_depth = (ctl & 0x003FF000) >> 12; 10500179771Sdavidch valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT3); 10501179771Sdavidch BCE_PRINTF(" RV2PCSR 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", 10502206268Sdavidch cmd, ctl, cur_depth, max_depth, valid_cnt); 10503179771Sdavidch } 10504182293Sdavidch 10505176448Sdavidch BCE_PRINTF( 10506206268Sdavidch "----------------------------" 10507206268Sdavidch "----------------" 10508206268Sdavidch "----------------------------\n"); 10509176448Sdavidch} 10510176448Sdavidch 10511176448Sdavidch 10512176448Sdavidch/****************************************************************************/ 10513170810Sdavidch/* Prints out the TX chain. */ 10514169271Sdavidch/* */ 10515169271Sdavidch/* Returns: */ 10516169271Sdavidch/* Nothing. */ 10517169271Sdavidch/****************************************************************************/ 10518179771Sdavidchstatic __attribute__ ((noinline)) void 10519176448Sdavidchbce_dump_tx_chain(struct bce_softc *sc, u16 tx_prod, int count) 10520157642Sps{ 10521157642Sps struct tx_bd *txbd; 10522157642Sps 10523157642Sps /* First some info about the tx_bd chain structure. */ 10524169271Sdavidch BCE_PRINTF( 10525206268Sdavidch "----------------------------" 10526206268Sdavidch " tx_bd chain " 10527206268Sdavidch "----------------------------\n"); 10528157642Sps 10529169271Sdavidch BCE_PRINTF("page size = 0x%08X, tx chain pages = 0x%08X\n", 10530218423Sdavidch (u32) BCM_PAGE_SIZE, (u32) sc->tx_pages); 10531169271Sdavidch BCE_PRINTF("tx_bd per page = 0x%08X, usable tx_bd per page = 0x%08X\n", 10532206268Sdavidch (u32) TOTAL_TX_BD_PER_PAGE, (u32) USABLE_TX_BD_PER_PAGE); 10533218423Sdavidch BCE_PRINTF("total tx_bd = 0x%08X\n", (u32) TOTAL_TX_BD_ALLOC); 10534157642Sps 10535170810Sdavidch BCE_PRINTF( 10536206268Sdavidch "----------------------------" 10537206268Sdavidch " tx_bd data " 10538206268Sdavidch "----------------------------\n"); 10539157642Sps 10540205300Sdavidch /* Now print out a decoded list of TX buffer descriptors. */ 10541157642Sps for (int i = 0; i < count; i++) { 10542157642Sps txbd = &sc->tx_bd_chain[TX_PAGE(tx_prod)][TX_IDX(tx_prod)]; 10543157642Sps bce_dump_txbd(sc, tx_prod, txbd); 10544205300Sdavidch tx_prod++; 10545157642Sps } 10546157642Sps 10547169271Sdavidch BCE_PRINTF( 10548206268Sdavidch "----------------------------" 10549206268Sdavidch "----------------" 10550206268Sdavidch "----------------------------\n"); 10551157642Sps} 10552157642Sps 10553157642Sps 10554169271Sdavidch/****************************************************************************/ 10555170810Sdavidch/* Prints out the RX chain. */ 10556169271Sdavidch/* */ 10557169271Sdavidch/* Returns: */ 10558169271Sdavidch/* Nothing. */ 10559169271Sdavidch/****************************************************************************/ 10560179771Sdavidchstatic __attribute__ ((noinline)) void 10561206268Sdavidchbce_dump_rx_bd_chain(struct bce_softc *sc, u16 rx_prod, int count) 10562157642Sps{ 10563157642Sps struct rx_bd *rxbd; 10564157642Sps 10565176448Sdavidch /* First some info about the rx_bd chain structure. */ 10566169271Sdavidch BCE_PRINTF( 10567206268Sdavidch "----------------------------" 10568206268Sdavidch " rx_bd chain " 10569206268Sdavidch "----------------------------\n"); 10570157642Sps 10571169271Sdavidch BCE_PRINTF("page size = 0x%08X, rx chain pages = 0x%08X\n", 10572218423Sdavidch (u32) BCM_PAGE_SIZE, (u32) sc->rx_pages); 10573157642Sps 10574169271Sdavidch BCE_PRINTF("rx_bd per page = 0x%08X, usable rx_bd per page = 0x%08X\n", 10575206268Sdavidch (u32) TOTAL_RX_BD_PER_PAGE, (u32) USABLE_RX_BD_PER_PAGE); 10576157642Sps 10577218423Sdavidch BCE_PRINTF("total rx_bd = 0x%08X\n", (u32) TOTAL_RX_BD_ALLOC); 10578157642Sps 10579169271Sdavidch BCE_PRINTF( 10580206268Sdavidch "----------------------------" 10581206268Sdavidch " rx_bd data " 10582206268Sdavidch "----------------------------\n"); 10583157642Sps 10584157642Sps /* Now print out the rx_bd's themselves. */ 10585157642Sps for (int i = 0; i < count; i++) { 10586157642Sps rxbd = &sc->rx_bd_chain[RX_PAGE(rx_prod)][RX_IDX(rx_prod)]; 10587157642Sps bce_dump_rxbd(sc, rx_prod, rxbd); 10588176448Sdavidch rx_prod = RX_CHAIN_IDX(rx_prod + 1); 10589157642Sps } 10590157642Sps 10591169271Sdavidch BCE_PRINTF( 10592206268Sdavidch "----------------------------" 10593206268Sdavidch "----------------" 10594206268Sdavidch "----------------------------\n"); 10595157642Sps} 10596157642Sps 10597157642Sps 10598169271Sdavidch/****************************************************************************/ 10599176448Sdavidch/* Prints out the page chain. */ 10600176448Sdavidch/* */ 10601176448Sdavidch/* Returns: */ 10602176448Sdavidch/* Nothing. */ 10603176448Sdavidch/****************************************************************************/ 10604179771Sdavidchstatic __attribute__ ((noinline)) void 10605176448Sdavidchbce_dump_pg_chain(struct bce_softc *sc, u16 pg_prod, int count) 10606176448Sdavidch{ 10607176448Sdavidch struct rx_bd *pgbd; 10608176448Sdavidch 10609176448Sdavidch /* First some info about the page chain structure. */ 10610176448Sdavidch BCE_PRINTF( 10611206268Sdavidch "----------------------------" 10612206268Sdavidch " page chain " 10613206268Sdavidch "----------------------------\n"); 10614176448Sdavidch 10615176448Sdavidch BCE_PRINTF("page size = 0x%08X, pg chain pages = 0x%08X\n", 10616218423Sdavidch (u32) BCM_PAGE_SIZE, (u32) sc->pg_pages); 10617176448Sdavidch 10618176448Sdavidch BCE_PRINTF("rx_bd per page = 0x%08X, usable rx_bd per page = 0x%08X\n", 10619206268Sdavidch (u32) TOTAL_PG_BD_PER_PAGE, (u32) USABLE_PG_BD_PER_PAGE); 10620176448Sdavidch 10621218423Sdavidch BCE_PRINTF("total pg_bd = 0x%08X\n", (u32) TOTAL_PG_BD_ALLOC); 10622176448Sdavidch 10623176448Sdavidch BCE_PRINTF( 10624206268Sdavidch "----------------------------" 10625206268Sdavidch " page data " 10626206268Sdavidch "----------------------------\n"); 10627176448Sdavidch 10628176448Sdavidch /* Now print out the rx_bd's themselves. */ 10629176448Sdavidch for (int i = 0; i < count; i++) { 10630178132Sdavidch pgbd = &sc->pg_bd_chain[PG_PAGE(pg_prod)][PG_IDX(pg_prod)]; 10631176448Sdavidch bce_dump_pgbd(sc, pg_prod, pgbd); 10632176448Sdavidch pg_prod = PG_CHAIN_IDX(pg_prod + 1); 10633176448Sdavidch } 10634176448Sdavidch 10635176448Sdavidch BCE_PRINTF( 10636206268Sdavidch "----------------------------" 10637206268Sdavidch "----------------" 10638206268Sdavidch "----------------------------\n"); 10639179771Sdavidch} 10640176448Sdavidch 10641176448Sdavidch 10642206268Sdavidch#define BCE_PRINT_RX_CONS(arg) \ 10643206268Sdavidchif (sblk->status_rx_quick_consumer_index##arg) \ 10644206268Sdavidch BCE_PRINTF("0x%04X(0x%04X) - rx_quick_consumer_index%d\n", \ 10645206268Sdavidch sblk->status_rx_quick_consumer_index##arg, (u16) \ 10646206268Sdavidch RX_CHAIN_IDX(sblk->status_rx_quick_consumer_index##arg), \ 10647206268Sdavidch arg); 10648205300Sdavidch 10649206268Sdavidch 10650206268Sdavidch#define BCE_PRINT_TX_CONS(arg) \ 10651206268Sdavidchif (sblk->status_tx_quick_consumer_index##arg) \ 10652206268Sdavidch BCE_PRINTF("0x%04X(0x%04X) - tx_quick_consumer_index%d\n", \ 10653206268Sdavidch sblk->status_tx_quick_consumer_index##arg, (u16) \ 10654206268Sdavidch TX_CHAIN_IDX(sblk->status_tx_quick_consumer_index##arg), \ 10655206268Sdavidch arg); 10656206268Sdavidch 10657176448Sdavidch/****************************************************************************/ 10658169271Sdavidch/* Prints out the status block from host memory. */ 10659169271Sdavidch/* */ 10660169271Sdavidch/* Returns: */ 10661169271Sdavidch/* Nothing. */ 10662169271Sdavidch/****************************************************************************/ 10663179771Sdavidchstatic __attribute__ ((noinline)) void 10664157642Spsbce_dump_status_block(struct bce_softc *sc) 10665157642Sps{ 10666157642Sps struct status_block *sblk; 10667157642Sps 10668251159Smarius bus_dmamap_sync(sc->status_tag, sc->status_map, BUS_DMASYNC_POSTREAD); 10669251159Smarius 10670157642Sps sblk = sc->status_block; 10671157642Sps 10672206268Sdavidch BCE_PRINTF( 10673206268Sdavidch "----------------------------" 10674206268Sdavidch " Status Block " 10675206268Sdavidch "----------------------------\n"); 10676170392Sdavidch 10677206268Sdavidch /* Theses indices are used for normal L2 drivers. */ 10678169632Sdavidch BCE_PRINTF(" 0x%08X - attn_bits\n", 10679206268Sdavidch sblk->status_attn_bits); 10680157642Sps 10681169632Sdavidch BCE_PRINTF(" 0x%08X - attn_bits_ack\n", 10682206268Sdavidch sblk->status_attn_bits_ack); 10683157642Sps 10684206268Sdavidch BCE_PRINT_RX_CONS(0); 10685206268Sdavidch BCE_PRINT_TX_CONS(0) 10686170392Sdavidch 10687169632Sdavidch BCE_PRINTF(" 0x%04X - status_idx\n", sblk->status_idx); 10688169632Sdavidch 10689157642Sps /* Theses indices are not used for normal L2 drivers. */ 10690206268Sdavidch BCE_PRINT_RX_CONS(1); BCE_PRINT_RX_CONS(2); BCE_PRINT_RX_CONS(3); 10691206268Sdavidch BCE_PRINT_RX_CONS(4); BCE_PRINT_RX_CONS(5); BCE_PRINT_RX_CONS(6); 10692206268Sdavidch BCE_PRINT_RX_CONS(7); BCE_PRINT_RX_CONS(8); BCE_PRINT_RX_CONS(9); 10693206268Sdavidch BCE_PRINT_RX_CONS(10); BCE_PRINT_RX_CONS(11); BCE_PRINT_RX_CONS(12); 10694206268Sdavidch BCE_PRINT_RX_CONS(13); BCE_PRINT_RX_CONS(14); BCE_PRINT_RX_CONS(15); 10695170392Sdavidch 10696206268Sdavidch BCE_PRINT_TX_CONS(1); BCE_PRINT_TX_CONS(2); BCE_PRINT_TX_CONS(3); 10697157642Sps 10698206268Sdavidch if (sblk->status_completion_producer_index || 10699206268Sdavidch sblk->status_cmd_consumer_index) 10700169271Sdavidch BCE_PRINTF("com_prod = 0x%08X, cmd_cons = 0x%08X\n", 10701206268Sdavidch sblk->status_completion_producer_index, 10702206268Sdavidch sblk->status_cmd_consumer_index); 10703170392Sdavidch 10704169271Sdavidch BCE_PRINTF( 10705206268Sdavidch "----------------------------" 10706206268Sdavidch "----------------" 10707206268Sdavidch "----------------------------\n"); 10708157642Sps} 10709157642Sps 10710157642Sps 10711206268Sdavidch#define BCE_PRINT_64BIT_STAT(arg) \ 10712206268Sdavidchif (sblk->arg##_lo || sblk->arg##_hi) \ 10713206268Sdavidch BCE_PRINTF("0x%08X:%08X : %s\n", sblk->arg##_hi, \ 10714206268Sdavidch sblk->arg##_lo, #arg); 10715205300Sdavidch 10716206268Sdavidch#define BCE_PRINT_32BIT_STAT(arg) \ 10717206268Sdavidchif (sblk->arg) \ 10718206268Sdavidch BCE_PRINTF(" 0x%08X : %s\n", \ 10719206268Sdavidch sblk->arg, #arg); 10720205300Sdavidch 10721169271Sdavidch/****************************************************************************/ 10722170810Sdavidch/* Prints out the statistics block from host memory. */ 10723169271Sdavidch/* */ 10724169271Sdavidch/* Returns: */ 10725169271Sdavidch/* Nothing. */ 10726169271Sdavidch/****************************************************************************/ 10727179771Sdavidchstatic __attribute__ ((noinline)) void 10728157642Spsbce_dump_stats_block(struct bce_softc *sc) 10729157642Sps{ 10730157642Sps struct statistics_block *sblk; 10731157642Sps 10732251159Smarius bus_dmamap_sync(sc->stats_tag, sc->stats_map, BUS_DMASYNC_POSTREAD); 10733251159Smarius 10734157642Sps sblk = sc->stats_block; 10735170392Sdavidch 10736169271Sdavidch BCE_PRINTF( 10737206268Sdavidch "---------------" 10738206268Sdavidch " Stats Block (All Stats Not Shown Are 0) " 10739206268Sdavidch "---------------\n"); 10740157642Sps 10741206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCInOctets); 10742206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCInBadOctets); 10743206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCOutOctets); 10744206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCOutBadOctets); 10745206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCInUcastPkts); 10746206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCInBroadcastPkts); 10747206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCInMulticastPkts); 10748206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCOutUcastPkts); 10749206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCOutBroadcastPkts); 10750206268Sdavidch BCE_PRINT_64BIT_STAT(stat_IfHCOutMulticastPkts); 10751206268Sdavidch BCE_PRINT_32BIT_STAT( 10752206268Sdavidch stat_emac_tx_stat_dot3statsinternalmactransmiterrors); 10753206268Sdavidch BCE_PRINT_32BIT_STAT(stat_Dot3StatsCarrierSenseErrors); 10754206268Sdavidch BCE_PRINT_32BIT_STAT(stat_Dot3StatsFCSErrors); 10755206268Sdavidch BCE_PRINT_32BIT_STAT(stat_Dot3StatsAlignmentErrors); 10756206268Sdavidch BCE_PRINT_32BIT_STAT(stat_Dot3StatsSingleCollisionFrames); 10757206268Sdavidch BCE_PRINT_32BIT_STAT(stat_Dot3StatsMultipleCollisionFrames); 10758206268Sdavidch BCE_PRINT_32BIT_STAT(stat_Dot3StatsDeferredTransmissions); 10759206268Sdavidch BCE_PRINT_32BIT_STAT(stat_Dot3StatsExcessiveCollisions); 10760206268Sdavidch BCE_PRINT_32BIT_STAT(stat_Dot3StatsLateCollisions); 10761206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsCollisions); 10762206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsFragments); 10763206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsJabbers); 10764206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsUndersizePkts); 10765206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsOversizePkts); 10766206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx64Octets); 10767206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx65Octetsto127Octets); 10768206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx128Octetsto255Octets); 10769206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx256Octetsto511Octets); 10770206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx512Octetsto1023Octets); 10771206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx1024Octetsto1522Octets); 10772206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx1523Octetsto9022Octets); 10773206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx64Octets); 10774206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx65Octetsto127Octets); 10775206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx128Octetsto255Octets); 10776206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx256Octetsto511Octets); 10777206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx512Octetsto1023Octets); 10778206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx1024Octetsto1522Octets); 10779206268Sdavidch BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx1523Octetsto9022Octets); 10780206268Sdavidch BCE_PRINT_32BIT_STAT(stat_XonPauseFramesReceived); 10781206268Sdavidch BCE_PRINT_32BIT_STAT(stat_XoffPauseFramesReceived); 10782206268Sdavidch BCE_PRINT_32BIT_STAT(stat_OutXonSent); 10783206268Sdavidch BCE_PRINT_32BIT_STAT(stat_OutXoffSent); 10784206268Sdavidch BCE_PRINT_32BIT_STAT(stat_FlowControlDone); 10785206268Sdavidch BCE_PRINT_32BIT_STAT(stat_MacControlFramesReceived); 10786206268Sdavidch BCE_PRINT_32BIT_STAT(stat_XoffStateEntered); 10787206268Sdavidch BCE_PRINT_32BIT_STAT(stat_IfInFramesL2FilterDiscards); 10788206268Sdavidch BCE_PRINT_32BIT_STAT(stat_IfInRuleCheckerDiscards); 10789206268Sdavidch BCE_PRINT_32BIT_STAT(stat_IfInFTQDiscards); 10790206268Sdavidch BCE_PRINT_32BIT_STAT(stat_IfInMBUFDiscards); 10791206268Sdavidch BCE_PRINT_32BIT_STAT(stat_IfInRuleCheckerP4Hit); 10792206268Sdavidch BCE_PRINT_32BIT_STAT(stat_CatchupInRuleCheckerDiscards); 10793206268Sdavidch BCE_PRINT_32BIT_STAT(stat_CatchupInFTQDiscards); 10794206268Sdavidch BCE_PRINT_32BIT_STAT(stat_CatchupInMBUFDiscards); 10795206268Sdavidch BCE_PRINT_32BIT_STAT(stat_CatchupInRuleCheckerP4Hit); 10796170392Sdavidch 10797169271Sdavidch BCE_PRINTF( 10798206268Sdavidch "----------------------------" 10799206268Sdavidch "----------------" 10800206268Sdavidch "----------------------------\n"); 10801157642Sps} 10802157642Sps 10803157642Sps 10804169271Sdavidch/****************************************************************************/ 10805169271Sdavidch/* Prints out a summary of the driver state. */ 10806169271Sdavidch/* */ 10807169271Sdavidch/* Returns: */ 10808169271Sdavidch/* Nothing. */ 10809169271Sdavidch/****************************************************************************/ 10810179771Sdavidchstatic __attribute__ ((noinline)) void 10811157642Spsbce_dump_driver_state(struct bce_softc *sc) 10812157642Sps{ 10813157642Sps u32 val_hi, val_lo; 10814157642Sps 10815169271Sdavidch BCE_PRINTF( 10816206268Sdavidch "-----------------------------" 10817206268Sdavidch " Driver State " 10818206268Sdavidch "-----------------------------\n"); 10819157642Sps 10820157642Sps val_hi = BCE_ADDR_HI(sc); 10821157642Sps val_lo = BCE_ADDR_LO(sc); 10822206268Sdavidch BCE_PRINTF("0x%08X:%08X - (sc) driver softc structure virtual " 10823206268Sdavidch "address\n", val_hi, val_lo); 10824157642Sps 10825157642Sps val_hi = BCE_ADDR_HI(sc->bce_vhandle); 10826157642Sps val_lo = BCE_ADDR_LO(sc->bce_vhandle); 10827206268Sdavidch BCE_PRINTF("0x%08X:%08X - (sc->bce_vhandle) PCI BAR virtual " 10828206268Sdavidch "address\n", val_hi, val_lo); 10829157642Sps 10830157642Sps val_hi = BCE_ADDR_HI(sc->status_block); 10831157642Sps val_lo = BCE_ADDR_LO(sc->status_block); 10832206268Sdavidch BCE_PRINTF("0x%08X:%08X - (sc->status_block) status block " 10833206268Sdavidch "virtual address\n", val_hi, val_lo); 10834157642Sps 10835157642Sps val_hi = BCE_ADDR_HI(sc->stats_block); 10836157642Sps val_lo = BCE_ADDR_LO(sc->stats_block); 10837206268Sdavidch BCE_PRINTF("0x%08X:%08X - (sc->stats_block) statistics block " 10838206268Sdavidch "virtual address\n", val_hi, val_lo); 10839157642Sps 10840157642Sps val_hi = BCE_ADDR_HI(sc->tx_bd_chain); 10841157642Sps val_lo = BCE_ADDR_LO(sc->tx_bd_chain); 10842206268Sdavidch BCE_PRINTF("0x%08X:%08X - (sc->tx_bd_chain) tx_bd chain " 10843206268Sdavidch "virtual adddress\n", val_hi, val_lo); 10844157642Sps 10845157642Sps val_hi = BCE_ADDR_HI(sc->rx_bd_chain); 10846157642Sps val_lo = BCE_ADDR_LO(sc->rx_bd_chain); 10847206268Sdavidch BCE_PRINTF("0x%08X:%08X - (sc->rx_bd_chain) rx_bd chain " 10848206268Sdavidch "virtual address\n", val_hi, val_lo); 10849157642Sps 10850218423Sdavidch if (bce_hdr_split == TRUE) { 10851218423Sdavidch val_hi = BCE_ADDR_HI(sc->pg_bd_chain); 10852218423Sdavidch val_lo = BCE_ADDR_LO(sc->pg_bd_chain); 10853218423Sdavidch BCE_PRINTF("0x%08X:%08X - (sc->pg_bd_chain) page chain " 10854218423Sdavidch "virtual address\n", val_hi, val_lo); 10855218423Sdavidch } 10856176448Sdavidch 10857157642Sps val_hi = BCE_ADDR_HI(sc->tx_mbuf_ptr); 10858157642Sps val_lo = BCE_ADDR_LO(sc->tx_mbuf_ptr); 10859206268Sdavidch BCE_PRINTF("0x%08X:%08X - (sc->tx_mbuf_ptr) tx mbuf chain " 10860206268Sdavidch "virtual address\n", val_hi, val_lo); 10861157642Sps 10862157642Sps val_hi = BCE_ADDR_HI(sc->rx_mbuf_ptr); 10863157642Sps val_lo = BCE_ADDR_LO(sc->rx_mbuf_ptr); 10864206268Sdavidch BCE_PRINTF("0x%08X:%08X - (sc->rx_mbuf_ptr) rx mbuf chain " 10865206268Sdavidch "virtual address\n", val_hi, val_lo); 10866157642Sps 10867218423Sdavidch if (bce_hdr_split == TRUE) { 10868218423Sdavidch val_hi = BCE_ADDR_HI(sc->pg_mbuf_ptr); 10869218423Sdavidch val_lo = BCE_ADDR_LO(sc->pg_mbuf_ptr); 10870218423Sdavidch BCE_PRINTF("0x%08X:%08X - (sc->pg_mbuf_ptr) page mbuf chain " 10871218423Sdavidch "virtual address\n", val_hi, val_lo); 10872218423Sdavidch } 10873176448Sdavidch 10874218423Sdavidch BCE_PRINTF(" 0x%016llX - (sc->interrupts_generated) " 10875218423Sdavidch "h/w intrs\n", 10876218423Sdavidch (long long unsigned int) sc->interrupts_generated); 10877179771Sdavidch 10878218423Sdavidch BCE_PRINTF(" 0x%016llX - (sc->interrupts_rx) " 10879218423Sdavidch "rx interrupts handled\n", 10880218423Sdavidch (long long unsigned int) sc->interrupts_rx); 10881157642Sps 10882218423Sdavidch BCE_PRINTF(" 0x%016llX - (sc->interrupts_tx) " 10883218423Sdavidch "tx interrupts handled\n", 10884218423Sdavidch (long long unsigned int) sc->interrupts_tx); 10885157642Sps 10886218423Sdavidch BCE_PRINTF(" 0x%016llX - (sc->phy_interrupts) " 10887218423Sdavidch "phy interrupts handled\n", 10888218423Sdavidch (long long unsigned int) sc->phy_interrupts); 10889157642Sps 10890206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->last_status_idx) " 10891206268Sdavidch "status block index\n", sc->last_status_idx); 10892157642Sps 10893206268Sdavidch BCE_PRINTF(" 0x%04X(0x%04X) - (sc->tx_prod) tx producer " 10894206268Sdavidch "index\n", sc->tx_prod, (u16) TX_CHAIN_IDX(sc->tx_prod)); 10895157642Sps 10896206268Sdavidch BCE_PRINTF(" 0x%04X(0x%04X) - (sc->tx_cons) tx consumer " 10897206268Sdavidch "index\n", sc->tx_cons, (u16) TX_CHAIN_IDX(sc->tx_cons)); 10898157642Sps 10899206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->tx_prod_bseq) tx producer " 10900206268Sdavidch "byte seq index\n", sc->tx_prod_bseq); 10901171667Sdavidch 10902206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->debug_tx_mbuf_alloc) tx " 10903206268Sdavidch "mbufs allocated\n", sc->debug_tx_mbuf_alloc); 10904171667Sdavidch 10905206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->used_tx_bd) used " 10906206268Sdavidch "tx_bd's\n", sc->used_tx_bd); 10907171667Sdavidch 10908218423Sdavidch BCE_PRINTF(" 0x%04X/0x%04X - (sc->tx_hi_watermark)/" 10909218423Sdavidch "(sc->max_tx_bd)\n", sc->tx_hi_watermark, sc->max_tx_bd); 10910157642Sps 10911206268Sdavidch BCE_PRINTF(" 0x%04X(0x%04X) - (sc->rx_prod) rx producer " 10912206268Sdavidch "index\n", sc->rx_prod, (u16) RX_CHAIN_IDX(sc->rx_prod)); 10913157642Sps 10914206268Sdavidch BCE_PRINTF(" 0x%04X(0x%04X) - (sc->rx_cons) rx consumer " 10915206268Sdavidch "index\n", sc->rx_cons, (u16) RX_CHAIN_IDX(sc->rx_cons)); 10916157642Sps 10917206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->rx_prod_bseq) rx producer " 10918206268Sdavidch "byte seq index\n", sc->rx_prod_bseq); 10919157642Sps 10920218423Sdavidch BCE_PRINTF(" 0x%04X/0x%04X - (sc->rx_low_watermark)/" 10921218423Sdavidch "(sc->max_rx_bd)\n", sc->rx_low_watermark, sc->max_rx_bd); 10922218423Sdavidch 10923206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->debug_rx_mbuf_alloc) rx " 10924206268Sdavidch "mbufs allocated\n", sc->debug_rx_mbuf_alloc); 10925157642Sps 10926206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->free_rx_bd) free " 10927206268Sdavidch "rx_bd's\n", sc->free_rx_bd); 10928206268Sdavidch 10929218423Sdavidch if (bce_hdr_split == TRUE) { 10930218423Sdavidch BCE_PRINTF(" 0x%04X(0x%04X) - (sc->pg_prod) page producer " 10931218423Sdavidch "index\n", sc->pg_prod, (u16) PG_CHAIN_IDX(sc->pg_prod)); 10932157642Sps 10933218423Sdavidch BCE_PRINTF(" 0x%04X(0x%04X) - (sc->pg_cons) page consumer " 10934218423Sdavidch "index\n", sc->pg_cons, (u16) PG_CHAIN_IDX(sc->pg_cons)); 10935176448Sdavidch 10936218423Sdavidch BCE_PRINTF(" 0x%08X - (sc->debug_pg_mbuf_alloc) page " 10937218423Sdavidch "mbufs allocated\n", sc->debug_pg_mbuf_alloc); 10938218423Sdavidch } 10939176448Sdavidch 10940206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->free_pg_bd) free page " 10941206268Sdavidch "rx_bd's\n", sc->free_pg_bd); 10942176448Sdavidch 10943218423Sdavidch BCE_PRINTF(" 0x%04X/0x%04X - (sc->pg_low_watermark)/" 10944218423Sdavidch "(sc->max_pg_bd)\n", sc->pg_low_watermark, sc->max_pg_bd); 10945176448Sdavidch 10946189325Sdavidch BCE_PRINTF(" 0x%08X - (sc->mbuf_alloc_failed_count) " 10947206268Sdavidch "mbuf alloc failures\n", sc->mbuf_alloc_failed_count); 10948157642Sps 10949206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->bce_flags) " 10950206268Sdavidch "bce mac flags\n", sc->bce_flags); 10951179771Sdavidch 10952206268Sdavidch BCE_PRINTF(" 0x%08X - (sc->bce_phy_flags) " 10953206268Sdavidch "bce phy flags\n", sc->bce_phy_flags); 10954179771Sdavidch 10955169271Sdavidch BCE_PRINTF( 10956206268Sdavidch "----------------------------" 10957206268Sdavidch "----------------" 10958206268Sdavidch "----------------------------\n"); 10959157642Sps} 10960157642Sps 10961170392Sdavidch 10962169271Sdavidch/****************************************************************************/ 10963170810Sdavidch/* Prints out the hardware state through a summary of important register, */ 10964169271Sdavidch/* followed by a complete register dump. */ 10965169271Sdavidch/* */ 10966169271Sdavidch/* Returns: */ 10967169271Sdavidch/* Nothing. */ 10968169271Sdavidch/****************************************************************************/ 10969179771Sdavidchstatic __attribute__ ((noinline)) void 10970157642Spsbce_dump_hw_state(struct bce_softc *sc) 10971157642Sps{ 10972176448Sdavidch u32 val; 10973157642Sps 10974169271Sdavidch BCE_PRINTF( 10975206268Sdavidch "----------------------------" 10976206268Sdavidch " Hardware State " 10977206268Sdavidch "----------------------------\n"); 10978157642Sps 10979194781Sdavidch BCE_PRINTF("%s - bootcode version\n", sc->bce_bc_ver); 10980157642Sps 10981176448Sdavidch val = REG_RD(sc, BCE_MISC_ENABLE_STATUS_BITS); 10982169632Sdavidch BCE_PRINTF("0x%08X - (0x%06X) misc_enable_status_bits\n", 10983206268Sdavidch val, BCE_MISC_ENABLE_STATUS_BITS); 10984157642Sps 10985176448Sdavidch val = REG_RD(sc, BCE_DMA_STATUS); 10986207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) dma_status\n", 10987206268Sdavidch val, BCE_DMA_STATUS); 10988157642Sps 10989176448Sdavidch val = REG_RD(sc, BCE_CTX_STATUS); 10990207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) ctx_status\n", 10991206268Sdavidch val, BCE_CTX_STATUS); 10992157642Sps 10993176448Sdavidch val = REG_RD(sc, BCE_EMAC_STATUS); 10994207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) emac_status\n", 10995206268Sdavidch val, BCE_EMAC_STATUS); 10996157642Sps 10997176448Sdavidch val = REG_RD(sc, BCE_RPM_STATUS); 10998206268Sdavidch BCE_PRINTF("0x%08X - (0x%06X) rpm_status\n", 10999206268Sdavidch val, BCE_RPM_STATUS); 11000157642Sps 11001206268Sdavidch /* ToDo: Create a #define for this constant. */ 11002176448Sdavidch val = REG_RD(sc, 0x2004); 11003207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) rlup_status\n", 11004206268Sdavidch val, 0x2004); 11005157642Sps 11006176448Sdavidch val = REG_RD(sc, BCE_RV2P_STATUS); 11007207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) rv2p_status\n", 11008206268Sdavidch val, BCE_RV2P_STATUS); 11009157642Sps 11010206268Sdavidch /* ToDo: Create a #define for this constant. */ 11011176448Sdavidch val = REG_RD(sc, 0x2c04); 11012207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) rdma_status\n", 11013206268Sdavidch val, 0x2c04); 11014157642Sps 11015176448Sdavidch val = REG_RD(sc, BCE_TBDR_STATUS); 11016206268Sdavidch BCE_PRINTF("0x%08X - (0x%06X) tbdr_status\n", 11017206268Sdavidch val, BCE_TBDR_STATUS); 11018169632Sdavidch 11019176448Sdavidch val = REG_RD(sc, BCE_TDMA_STATUS); 11020207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) tdma_status\n", 11021206268Sdavidch val, BCE_TDMA_STATUS); 11022169632Sdavidch 11023176448Sdavidch val = REG_RD(sc, BCE_HC_STATUS); 11024206268Sdavidch BCE_PRINTF("0x%08X - (0x%06X) hc_status\n", 11025206268Sdavidch val, BCE_HC_STATUS); 11026169632Sdavidch 11027176448Sdavidch val = REG_RD_IND(sc, BCE_TXP_CPU_STATE); 11028207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_state\n", 11029206268Sdavidch val, BCE_TXP_CPU_STATE); 11030169632Sdavidch 11031176448Sdavidch val = REG_RD_IND(sc, BCE_TPAT_CPU_STATE); 11032207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_state\n", 11033206268Sdavidch val, BCE_TPAT_CPU_STATE); 11034169632Sdavidch 11035176448Sdavidch val = REG_RD_IND(sc, BCE_RXP_CPU_STATE); 11036207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_state\n", 11037206268Sdavidch val, BCE_RXP_CPU_STATE); 11038169632Sdavidch 11039176448Sdavidch val = REG_RD_IND(sc, BCE_COM_CPU_STATE); 11040207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) com_cpu_state\n", 11041206268Sdavidch val, BCE_COM_CPU_STATE); 11042176448Sdavidch 11043176448Sdavidch val = REG_RD_IND(sc, BCE_MCP_CPU_STATE); 11044207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) mcp_cpu_state\n", 11045206268Sdavidch val, BCE_MCP_CPU_STATE); 11046176448Sdavidch 11047176448Sdavidch val = REG_RD_IND(sc, BCE_CP_CPU_STATE); 11048207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_state\n", 11049206268Sdavidch val, BCE_CP_CPU_STATE); 11050176448Sdavidch 11051179771Sdavidch BCE_PRINTF( 11052206268Sdavidch "----------------------------" 11053206268Sdavidch "----------------" 11054206268Sdavidch "----------------------------\n"); 11055157642Sps 11056179771Sdavidch BCE_PRINTF( 11057206268Sdavidch "----------------------------" 11058206268Sdavidch " Register Dump " 11059206268Sdavidch "----------------------------\n"); 11060170392Sdavidch 11061178132Sdavidch for (int i = 0x400; i < 0x8000; i += 0x10) { 11062169271Sdavidch BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n", 11063206268Sdavidch i, REG_RD(sc, i), REG_RD(sc, i + 0x4), 11064206268Sdavidch REG_RD(sc, i + 0x8), REG_RD(sc, i + 0xC)); 11065176448Sdavidch } 11066157642Sps 11067179771Sdavidch BCE_PRINTF( 11068206268Sdavidch "----------------------------" 11069206268Sdavidch "----------------" 11070206268Sdavidch "----------------------------\n"); 11071157642Sps} 11072157642Sps 11073157642Sps 11074169271Sdavidch/****************************************************************************/ 11075218423Sdavidch/* Prints out the contentst of shared memory which is used for host driver */ 11076218423Sdavidch/* to bootcode firmware communication. */ 11077218423Sdavidch/* */ 11078218423Sdavidch/* Returns: */ 11079218423Sdavidch/* Nothing. */ 11080218423Sdavidch/****************************************************************************/ 11081218423Sdavidchstatic __attribute__ ((noinline)) void 11082218423Sdavidchbce_dump_shmem_state(struct bce_softc *sc) 11083218423Sdavidch{ 11084218423Sdavidch BCE_PRINTF( 11085218423Sdavidch "----------------------------" 11086218423Sdavidch " Hardware State " 11087218423Sdavidch "----------------------------\n"); 11088218423Sdavidch 11089218423Sdavidch BCE_PRINTF("0x%08X - Shared memory base address\n", 11090218423Sdavidch sc->bce_shmem_base); 11091218423Sdavidch BCE_PRINTF("%s - bootcode version\n", 11092218423Sdavidch sc->bce_bc_ver); 11093218423Sdavidch 11094218423Sdavidch BCE_PRINTF( 11095218423Sdavidch "----------------------------" 11096218423Sdavidch " Shared Mem " 11097218423Sdavidch "----------------------------\n"); 11098218423Sdavidch 11099218423Sdavidch for (int i = 0x0; i < 0x200; i += 0x10) { 11100218423Sdavidch BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n", 11101218423Sdavidch i, bce_shmem_rd(sc, i), bce_shmem_rd(sc, i + 0x4), 11102218423Sdavidch bce_shmem_rd(sc, i + 0x8), bce_shmem_rd(sc, i + 0xC)); 11103218423Sdavidch } 11104218423Sdavidch 11105218423Sdavidch BCE_PRINTF( 11106218423Sdavidch "----------------------------" 11107218423Sdavidch "----------------" 11108218423Sdavidch "----------------------------\n"); 11109218423Sdavidch} 11110218423Sdavidch 11111218423Sdavidch 11112218423Sdavidch/****************************************************************************/ 11113179771Sdavidch/* Prints out the mailbox queue registers. */ 11114179771Sdavidch/* */ 11115179771Sdavidch/* Returns: */ 11116179771Sdavidch/* Nothing. */ 11117179771Sdavidch/****************************************************************************/ 11118179771Sdavidchstatic __attribute__ ((noinline)) void 11119179771Sdavidchbce_dump_mq_regs(struct bce_softc *sc) 11120179771Sdavidch{ 11121179771Sdavidch BCE_PRINTF( 11122206268Sdavidch "----------------------------" 11123206268Sdavidch " MQ Regs " 11124206268Sdavidch "----------------------------\n"); 11125179771Sdavidch 11126179771Sdavidch BCE_PRINTF( 11127206268Sdavidch "----------------------------" 11128206268Sdavidch "----------------" 11129206268Sdavidch "----------------------------\n"); 11130179771Sdavidch 11131179771Sdavidch for (int i = 0x3c00; i < 0x4000; i += 0x10) { 11132179771Sdavidch BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n", 11133206268Sdavidch i, REG_RD(sc, i), REG_RD(sc, i + 0x4), 11134206268Sdavidch REG_RD(sc, i + 0x8), REG_RD(sc, i + 0xC)); 11135179771Sdavidch } 11136179771Sdavidch 11137179771Sdavidch BCE_PRINTF( 11138206268Sdavidch "----------------------------" 11139206268Sdavidch "----------------" 11140206268Sdavidch "----------------------------\n"); 11141179771Sdavidch} 11142179771Sdavidch 11143179771Sdavidch 11144179771Sdavidch/****************************************************************************/ 11145170810Sdavidch/* Prints out the bootcode state. */ 11146170810Sdavidch/* */ 11147170810Sdavidch/* Returns: */ 11148170810Sdavidch/* Nothing. */ 11149170810Sdavidch/****************************************************************************/ 11150179771Sdavidchstatic __attribute__ ((noinline)) void 11151170810Sdavidchbce_dump_bc_state(struct bce_softc *sc) 11152170810Sdavidch{ 11153170810Sdavidch u32 val; 11154170810Sdavidch 11155170810Sdavidch BCE_PRINTF( 11156206268Sdavidch "----------------------------" 11157206268Sdavidch " Bootcode State " 11158206268Sdavidch "----------------------------\n"); 11159170810Sdavidch 11160194781Sdavidch BCE_PRINTF("%s - bootcode version\n", sc->bce_bc_ver); 11161170810Sdavidch 11162194781Sdavidch val = bce_shmem_rd(sc, BCE_BC_RESET_TYPE); 11163170810Sdavidch BCE_PRINTF("0x%08X - (0x%06X) reset_type\n", 11164206268Sdavidch val, BCE_BC_RESET_TYPE); 11165170810Sdavidch 11166194781Sdavidch val = bce_shmem_rd(sc, BCE_BC_STATE); 11167170810Sdavidch BCE_PRINTF("0x%08X - (0x%06X) state\n", 11168206268Sdavidch val, BCE_BC_STATE); 11169170810Sdavidch 11170202717Sdavidch val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION); 11171170810Sdavidch BCE_PRINTF("0x%08X - (0x%06X) condition\n", 11172206268Sdavidch val, BCE_BC_STATE_CONDITION); 11173170810Sdavidch 11174194781Sdavidch val = bce_shmem_rd(sc, BCE_BC_STATE_DEBUG_CMD); 11175170810Sdavidch BCE_PRINTF("0x%08X - (0x%06X) debug_cmd\n", 11176206268Sdavidch val, BCE_BC_STATE_DEBUG_CMD); 11177170810Sdavidch 11178179771Sdavidch BCE_PRINTF( 11179206268Sdavidch "----------------------------" 11180206268Sdavidch "----------------" 11181206268Sdavidch "----------------------------\n"); 11182170810Sdavidch} 11183170810Sdavidch 11184170810Sdavidch 11185170810Sdavidch/****************************************************************************/ 11186179771Sdavidch/* Prints out the TXP processor state. */ 11187169632Sdavidch/* */ 11188169632Sdavidch/* Returns: */ 11189169632Sdavidch/* Nothing. */ 11190169632Sdavidch/****************************************************************************/ 11191179771Sdavidchstatic __attribute__ ((noinline)) void 11192179771Sdavidchbce_dump_txp_state(struct bce_softc *sc, int regs) 11193169632Sdavidch{ 11194179771Sdavidch u32 val; 11195182293Sdavidch u32 fw_version[3]; 11196169632Sdavidch 11197169632Sdavidch BCE_PRINTF( 11198206268Sdavidch "----------------------------" 11199206268Sdavidch " TXP State " 11200206268Sdavidch "----------------------------\n"); 11201169632Sdavidch 11202182293Sdavidch for (int i = 0; i < 3; i++) 11203182293Sdavidch fw_version[i] = htonl(REG_RD_IND(sc, 11204206268Sdavidch (BCE_TXP_SCRATCH + 0x10 + i * 4))); 11205182293Sdavidch BCE_PRINTF("Firmware version - %s\n", (char *) fw_version); 11206182293Sdavidch 11207179771Sdavidch val = REG_RD_IND(sc, BCE_TXP_CPU_MODE); 11208207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_mode\n", 11209206268Sdavidch val, BCE_TXP_CPU_MODE); 11210169632Sdavidch 11211179771Sdavidch val = REG_RD_IND(sc, BCE_TXP_CPU_STATE); 11212207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_state\n", 11213206268Sdavidch val, BCE_TXP_CPU_STATE); 11214169632Sdavidch 11215179771Sdavidch val = REG_RD_IND(sc, BCE_TXP_CPU_EVENT_MASK); 11216207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_event_mask\n", 11217206268Sdavidch val, BCE_TXP_CPU_EVENT_MASK); 11218169632Sdavidch 11219179771Sdavidch if (regs) { 11220179771Sdavidch BCE_PRINTF( 11221206268Sdavidch "----------------------------" 11222206268Sdavidch " Register Dump " 11223206268Sdavidch "----------------------------\n"); 11224170392Sdavidch 11225179771Sdavidch for (int i = BCE_TXP_CPU_MODE; i < 0x68000; i += 0x10) { 11226179771Sdavidch /* Skip the big blank spaces */ 11227179771Sdavidch if (i < 0x454000 && i > 0x5ffff) 11228206268Sdavidch BCE_PRINTF("0x%04X: 0x%08X 0x%08X " 11229207411Sdavidch "0x%08X 0x%08X\n", i, 11230207411Sdavidch REG_RD_IND(sc, i), 11231206268Sdavidch REG_RD_IND(sc, i + 0x4), 11232206268Sdavidch REG_RD_IND(sc, i + 0x8), 11233206268Sdavidch REG_RD_IND(sc, i + 0xC)); 11234179771Sdavidch } 11235169632Sdavidch } 11236169632Sdavidch 11237179771Sdavidch BCE_PRINTF( 11238206268Sdavidch "----------------------------" 11239206268Sdavidch "----------------" 11240206268Sdavidch "----------------------------\n"); 11241169632Sdavidch} 11242169632Sdavidch 11243169632Sdavidch 11244169632Sdavidch/****************************************************************************/ 11245179771Sdavidch/* Prints out the RXP processor state. */ 11246169632Sdavidch/* */ 11247169632Sdavidch/* Returns: */ 11248169632Sdavidch/* Nothing. */ 11249169632Sdavidch/****************************************************************************/ 11250179771Sdavidchstatic __attribute__ ((noinline)) void 11251179771Sdavidchbce_dump_rxp_state(struct bce_softc *sc, int regs) 11252169632Sdavidch{ 11253179771Sdavidch u32 val; 11254182293Sdavidch u32 fw_version[3]; 11255169632Sdavidch 11256169632Sdavidch BCE_PRINTF( 11257206268Sdavidch "----------------------------" 11258206268Sdavidch " RXP State " 11259206268Sdavidch "----------------------------\n"); 11260169632Sdavidch 11261182293Sdavidch for (int i = 0; i < 3; i++) 11262182293Sdavidch fw_version[i] = htonl(REG_RD_IND(sc, 11263206268Sdavidch (BCE_RXP_SCRATCH + 0x10 + i * 4))); 11264206268Sdavidch 11265182293Sdavidch BCE_PRINTF("Firmware version - %s\n", (char *) fw_version); 11266182293Sdavidch 11267179771Sdavidch val = REG_RD_IND(sc, BCE_RXP_CPU_MODE); 11268207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_mode\n", 11269206268Sdavidch val, BCE_RXP_CPU_MODE); 11270169632Sdavidch 11271179771Sdavidch val = REG_RD_IND(sc, BCE_RXP_CPU_STATE); 11272207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_state\n", 11273206268Sdavidch val, BCE_RXP_CPU_STATE); 11274169632Sdavidch 11275179771Sdavidch val = REG_RD_IND(sc, BCE_RXP_CPU_EVENT_MASK); 11276207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_event_mask\n", 11277206268Sdavidch val, BCE_RXP_CPU_EVENT_MASK); 11278169632Sdavidch 11279179771Sdavidch if (regs) { 11280179771Sdavidch BCE_PRINTF( 11281206268Sdavidch "----------------------------" 11282206268Sdavidch " Register Dump " 11283206268Sdavidch "----------------------------\n"); 11284179771Sdavidch 11285179771Sdavidch for (int i = BCE_RXP_CPU_MODE; i < 0xe8fff; i += 0x10) { 11286179771Sdavidch /* Skip the big blank sapces */ 11287179771Sdavidch if (i < 0xc5400 && i > 0xdffff) 11288206268Sdavidch BCE_PRINTF("0x%04X: 0x%08X 0x%08X " 11289207411Sdavidch "0x%08X 0x%08X\n", i, 11290207411Sdavidch REG_RD_IND(sc, i), 11291206268Sdavidch REG_RD_IND(sc, i + 0x4), 11292207411Sdavidch REG_RD_IND(sc, i + 0x8), 11293206268Sdavidch REG_RD_IND(sc, i + 0xC)); 11294179771Sdavidch } 11295179771Sdavidch } 11296179771Sdavidch 11297179771Sdavidch BCE_PRINTF( 11298206268Sdavidch "----------------------------" 11299206268Sdavidch "----------------" 11300206268Sdavidch "----------------------------\n"); 11301179771Sdavidch} 11302170392Sdavidch 11303179771Sdavidch 11304179771Sdavidch/****************************************************************************/ 11305179771Sdavidch/* Prints out the TPAT processor state. */ 11306179771Sdavidch/* */ 11307179771Sdavidch/* Returns: */ 11308179771Sdavidch/* Nothing. */ 11309179771Sdavidch/****************************************************************************/ 11310179771Sdavidchstatic __attribute__ ((noinline)) void 11311179771Sdavidchbce_dump_tpat_state(struct bce_softc *sc, int regs) 11312179771Sdavidch{ 11313179771Sdavidch u32 val; 11314182293Sdavidch u32 fw_version[3]; 11315179771Sdavidch 11316179771Sdavidch BCE_PRINTF( 11317206268Sdavidch "----------------------------" 11318206268Sdavidch " TPAT State " 11319206268Sdavidch "----------------------------\n"); 11320179771Sdavidch 11321182293Sdavidch for (int i = 0; i < 3; i++) 11322182293Sdavidch fw_version[i] = htonl(REG_RD_IND(sc, 11323206268Sdavidch (BCE_TPAT_SCRATCH + 0x410 + i * 4))); 11324206268Sdavidch 11325182293Sdavidch BCE_PRINTF("Firmware version - %s\n", (char *) fw_version); 11326182293Sdavidch 11327179771Sdavidch val = REG_RD_IND(sc, BCE_TPAT_CPU_MODE); 11328207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_mode\n", 11329206268Sdavidch val, BCE_TPAT_CPU_MODE); 11330179771Sdavidch 11331179771Sdavidch val = REG_RD_IND(sc, BCE_TPAT_CPU_STATE); 11332207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_state\n", 11333206268Sdavidch val, BCE_TPAT_CPU_STATE); 11334179771Sdavidch 11335179771Sdavidch val = REG_RD_IND(sc, BCE_TPAT_CPU_EVENT_MASK); 11336207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_event_mask\n", 11337206268Sdavidch val, BCE_TPAT_CPU_EVENT_MASK); 11338179771Sdavidch 11339179771Sdavidch if (regs) { 11340179771Sdavidch BCE_PRINTF( 11341206268Sdavidch "----------------------------" 11342206268Sdavidch " Register Dump " 11343206268Sdavidch "----------------------------\n"); 11344179771Sdavidch 11345179771Sdavidch for (int i = BCE_TPAT_CPU_MODE; i < 0xa3fff; i += 0x10) { 11346179771Sdavidch /* Skip the big blank spaces */ 11347179771Sdavidch if (i < 0x854000 && i > 0x9ffff) 11348206268Sdavidch BCE_PRINTF("0x%04X: 0x%08X 0x%08X " 11349206268Sdavidch "0x%08X 0x%08X\n", i, 11350207411Sdavidch REG_RD_IND(sc, i), 11351206268Sdavidch REG_RD_IND(sc, i + 0x4), 11352207411Sdavidch REG_RD_IND(sc, i + 0x8), 11353206268Sdavidch REG_RD_IND(sc, i + 0xC)); 11354179771Sdavidch } 11355169632Sdavidch } 11356169632Sdavidch 11357179771Sdavidch BCE_PRINTF( 11358169632Sdavidch "----------------------------" 11359169632Sdavidch "----------------" 11360169632Sdavidch "----------------------------\n"); 11361169632Sdavidch} 11362169632Sdavidch 11363169632Sdavidch 11364169632Sdavidch/****************************************************************************/ 11365179771Sdavidch/* Prints out the Command Procesor (CP) state. */ 11366169632Sdavidch/* */ 11367169632Sdavidch/* Returns: */ 11368169632Sdavidch/* Nothing. */ 11369169632Sdavidch/****************************************************************************/ 11370179771Sdavidchstatic __attribute__ ((noinline)) void 11371179771Sdavidchbce_dump_cp_state(struct bce_softc *sc, int regs) 11372169632Sdavidch{ 11373179771Sdavidch u32 val; 11374182293Sdavidch u32 fw_version[3]; 11375169632Sdavidch 11376169632Sdavidch BCE_PRINTF( 11377206268Sdavidch "----------------------------" 11378206268Sdavidch " CP State " 11379206268Sdavidch "----------------------------\n"); 11380169632Sdavidch 11381182293Sdavidch for (int i = 0; i < 3; i++) 11382182293Sdavidch fw_version[i] = htonl(REG_RD_IND(sc, 11383206268Sdavidch (BCE_CP_SCRATCH + 0x10 + i * 4))); 11384206268Sdavidch 11385182293Sdavidch BCE_PRINTF("Firmware version - %s\n", (char *) fw_version); 11386182293Sdavidch 11387179771Sdavidch val = REG_RD_IND(sc, BCE_CP_CPU_MODE); 11388207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_mode\n", 11389206268Sdavidch val, BCE_CP_CPU_MODE); 11390169632Sdavidch 11391179771Sdavidch val = REG_RD_IND(sc, BCE_CP_CPU_STATE); 11392207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_state\n", 11393206268Sdavidch val, BCE_CP_CPU_STATE); 11394169632Sdavidch 11395179771Sdavidch val = REG_RD_IND(sc, BCE_CP_CPU_EVENT_MASK); 11396179771Sdavidch BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_event_mask\n", val, 11397206268Sdavidch BCE_CP_CPU_EVENT_MASK); 11398169632Sdavidch 11399179771Sdavidch if (regs) { 11400179771Sdavidch BCE_PRINTF( 11401206268Sdavidch "----------------------------" 11402206268Sdavidch " Register Dump " 11403206268Sdavidch "----------------------------\n"); 11404179771Sdavidch 11405179771Sdavidch for (int i = BCE_CP_CPU_MODE; i < 0x1aa000; i += 0x10) { 11406179771Sdavidch /* Skip the big blank spaces */ 11407179771Sdavidch if (i < 0x185400 && i > 0x19ffff) 11408206268Sdavidch BCE_PRINTF("0x%04X: 0x%08X 0x%08X " 11409207411Sdavidch "0x%08X 0x%08X\n", i, 11410207411Sdavidch REG_RD_IND(sc, i), 11411206268Sdavidch REG_RD_IND(sc, i + 0x4), 11412207411Sdavidch REG_RD_IND(sc, i + 0x8), 11413206268Sdavidch REG_RD_IND(sc, i + 0xC)); 11414179771Sdavidch } 11415179771Sdavidch } 11416179771Sdavidch 11417179771Sdavidch BCE_PRINTF( 11418206268Sdavidch "----------------------------" 11419206268Sdavidch "----------------" 11420206268Sdavidch "----------------------------\n"); 11421179771Sdavidch} 11422170392Sdavidch 11423179771Sdavidch 11424179771Sdavidch/****************************************************************************/ 11425179771Sdavidch/* Prints out the Completion Procesor (COM) state. */ 11426179771Sdavidch/* */ 11427179771Sdavidch/* Returns: */ 11428179771Sdavidch/* Nothing. */ 11429179771Sdavidch/****************************************************************************/ 11430179771Sdavidchstatic __attribute__ ((noinline)) void 11431179771Sdavidchbce_dump_com_state(struct bce_softc *sc, int regs) 11432179771Sdavidch{ 11433179771Sdavidch u32 val; 11434205300Sdavidch u32 fw_version[4]; 11435179771Sdavidch 11436179771Sdavidch BCE_PRINTF( 11437206268Sdavidch "----------------------------" 11438206268Sdavidch " COM State " 11439206268Sdavidch "----------------------------\n"); 11440179771Sdavidch 11441182293Sdavidch for (int i = 0; i < 3; i++) 11442182293Sdavidch fw_version[i] = htonl(REG_RD_IND(sc, 11443206268Sdavidch (BCE_COM_SCRATCH + 0x10 + i * 4))); 11444206268Sdavidch 11445182293Sdavidch BCE_PRINTF("Firmware version - %s\n", (char *) fw_version); 11446182293Sdavidch 11447179771Sdavidch val = REG_RD_IND(sc, BCE_COM_CPU_MODE); 11448207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) com_cpu_mode\n", 11449206268Sdavidch val, BCE_COM_CPU_MODE); 11450179771Sdavidch 11451179771Sdavidch val = REG_RD_IND(sc, BCE_COM_CPU_STATE); 11452207411Sdavidch BCE_PRINTF("0x%08X - (0x%06X) com_cpu_state\n", 11453206268Sdavidch val, BCE_COM_CPU_STATE); 11454179771Sdavidch 11455179771Sdavidch val = REG_RD_IND(sc, BCE_COM_CPU_EVENT_MASK); 11456179771Sdavidch BCE_PRINTF("0x%08X - (0x%06X) com_cpu_event_mask\n", val, 11457206268Sdavidch BCE_COM_CPU_EVENT_MASK); 11458179771Sdavidch 11459179771Sdavidch if (regs) { 11460179771Sdavidch BCE_PRINTF( 11461206268Sdavidch "----------------------------" 11462206268Sdavidch " Register Dump " 11463206268Sdavidch "----------------------------\n"); 11464179771Sdavidch 11465179771Sdavidch for (int i = BCE_COM_CPU_MODE; i < 0x1053e8; i += 0x10) { 11466206268Sdavidch BCE_PRINTF("0x%04X: 0x%08X 0x%08X " 11467207411Sdavidch "0x%08X 0x%08X\n", i, 11468207411Sdavidch REG_RD_IND(sc, i), 11469206268Sdavidch REG_RD_IND(sc, i + 0x4), 11470206268Sdavidch REG_RD_IND(sc, i + 0x8), 11471206268Sdavidch REG_RD_IND(sc, i + 0xC)); 11472179771Sdavidch } 11473169632Sdavidch } 11474169632Sdavidch 11475179771Sdavidch BCE_PRINTF( 11476169632Sdavidch "----------------------------" 11477169632Sdavidch "----------------" 11478169632Sdavidch "----------------------------\n"); 11479169632Sdavidch} 11480169632Sdavidch 11481169632Sdavidch 11482169632Sdavidch/****************************************************************************/ 11483205300Sdavidch/* Prints out the Receive Virtual 2 Physical (RV2P) state. */ 11484205300Sdavidch/* */ 11485205300Sdavidch/* Returns: */ 11486205300Sdavidch/* Nothing. */ 11487205300Sdavidch/****************************************************************************/ 11488205300Sdavidchstatic __attribute__ ((noinline)) void 11489205300Sdavidchbce_dump_rv2p_state(struct bce_softc *sc) 11490205300Sdavidch{ 11491205300Sdavidch u32 val, pc1, pc2, fw_ver_high, fw_ver_low; 11492205300Sdavidch 11493205300Sdavidch BCE_PRINTF( 11494206268Sdavidch "----------------------------" 11495206268Sdavidch " RV2P State " 11496206268Sdavidch "----------------------------\n"); 11497205300Sdavidch 11498206268Sdavidch /* Stall the RV2P processors. */ 11499206268Sdavidch val = REG_RD_IND(sc, BCE_RV2P_CONFIG); 11500206268Sdavidch val |= BCE_RV2P_CONFIG_STALL_PROC1 | BCE_RV2P_CONFIG_STALL_PROC2; 11501206268Sdavidch REG_WR_IND(sc, BCE_RV2P_CONFIG, val); 11502205300Sdavidch 11503206268Sdavidch /* Read the firmware version. */ 11504206268Sdavidch val = 0x00000001; 11505206268Sdavidch REG_WR_IND(sc, BCE_RV2P_PROC1_ADDR_CMD, val); 11506206268Sdavidch fw_ver_low = REG_RD_IND(sc, BCE_RV2P_INSTR_LOW); 11507207411Sdavidch fw_ver_high = REG_RD_IND(sc, BCE_RV2P_INSTR_HIGH) & 11508206268Sdavidch BCE_RV2P_INSTR_HIGH_HIGH; 11509207411Sdavidch BCE_PRINTF("RV2P1 Firmware version - 0x%08X:0x%08X\n", 11510206268Sdavidch fw_ver_high, fw_ver_low); 11511205300Sdavidch 11512206268Sdavidch val = 0x00000001; 11513206268Sdavidch REG_WR_IND(sc, BCE_RV2P_PROC2_ADDR_CMD, val); 11514206268Sdavidch fw_ver_low = REG_RD_IND(sc, BCE_RV2P_INSTR_LOW); 11515207411Sdavidch fw_ver_high = REG_RD_IND(sc, BCE_RV2P_INSTR_HIGH) & 11516206268Sdavidch BCE_RV2P_INSTR_HIGH_HIGH; 11517207411Sdavidch BCE_PRINTF("RV2P2 Firmware version - 0x%08X:0x%08X\n", 11518206268Sdavidch fw_ver_high, fw_ver_low); 11519205300Sdavidch 11520206268Sdavidch /* Resume the RV2P processors. */ 11521206268Sdavidch val = REG_RD_IND(sc, BCE_RV2P_CONFIG); 11522206268Sdavidch val &= ~(BCE_RV2P_CONFIG_STALL_PROC1 | BCE_RV2P_CONFIG_STALL_PROC2); 11523206268Sdavidch REG_WR_IND(sc, BCE_RV2P_CONFIG, val); 11524205300Sdavidch 11525206268Sdavidch /* Fetch the program counter value. */ 11526205300Sdavidch val = 0x68007800; 11527206268Sdavidch REG_WR_IND(sc, BCE_RV2P_DEBUG_VECT_PEEK, val); 11528206268Sdavidch val = REG_RD_IND(sc, BCE_RV2P_DEBUG_VECT_PEEK); 11529206268Sdavidch pc1 = (val & BCE_RV2P_DEBUG_VECT_PEEK_1_VALUE); 11530206268Sdavidch pc2 = (val & BCE_RV2P_DEBUG_VECT_PEEK_2_VALUE) >> 16; 11531206268Sdavidch BCE_PRINTF("0x%08X - RV2P1 program counter (1st read)\n", pc1); 11532206268Sdavidch BCE_PRINTF("0x%08X - RV2P2 program counter (1st read)\n", pc2); 11533205300Sdavidch 11534206268Sdavidch /* Fetch the program counter value again to see if it is advancing. */ 11535206268Sdavidch val = 0x68007800; 11536206268Sdavidch REG_WR_IND(sc, BCE_RV2P_DEBUG_VECT_PEEK, val); 11537206268Sdavidch val = REG_RD_IND(sc, BCE_RV2P_DEBUG_VECT_PEEK); 11538206268Sdavidch pc1 = (val & BCE_RV2P_DEBUG_VECT_PEEK_1_VALUE); 11539206268Sdavidch pc2 = (val & BCE_RV2P_DEBUG_VECT_PEEK_2_VALUE) >> 16; 11540206268Sdavidch BCE_PRINTF("0x%08X - RV2P1 program counter (2nd read)\n", pc1); 11541206268Sdavidch BCE_PRINTF("0x%08X - RV2P2 program counter (2nd read)\n", pc2); 11542205300Sdavidch 11543205300Sdavidch BCE_PRINTF( 11544206268Sdavidch "----------------------------" 11545206268Sdavidch "----------------" 11546206268Sdavidch "----------------------------\n"); 11547205300Sdavidch} 11548205300Sdavidch 11549205300Sdavidch 11550205300Sdavidch/****************************************************************************/ 11551170392Sdavidch/* Prints out the driver state and then enters the debugger. */ 11552169271Sdavidch/* */ 11553169271Sdavidch/* Returns: */ 11554169271Sdavidch/* Nothing. */ 11555169271Sdavidch/****************************************************************************/ 11556205300Sdavidchstatic __attribute__ ((noinline)) void 11557157642Spsbce_breakpoint(struct bce_softc *sc) 11558157642Sps{ 11559157642Sps 11560179771Sdavidch /* 11561179771Sdavidch * Unreachable code to silence compiler warnings 11562179771Sdavidch * about unused functions. 11563176448Sdavidch */ 11564157642Sps if (0) { 11565170392Sdavidch bce_freeze_controller(sc); 11566170392Sdavidch bce_unfreeze_controller(sc); 11567182293Sdavidch bce_dump_enet(sc, NULL); 11568206268Sdavidch bce_dump_txbd(sc, 0, NULL); 11569157642Sps bce_dump_rxbd(sc, 0, NULL); 11570218423Sdavidch bce_dump_tx_mbuf_chain(sc, 0, USABLE_TX_BD_ALLOC); 11571218423Sdavidch bce_dump_rx_mbuf_chain(sc, 0, USABLE_RX_BD_ALLOC); 11572218423Sdavidch bce_dump_pg_mbuf_chain(sc, 0, USABLE_PG_BD_ALLOC); 11573157642Sps bce_dump_l2fhdr(sc, 0, NULL); 11574176448Sdavidch bce_dump_ctx(sc, RX_CID); 11575176448Sdavidch bce_dump_ftqs(sc); 11576218423Sdavidch bce_dump_tx_chain(sc, 0, USABLE_TX_BD_ALLOC); 11577218423Sdavidch bce_dump_rx_bd_chain(sc, 0, USABLE_RX_BD_ALLOC); 11578218423Sdavidch bce_dump_pg_chain(sc, 0, USABLE_PG_BD_ALLOC); 11579157642Sps bce_dump_status_block(sc); 11580157642Sps bce_dump_stats_block(sc); 11581157642Sps bce_dump_driver_state(sc); 11582157642Sps bce_dump_hw_state(sc); 11583170810Sdavidch bce_dump_bc_state(sc); 11584179771Sdavidch bce_dump_txp_state(sc, 0); 11585179771Sdavidch bce_dump_rxp_state(sc, 0); 11586179771Sdavidch bce_dump_tpat_state(sc, 0); 11587179771Sdavidch bce_dump_cp_state(sc, 0); 11588182293Sdavidch bce_dump_com_state(sc, 0); 11589206268Sdavidch bce_dump_rv2p_state(sc); 11590179695Sdavidch bce_dump_pgbd(sc, 0, NULL); 11591157642Sps } 11592157642Sps 11593176448Sdavidch bce_dump_status_block(sc); 11594157642Sps bce_dump_driver_state(sc); 11595178132Sdavidch 11596157642Sps /* Call the debugger. */ 11597157642Sps breakpoint(); 11598157642Sps} 11599157642Sps#endif 11600