162387023Sdduvall /* 262387023Sdduvall * CDDL HEADER START 362387023Sdduvall * 462387023Sdduvall * The contents of this file are subject to the terms of the 562387023Sdduvall * Common Development and Distribution License (the "License"). 662387023Sdduvall * You may not use this file except in compliance with the License. 762387023Sdduvall * 862387023Sdduvall * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 962387023Sdduvall * or http://www.opensolaris.org/os/licensing. 1062387023Sdduvall * See the License for the specific language governing permissions 1162387023Sdduvall * and limitations under the License. 1262387023Sdduvall * 1362387023Sdduvall * When distributing Covered Code, include this CDDL HEADER in each 1462387023Sdduvall * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1562387023Sdduvall * If applicable, add the following below this CDDL HEADER, with the 1662387023Sdduvall * fields enclosed by brackets "[]" replaced with your own identifying 1762387023Sdduvall * information: Portions Copyright [yyyy] [name of copyright owner] 1862387023Sdduvall * 1962387023Sdduvall * CDDL HEADER END 2062387023Sdduvall */ 2162387023Sdduvall 2262387023Sdduvall /* 23087a28d1SDavid Gwynne * Copyright (c) 2010-2013, by Broadcom, Inc. 24087a28d1SDavid Gwynne * All Rights Reserved. 2562387023Sdduvall */ 2662387023Sdduvall 27d66f292dSGarrett D'Amore /* 28087a28d1SDavid Gwynne * Copyright (c) 2002, 2010, Oracle and/or its affiliates. 29087a28d1SDavid Gwynne * All rights reserved. 30*76a3936eSHans Rosenfeld * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 31d66f292dSGarrett D'Amore */ 32d66f292dSGarrett D'Amore 33f724721bSzh199473 #include "bge_impl.h" 3462387023Sdduvall 3562387023Sdduvall #define PIO_ADDR(bgep, offset) ((void *)((caddr_t)(bgep)->io_regs+(offset))) 36087a28d1SDavid Gwynne #define APE_ADDR(bgep, offset) ((void *)((caddr_t)(bgep)->ape_regs+(offset))) 3762387023Sdduvall 3862387023Sdduvall /* 3962387023Sdduvall * Future features ... ? 4062387023Sdduvall */ 41256e438eSzh199473 #define BGE_CFG_IO8 1 /* 8/16-bit cfg space BIS/BIC */ 42a4de4ba2Sml149210 #define BGE_IND_IO32 1 /* indirect access code */ 4362387023Sdduvall #define BGE_SEE_IO32 1 /* SEEPROM access code */ 4462387023Sdduvall #define BGE_FLASH_IO32 1 /* FLASH access code */ 4562387023Sdduvall 4662387023Sdduvall /* 4762387023Sdduvall * BGE MSI tunable: 4862387023Sdduvall * 4962387023Sdduvall * By default MSI is enabled on all supported platforms but it is disabled 5062387023Sdduvall * for some Broadcom chips due to known MSI hardware issues. Currently MSI 5162387023Sdduvall * is enabled only for 5714C A2 and 5715C A2 broadcom chips. 5262387023Sdduvall */ 5362387023Sdduvall boolean_t bge_enable_msi = B_TRUE; 5462387023Sdduvall 5562387023Sdduvall /* 565952d588Szh199473 * PCI-X/PCI-E relaxed ordering tunable for OS/Nexus driver 575952d588Szh199473 */ 585952d588Szh199473 boolean_t bge_relaxed_ordering = B_TRUE; 595952d588Szh199473 605952d588Szh199473 /* 6162387023Sdduvall * Patchable globals: 6262387023Sdduvall * 6362387023Sdduvall * bge_autorecover 6462387023Sdduvall * Enables/disables automatic recovery after fault detection 6562387023Sdduvall * 6662387023Sdduvall * bge_mlcr_default 6762387023Sdduvall * Value to program into the MLCR; controls the chip's GPIO pins 6862387023Sdduvall * 6962387023Sdduvall * bge_dma_{rd,wr}prio 7062387023Sdduvall * Relative priorities of DMA reads & DMA writes respectively. 7162387023Sdduvall * These may each be patched to any value 0-3. Equal values 7262387023Sdduvall * will give "fair" (round-robin) arbitration for PCI access. 7362387023Sdduvall * Unequal values will give one or the other function priority. 7462387023Sdduvall * 7562387023Sdduvall * bge_dma_rwctrl 7662387023Sdduvall * Value to put in the Read/Write DMA control register. See 7762387023Sdduvall * the Broadcom PRM for things you can fiddle with in this 7862387023Sdduvall * register ... 7962387023Sdduvall * 8062387023Sdduvall * bge_{tx,rx}_{count,ticks}_{norm,intr} 8162387023Sdduvall * Send/receive interrupt coalescing parameters. Counts are 8262387023Sdduvall * #s of descriptors, ticks are in microseconds. *norm* values 8362387023Sdduvall * apply between status updates/interrupts; the *intr* values 8462387023Sdduvall * refer to the 'during-interrupt' versions - see the PRM. 8562387023Sdduvall * 8662387023Sdduvall * NOTE: these values have been determined by measurement. They 8762387023Sdduvall * differ significantly from the values recommended in the PRM. 8862387023Sdduvall */ 8962387023Sdduvall static uint32_t bge_autorecover = 1; 9062387023Sdduvall static uint32_t bge_mlcr_default_5714 = MLCR_DEFAULT_5714; 9162387023Sdduvall 9262387023Sdduvall static uint32_t bge_dma_rdprio = 1; 9362387023Sdduvall static uint32_t bge_dma_wrprio = 0; 9462387023Sdduvall static uint32_t bge_dma_rwctrl = PDRWCR_VAR_DEFAULT; 9562387023Sdduvall static uint32_t bge_dma_rwctrl_5721 = PDRWCR_VAR_5721; 9662387023Sdduvall static uint32_t bge_dma_rwctrl_5714 = PDRWCR_VAR_5714; 9762387023Sdduvall static uint32_t bge_dma_rwctrl_5715 = PDRWCR_VAR_5715; 9862387023Sdduvall 9962387023Sdduvall uint32_t bge_rx_ticks_norm = 128; 100087a28d1SDavid Gwynne uint32_t bge_tx_ticks_norm = 512; 10162387023Sdduvall uint32_t bge_rx_count_norm = 8; 10262387023Sdduvall uint32_t bge_tx_count_norm = 128; 10362387023Sdduvall 10462387023Sdduvall static uint32_t bge_rx_ticks_intr = 128; 10562387023Sdduvall static uint32_t bge_tx_ticks_intr = 0; /* 8 for FJ2+ !?!? */ 10662387023Sdduvall static uint32_t bge_rx_count_intr = 2; 10762387023Sdduvall static uint32_t bge_tx_count_intr = 0; 10862387023Sdduvall 10962387023Sdduvall /* 11062387023Sdduvall * Memory pool configuration parameters. 11162387023Sdduvall * 11262387023Sdduvall * These are generally specific to each member of the chip family, since 11362387023Sdduvall * each one may have a different memory size/configuration. 11462387023Sdduvall * 11562387023Sdduvall * Setting the mbuf pool length for a specific type of chip to 0 inhibits 11662387023Sdduvall * the driver from programming the various registers; instead they are left 11762387023Sdduvall * at their hardware defaults. This is the preferred option for later chips 11862387023Sdduvall * (5705+), whereas the older chips *required* these registers to be set, 11962387023Sdduvall * since the h/w default was 0 ;-( 12062387023Sdduvall */ 12162387023Sdduvall static uint32_t bge_mbuf_pool_base = MBUF_POOL_BASE_DEFAULT; 12262387023Sdduvall static uint32_t bge_mbuf_pool_base_5704 = MBUF_POOL_BASE_5704; 12362387023Sdduvall static uint32_t bge_mbuf_pool_base_5705 = MBUF_POOL_BASE_5705; 12462387023Sdduvall static uint32_t bge_mbuf_pool_base_5721 = MBUF_POOL_BASE_5721; 12562387023Sdduvall static uint32_t bge_mbuf_pool_len = MBUF_POOL_LENGTH_DEFAULT; 12662387023Sdduvall static uint32_t bge_mbuf_pool_len_5704 = MBUF_POOL_LENGTH_5704; 12762387023Sdduvall static uint32_t bge_mbuf_pool_len_5705 = 0; /* use h/w default */ 12862387023Sdduvall static uint32_t bge_mbuf_pool_len_5721 = 0; 12962387023Sdduvall 13062387023Sdduvall /* 13162387023Sdduvall * Various high and low water marks, thresholds, etc ... 13262387023Sdduvall * 13362387023Sdduvall * Note: these are taken from revision 7 of the PRM, and some are different 13462387023Sdduvall * from both the values in earlier PRMs *and* those determined experimentally 13562387023Sdduvall * and used in earlier versions of this driver ... 13662387023Sdduvall */ 13762387023Sdduvall static uint32_t bge_mbuf_hi_water = MBUF_HIWAT_DEFAULT; 13862387023Sdduvall static uint32_t bge_mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_DEFAULT; 13962387023Sdduvall static uint32_t bge_mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_DEFAULT; 14062387023Sdduvall 14162387023Sdduvall static uint32_t bge_dmad_lo_water = DMAD_POOL_LOWAT_DEFAULT; 14262387023Sdduvall static uint32_t bge_dmad_hi_water = DMAD_POOL_HIWAT_DEFAULT; 14362387023Sdduvall static uint32_t bge_lowat_recv_frames = LOWAT_MAX_RECV_FRAMES_DEFAULT; 14462387023Sdduvall 14562387023Sdduvall static uint32_t bge_replenish_std = STD_RCV_BD_REPLENISH_DEFAULT; 14662387023Sdduvall static uint32_t bge_replenish_mini = MINI_RCV_BD_REPLENISH_DEFAULT; 14762387023Sdduvall static uint32_t bge_replenish_jumbo = JUMBO_RCV_BD_REPLENISH_DEFAULT; 14862387023Sdduvall 14962387023Sdduvall static uint32_t bge_watchdog_count = 1 << 16; 15062387023Sdduvall static uint16_t bge_dma_miss_limit = 20; 15162387023Sdduvall 15262387023Sdduvall static uint32_t bge_stop_start_on_sync = 0; 15362387023Sdduvall 15462387023Sdduvall /* 155a4de4ba2Sml149210 * bge_intr_max_loop controls the maximum loop number within bge_intr. 156a4de4ba2Sml149210 * When loading NIC with heavy network traffic, it is useful. 157a4de4ba2Sml149210 * Increasing this value could have positive effect to throughput, 158a4de4ba2Sml149210 * but it might also increase ticks of a bge ISR stick on CPU, which might 159a4de4ba2Sml149210 * lead to bad UI interactive experience. So tune this with caution. 160a4de4ba2Sml149210 */ 161a4de4ba2Sml149210 static int bge_intr_max_loop = 1; 162a4de4ba2Sml149210 163a4de4ba2Sml149210 /* 16462387023Sdduvall * ========== Low-level chip & ring buffer manipulation ========== 16562387023Sdduvall */ 16662387023Sdduvall 16762387023Sdduvall #define BGE_DBG BGE_DBG_REGS /* debug flag for this code */ 16862387023Sdduvall 16962387023Sdduvall 17062387023Sdduvall /* 17162387023Sdduvall * Config space read-modify-write routines 17262387023Sdduvall */ 17362387023Sdduvall 17462387023Sdduvall #if BGE_CFG_IO8 17562387023Sdduvall 17662387023Sdduvall static void bge_cfg_clr16(bge_t *bgep, bge_regno_t regno, uint16_t bits); 17762387023Sdduvall #pragma inline(bge_cfg_clr16) 17862387023Sdduvall 17962387023Sdduvall static void 18062387023Sdduvall bge_cfg_clr16(bge_t *bgep, bge_regno_t regno, uint16_t bits) 18162387023Sdduvall { 18262387023Sdduvall uint16_t regval; 18362387023Sdduvall 18462387023Sdduvall BGE_TRACE(("bge_cfg_clr16($%p, 0x%lx, 0x%x)", 18562387023Sdduvall (void *)bgep, regno, bits)); 18662387023Sdduvall 18762387023Sdduvall regval = pci_config_get16(bgep->cfg_handle, regno); 18862387023Sdduvall 18962387023Sdduvall BGE_DEBUG(("bge_cfg_clr16($%p, 0x%lx, 0x%x): 0x%x => 0x%x", 19062387023Sdduvall (void *)bgep, regno, bits, regval, regval & ~bits)); 19162387023Sdduvall 19262387023Sdduvall regval &= ~bits; 19362387023Sdduvall pci_config_put16(bgep->cfg_handle, regno, regval); 19462387023Sdduvall } 19562387023Sdduvall 19662387023Sdduvall #endif /* BGE_CFG_IO8 */ 19762387023Sdduvall 19862387023Sdduvall static void bge_cfg_clr32(bge_t *bgep, bge_regno_t regno, uint32_t bits); 19962387023Sdduvall #pragma inline(bge_cfg_clr32) 20062387023Sdduvall 20162387023Sdduvall static void 20262387023Sdduvall bge_cfg_clr32(bge_t *bgep, bge_regno_t regno, uint32_t bits) 20362387023Sdduvall { 20462387023Sdduvall uint32_t regval; 20562387023Sdduvall 20662387023Sdduvall BGE_TRACE(("bge_cfg_clr32($%p, 0x%lx, 0x%x)", 20762387023Sdduvall (void *)bgep, regno, bits)); 20862387023Sdduvall 20962387023Sdduvall regval = pci_config_get32(bgep->cfg_handle, regno); 21062387023Sdduvall 21162387023Sdduvall BGE_DEBUG(("bge_cfg_clr32($%p, 0x%lx, 0x%x): 0x%x => 0x%x", 21262387023Sdduvall (void *)bgep, regno, bits, regval, regval & ~bits)); 21362387023Sdduvall 21462387023Sdduvall regval &= ~bits; 21562387023Sdduvall pci_config_put32(bgep->cfg_handle, regno, regval); 21662387023Sdduvall } 21762387023Sdduvall 21862387023Sdduvall #if BGE_IND_IO32 21962387023Sdduvall 22062387023Sdduvall /* 22162387023Sdduvall * Indirect access to registers & RISC scratchpads, using config space 22262387023Sdduvall * accesses only. 22362387023Sdduvall * 22462387023Sdduvall * This isn't currently used, but someday we might want to use it for 22562387023Sdduvall * restoring the Subsystem Device/Vendor registers (which aren't directly 22662387023Sdduvall * writable in Config Space), or for downloading firmware into the RISCs 22762387023Sdduvall * 22862387023Sdduvall * In any case there are endian issues to be resolved before this code is 22962387023Sdduvall * enabled; the bizarre way that bytes get twisted by this chip AND by 23062387023Sdduvall * the PCI bridge in SPARC systems mean that we shouldn't enable it until 23162387023Sdduvall * it's been thoroughly tested for all access sizes on all supported 23262387023Sdduvall * architectures (SPARC *and* x86!). 23362387023Sdduvall */ 234a4de4ba2Sml149210 uint32_t bge_ind_get32(bge_t *bgep, bge_regno_t regno); 23562387023Sdduvall #pragma inline(bge_ind_get32) 23662387023Sdduvall 237a4de4ba2Sml149210 uint32_t 23862387023Sdduvall bge_ind_get32(bge_t *bgep, bge_regno_t regno) 23962387023Sdduvall { 24062387023Sdduvall uint32_t val; 24162387023Sdduvall 24262387023Sdduvall BGE_TRACE(("bge_ind_get32($%p, 0x%lx)", (void *)bgep, regno)); 24362387023Sdduvall 244dc3f9a75Syong tan - Sun Microsystems - Beijing China #ifdef __sparc 245087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 246087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 247dc3f9a75Syong tan - Sun Microsystems - Beijing China regno = LE_32(regno); 248087a28d1SDavid Gwynne } 249dc3f9a75Syong tan - Sun Microsystems - Beijing China #endif 25062387023Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_RIAAR, regno); 25162387023Sdduvall val = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_RIADR); 25262387023Sdduvall 25362387023Sdduvall BGE_DEBUG(("bge_ind_get32($%p, 0x%lx) => 0x%x", 25462387023Sdduvall (void *)bgep, regno, val)); 25562387023Sdduvall 256a4de4ba2Sml149210 val = LE_32(val); 257a4de4ba2Sml149210 25862387023Sdduvall return (val); 25962387023Sdduvall } 26062387023Sdduvall 261a4de4ba2Sml149210 void bge_ind_put32(bge_t *bgep, bge_regno_t regno, uint32_t val); 26262387023Sdduvall #pragma inline(bge_ind_put32) 26362387023Sdduvall 264a4de4ba2Sml149210 void 26562387023Sdduvall bge_ind_put32(bge_t *bgep, bge_regno_t regno, uint32_t val) 26662387023Sdduvall { 26762387023Sdduvall BGE_TRACE(("bge_ind_put32($%p, 0x%lx, 0x%x)", 26862387023Sdduvall (void *)bgep, regno, val)); 26962387023Sdduvall 270a4de4ba2Sml149210 val = LE_32(val); 271dc3f9a75Syong tan - Sun Microsystems - Beijing China #ifdef __sparc 272087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 273087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 274dc3f9a75Syong tan - Sun Microsystems - Beijing China regno = LE_32(regno); 275087a28d1SDavid Gwynne } 276dc3f9a75Syong tan - Sun Microsystems - Beijing China #endif 27762387023Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_RIAAR, regno); 27862387023Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_RIADR, val); 27962387023Sdduvall } 28062387023Sdduvall 28162387023Sdduvall #endif /* BGE_IND_IO32 */ 28262387023Sdduvall 28362387023Sdduvall #if BGE_DEBUGGING 28462387023Sdduvall 28562387023Sdduvall static void bge_pci_check(bge_t *bgep); 28662387023Sdduvall #pragma no_inline(bge_pci_check) 28762387023Sdduvall 28862387023Sdduvall static void 28962387023Sdduvall bge_pci_check(bge_t *bgep) 29062387023Sdduvall { 29162387023Sdduvall uint16_t pcistatus; 29262387023Sdduvall 29362387023Sdduvall pcistatus = pci_config_get16(bgep->cfg_handle, PCI_CONF_STAT); 29462387023Sdduvall if ((pcistatus & (PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB)) != 0) 29562387023Sdduvall BGE_DEBUG(("bge_pci_check($%p): PCI status 0x%x", 29662387023Sdduvall (void *)bgep, pcistatus)); 29762387023Sdduvall } 29862387023Sdduvall 29962387023Sdduvall #endif /* BGE_DEBUGGING */ 30062387023Sdduvall 30162387023Sdduvall /* 30262387023Sdduvall * Perform first-stage chip (re-)initialisation, using only config-space 30362387023Sdduvall * accesses: 30462387023Sdduvall * 30562387023Sdduvall * + Read the vendor/device/revision/subsystem/cache-line-size registers, 30662387023Sdduvall * returning the data in the structure pointed to by <idp>. 30762387023Sdduvall * + Configure the target-mode endianness (swap) options. 30862387023Sdduvall * + Disable interrupts and enable Memory Space accesses. 30962387023Sdduvall * + Enable or disable Bus Mastering according to the <enable_dma> flag. 31062387023Sdduvall * 31162387023Sdduvall * This sequence is adapted from Broadcom document 570X-PG102-R, 31262387023Sdduvall * page 102, steps 1-3, 6-8 and 11-13. The omitted parts of the sequence 31362387023Sdduvall * are 4 and 5 (Reset Core and wait) which are handled elsewhere. 31462387023Sdduvall * 31562387023Sdduvall * This function MUST be called before any non-config-space accesses 31662387023Sdduvall * are made; on this first call <enable_dma> is B_FALSE, and it 31762387023Sdduvall * effectively performs steps 3-1(!) of the initialisation sequence 31862387023Sdduvall * (the rest are not required but should be harmless). 31962387023Sdduvall * 320256e438eSzh199473 * It MUST also be called after a chip reset, as this disables 32162387023Sdduvall * Memory Space cycles! In this case, <enable_dma> is B_TRUE, and 32262387023Sdduvall * it is effectively performing steps 6-8. 32362387023Sdduvall */ 32462387023Sdduvall void bge_chip_cfg_init(bge_t *bgep, chip_id_t *cidp, boolean_t enable_dma); 32562387023Sdduvall #pragma no_inline(bge_chip_cfg_init) 32662387023Sdduvall 32762387023Sdduvall void 32862387023Sdduvall bge_chip_cfg_init(bge_t *bgep, chip_id_t *cidp, boolean_t enable_dma) 32962387023Sdduvall { 33062387023Sdduvall ddi_acc_handle_t handle; 33162387023Sdduvall uint16_t command; 33262387023Sdduvall uint32_t mhcr; 333087a28d1SDavid Gwynne uint32_t prodid; 334087a28d1SDavid Gwynne uint32_t pci_state; 33562387023Sdduvall uint16_t value16; 33662387023Sdduvall int i; 33762387023Sdduvall 33862387023Sdduvall BGE_TRACE(("bge_chip_cfg_init($%p, $%p, %d)", 33962387023Sdduvall (void *)bgep, (void *)cidp, enable_dma)); 34062387023Sdduvall 34162387023Sdduvall /* 34262387023Sdduvall * Step 3: save PCI cache line size and subsystem vendor ID 34362387023Sdduvall * 34462387023Sdduvall * Read all the config-space registers that characterise the 34562387023Sdduvall * chip, specifically vendor/device/revision/subsystem vendor 34662387023Sdduvall * and subsystem device id. We expect (but don't check) that 34762387023Sdduvall * (vendor == VENDOR_ID_BROADCOM) && (device == DEVICE_ID_5704) 34862387023Sdduvall * 349256e438eSzh199473 * Also save all bus-transaction related registers (cache-line 35062387023Sdduvall * size, bus-grant/latency parameters, etc). Some of these are 35162387023Sdduvall * cleared by reset, so we'll have to restore them later. This 35262387023Sdduvall * comes from the Broadcom document 570X-PG102-R ... 35362387023Sdduvall * 35462387023Sdduvall * Note: Broadcom document 570X-PG102-R seems to be in error 35562387023Sdduvall * here w.r.t. the offsets of the Subsystem Vendor ID and 35662387023Sdduvall * Subsystem (Device) ID registers, which are the opposite way 35762387023Sdduvall * round according to the PCI standard. For good measure, we 35862387023Sdduvall * save/restore both anyway. 35962387023Sdduvall */ 36062387023Sdduvall handle = bgep->cfg_handle; 36162387023Sdduvall 362dc3f9a75Syong tan - Sun Microsystems - Beijing China /* 363dc3f9a75Syong tan - Sun Microsystems - Beijing China * For some chipsets (e.g., BCM5718), if MHCR_ENABLE_ENDIAN_BYTE_SWAP 364dc3f9a75Syong tan - Sun Microsystems - Beijing China * has been set in PCI_CONF_COMM already, we need to write the 365dc3f9a75Syong tan - Sun Microsystems - Beijing China * byte-swapped value to it. So we just write zero first for simplicity. 366dc3f9a75Syong tan - Sun Microsystems - Beijing China */ 367dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->device = pci_config_get16(handle, PCI_CONF_DEVID); 368087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 369087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 370dc3f9a75Syong tan - Sun Microsystems - Beijing China pci_config_put32(handle, PCI_CONF_BGE_MHCR, 0); 371087a28d1SDavid Gwynne } 372087a28d1SDavid Gwynne 37362387023Sdduvall mhcr = pci_config_get32(handle, PCI_CONF_BGE_MHCR); 374087a28d1SDavid Gwynne cidp->asic_rev = (mhcr & MHCR_CHIP_REV_MASK); 375087a28d1SDavid Gwynne cidp->asic_rev_prod_id = 0; 376087a28d1SDavid Gwynne if ((cidp->asic_rev & 0xf0000000) == CHIP_ASIC_REV_USE_PROD_ID_REG) { 377087a28d1SDavid Gwynne prodid = CHIP_ASIC_REV_PROD_ID_REG; 378087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 379087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 380087a28d1SDavid Gwynne prodid = CHIP_ASIC_REV_PROD_ID_GEN2_REG; 381087a28d1SDavid Gwynne } 382087a28d1SDavid Gwynne cidp->asic_rev_prod_id = pci_config_get32(handle, prodid); 383087a28d1SDavid Gwynne } 384087a28d1SDavid Gwynne 38562387023Sdduvall cidp->businfo = pci_config_get32(handle, PCI_CONF_BGE_PCISTATE); 38662387023Sdduvall cidp->command = pci_config_get16(handle, PCI_CONF_COMM); 38762387023Sdduvall 38862387023Sdduvall cidp->vendor = pci_config_get16(handle, PCI_CONF_VENID); 38962387023Sdduvall cidp->subven = pci_config_get16(handle, PCI_CONF_SUBVENID); 39062387023Sdduvall cidp->subdev = pci_config_get16(handle, PCI_CONF_SUBSYSID); 39162387023Sdduvall cidp->revision = pci_config_get8(handle, PCI_CONF_REVID); 39262387023Sdduvall cidp->clsize = pci_config_get8(handle, PCI_CONF_CACHE_LINESZ); 39362387023Sdduvall cidp->latency = pci_config_get8(handle, PCI_CONF_LATENCY_TIMER); 39462387023Sdduvall 395087a28d1SDavid Gwynne /* 5717 C0 is treated just like 5720 A0 */ 396087a28d1SDavid Gwynne if (pci_config_get16(bgep->cfg_handle, PCI_CONF_DEVID) == 397087a28d1SDavid Gwynne DEVICE_ID_5717_C0) { 398087a28d1SDavid Gwynne cidp->device = DEVICE_ID_5720; 399087a28d1SDavid Gwynne } 400087a28d1SDavid Gwynne 40162387023Sdduvall BGE_DEBUG(("bge_chip_cfg_init: %s bus is %s and %s; #INTA is %s", 40262387023Sdduvall cidp->businfo & PCISTATE_BUS_IS_PCI ? "PCI" : "PCI-X", 40362387023Sdduvall cidp->businfo & PCISTATE_BUS_IS_FAST ? "fast" : "slow", 40462387023Sdduvall cidp->businfo & PCISTATE_BUS_IS_32_BIT ? "narrow" : "wide", 40562387023Sdduvall cidp->businfo & PCISTATE_INTA_STATE ? "high" : "low")); 40662387023Sdduvall BGE_DEBUG(("bge_chip_cfg_init: vendor 0x%x device 0x%x revision 0x%x", 40762387023Sdduvall cidp->vendor, cidp->device, cidp->revision)); 40862387023Sdduvall BGE_DEBUG(("bge_chip_cfg_init: subven 0x%x subdev 0x%x asic_rev 0x%x", 40962387023Sdduvall cidp->subven, cidp->subdev, cidp->asic_rev)); 41062387023Sdduvall BGE_DEBUG(("bge_chip_cfg_init: clsize %d latency %d command 0x%x", 41162387023Sdduvall cidp->clsize, cidp->latency, cidp->command)); 41262387023Sdduvall 41362387023Sdduvall /* 41462387023Sdduvall * Step 2 (also step 6): disable and clear interrupts. 41562387023Sdduvall * Steps 11-13: configure PIO endianness options, and enable 41662387023Sdduvall * indirect register access. We'll also select any other 417256e438eSzh199473 * options controlled by the MHCR (e.g. tagged status, mask 41862387023Sdduvall * interrupt mode) at this stage ... 41962387023Sdduvall * 42062387023Sdduvall * Note: internally, the chip is 64-bit and BIG-endian, but 42162387023Sdduvall * since it talks to the host over a (LITTLE-endian) PCI bus, 42262387023Sdduvall * it normally swaps bytes around at the PCI interface. 42362387023Sdduvall * However, the PCI host bridge on SPARC systems normally 42462387023Sdduvall * swaps the byte lanes around too, since SPARCs are also 42562387023Sdduvall * BIG-endian. So it turns out that on SPARC, the right 42662387023Sdduvall * option is to tell the chip to swap (and the host bridge 42762387023Sdduvall * will swap back again), whereas on x86 we ask the chip 42862387023Sdduvall * NOT to swap, so the natural little-endianness of the 42962387023Sdduvall * PCI bus is assumed. Then the only thing that doesn't 43062387023Sdduvall * automatically work right is access to an 8-byte register 43162387023Sdduvall * by a little-endian host; but we don't want to set the 43262387023Sdduvall * MHCR_ENABLE_REGISTER_WORD_SWAP bit because then 4-byte 43362387023Sdduvall * accesses don't go where expected ;-( So we live with 43462387023Sdduvall * that, and perform word-swaps in software in the few cases 43562387023Sdduvall * where a chip register is defined as an 8-byte value -- 43662387023Sdduvall * see the code below for details ... 43762387023Sdduvall * 43862387023Sdduvall * Note: the meaning of the 'MASK_INTERRUPT_MODE' bit isn't 43962387023Sdduvall * very clear in the register description in the PRM, but 44062387023Sdduvall * Broadcom document 570X-PG104-R page 248 explains a little 44162387023Sdduvall * more (under "Broadcom Mask Mode"). The bit changes the way 44262387023Sdduvall * the MASK_PCI_INT_OUTPUT bit works: with MASK_INTERRUPT_MODE 44362387023Sdduvall * clear, the chip interprets MASK_PCI_INT_OUTPUT in the same 44462387023Sdduvall * way as the 5700 did, which isn't very convenient. Setting 44562387023Sdduvall * the MASK_INTERRUPT_MODE bit makes the MASK_PCI_INT_OUTPUT 44662387023Sdduvall * bit do just what its name says -- MASK the PCI #INTA output 44762387023Sdduvall * (i.e. deassert the signal at the pin) leaving all internal 44862387023Sdduvall * state unchanged. This is much more convenient for our 44962387023Sdduvall * interrupt handler, so we set MASK_INTERRUPT_MODE here. 45062387023Sdduvall * 45162387023Sdduvall * Note: the inconvenient semantics of the interrupt mailbox 45262387023Sdduvall * (nonzero disables and acknowledges/clears the interrupt, 45362387023Sdduvall * zero enables AND CLEARS it) would make race conditions 45462387023Sdduvall * likely in the interrupt handler: 45562387023Sdduvall * 45662387023Sdduvall * (1) acknowledge & disable interrupts 45762387023Sdduvall * (2) while (more to do) 45862387023Sdduvall * process packets 45962387023Sdduvall * (3) enable interrupts -- also clears pending 46062387023Sdduvall * 46162387023Sdduvall * If the chip received more packets and internally generated 46262387023Sdduvall * an interrupt between the check at (2) and the mbox write 46362387023Sdduvall * at (3), this interrupt would be lost :-( 46462387023Sdduvall * 46562387023Sdduvall * The best way to avoid this is to use TAGGED STATUS mode, 46662387023Sdduvall * where the chip includes a unique tag in each status block 46762387023Sdduvall * update, and the host, when re-enabling interrupts, passes 46862387023Sdduvall * the last tag it saw back to the chip; then the chip can 46962387023Sdduvall * see whether the host is truly up to date, and regenerate 47062387023Sdduvall * its interrupt if not. 47162387023Sdduvall */ 47262387023Sdduvall mhcr = MHCR_ENABLE_INDIRECT_ACCESS | 473087a28d1SDavid Gwynne MHCR_ENABLE_PCI_STATE_RW | 47462387023Sdduvall MHCR_ENABLE_TAGGED_STATUS_MODE | 47562387023Sdduvall MHCR_MASK_INTERRUPT_MODE | 47662387023Sdduvall MHCR_CLEAR_INTERRUPT_INTA; 47762387023Sdduvall if (bgep->intr_type == DDI_INTR_TYPE_FIXED) 47862387023Sdduvall mhcr |= MHCR_MASK_PCI_INT_OUTPUT; 47962387023Sdduvall 48062387023Sdduvall #ifdef _BIG_ENDIAN 48162387023Sdduvall mhcr |= MHCR_ENABLE_ENDIAN_WORD_SWAP | MHCR_ENABLE_ENDIAN_BYTE_SWAP; 48262387023Sdduvall #endif /* _BIG_ENDIAN */ 48362387023Sdduvall pci_config_put32(handle, PCI_CONF_BGE_MHCR, mhcr); 48462387023Sdduvall 48567f02347Srandyf #ifdef BGE_IPMI_ASF 48667f02347Srandyf bgep->asf_wordswapped = B_FALSE; 48767f02347Srandyf #endif 488087a28d1SDavid Gwynne 489087a28d1SDavid Gwynne pci_state = (PCISTATE_EXT_ROM_ENABLE | PCISTATE_EXT_ROM_RETRY); 490087a28d1SDavid Gwynne /* allow reads and writes to the APE register and memory space */ 491087a28d1SDavid Gwynne if (bgep->ape_enabled) { 492087a28d1SDavid Gwynne pci_state |= PCISTATE_ALLOW_APE_CTLSPC_WR | 493087a28d1SDavid Gwynne PCISTATE_ALLOW_APE_SHMEM_WR | PCISTATE_ALLOW_APE_PSPACE_WR; 494087a28d1SDavid Gwynne } 495087a28d1SDavid Gwynne pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_PCISTATE, pci_state); 496087a28d1SDavid Gwynne 49762387023Sdduvall /* 49862387023Sdduvall * Step 1 (also step 7): Enable PCI Memory Space accesses 49962387023Sdduvall * Disable Memory Write/Invalidate 50062387023Sdduvall * Enable or disable Bus Mastering 50162387023Sdduvall * 50262387023Sdduvall * Note that all other bits are taken from the original value saved 50362387023Sdduvall * the first time through here, rather than from the current register 50462387023Sdduvall * value, 'cos that will have been cleared by a soft RESET since. 50562387023Sdduvall * In this way we preserve the OBP/nexus-parent's preferred settings 50662387023Sdduvall * of the parity-error and system-error enable bits across multiple 50762387023Sdduvall * chip RESETs. 50862387023Sdduvall */ 50962387023Sdduvall command = bgep->chipid.command | PCI_COMM_MAE; 51062387023Sdduvall command &= ~(PCI_COMM_ME|PCI_COMM_MEMWR_INVAL); 51162387023Sdduvall if (enable_dma) 51262387023Sdduvall command |= PCI_COMM_ME; 51362387023Sdduvall /* 51462387023Sdduvall * on BCM5714 revision A0, false parity error gets generated 515256e438eSzh199473 * due to a logic bug. Provide a workaround by disabling parity 51662387023Sdduvall * error. 51762387023Sdduvall */ 51862387023Sdduvall if (((cidp->device == DEVICE_ID_5714C) || 51962387023Sdduvall (cidp->device == DEVICE_ID_5714S)) && 52062387023Sdduvall (cidp->revision == REVISION_ID_5714_A0)) { 52162387023Sdduvall command &= ~PCI_COMM_PARITY_DETECT; 52262387023Sdduvall } 52362387023Sdduvall pci_config_put16(handle, PCI_CONF_COMM, command); 52462387023Sdduvall 52562387023Sdduvall /* 52662387023Sdduvall * On some PCI-E device, there were instances when 52762387023Sdduvall * the device was still link training. 52862387023Sdduvall */ 52962387023Sdduvall if (bgep->chipid.pci_type == BGE_PCI_E) { 53062387023Sdduvall i = 0; 53162387023Sdduvall value16 = pci_config_get16(handle, PCI_CONF_COMM); 53262387023Sdduvall while ((value16 != command) && (i < 100)) { 53362387023Sdduvall drv_usecwait(200); 53462387023Sdduvall value16 = pci_config_get16(handle, PCI_CONF_COMM); 53562387023Sdduvall ++i; 53662387023Sdduvall } 53762387023Sdduvall } 53862387023Sdduvall 53962387023Sdduvall /* 54062387023Sdduvall * Clear any remaining error status bits 54162387023Sdduvall */ 54262387023Sdduvall pci_config_put16(handle, PCI_CONF_STAT, ~0); 54362387023Sdduvall 54462387023Sdduvall /* 545990f1831Svivek * Do following if and only if the device is NOT BCM5714C OR 546990f1831Svivek * BCM5715C 547990f1831Svivek */ 548990f1831Svivek if (!((cidp->device == DEVICE_ID_5714C) || 549990f1831Svivek (cidp->device == DEVICE_ID_5715C))) { 550990f1831Svivek /* 55162387023Sdduvall * Make sure these indirect-access registers are sane 55262387023Sdduvall * rather than random after power-up or reset 55362387023Sdduvall */ 55462387023Sdduvall pci_config_put32(handle, PCI_CONF_BGE_RIAAR, 0); 55562387023Sdduvall pci_config_put32(handle, PCI_CONF_BGE_MWBAR, 0); 55662387023Sdduvall } 557256e438eSzh199473 /* 558256e438eSzh199473 * Step 8: Disable PCI-X/PCI-E Relaxed Ordering 559256e438eSzh199473 */ 560256e438eSzh199473 bge_cfg_clr16(bgep, PCIX_CONF_COMM, PCIX_COMM_RELAXED); 561256e438eSzh199473 56200d84294Syong tan - Sun Microsystems - Beijing China if (cidp->pci_type == BGE_PCI_E) { 56300d84294Syong tan - Sun Microsystems - Beijing China if (DEVICE_5723_SERIES_CHIPSETS(bgep)) { 56400d84294Syong tan - Sun Microsystems - Beijing China bge_cfg_clr16(bgep, PCI_CONF_DEV_CTRL_5723, 56500d84294Syong tan - Sun Microsystems - Beijing China DEV_CTRL_NO_SNOOP | DEV_CTRL_RELAXED); 566087a28d1SDavid Gwynne } else if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 567087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 568087a28d1SDavid Gwynne bge_cfg_clr16(bgep, PCI_CONF_DEV_CTRL_5717, 569087a28d1SDavid Gwynne DEV_CTRL_NO_SNOOP | DEV_CTRL_RELAXED); 570087a28d1SDavid Gwynne } else { 571256e438eSzh199473 bge_cfg_clr16(bgep, PCI_CONF_DEV_CTRL, 572256e438eSzh199473 DEV_CTRL_NO_SNOOP | DEV_CTRL_RELAXED); 573990f1831Svivek } 57400d84294Syong tan - Sun Microsystems - Beijing China } 575087a28d1SDavid Gwynne } 57662387023Sdduvall 57762387023Sdduvall #ifdef __amd64 57862387023Sdduvall /* 57962387023Sdduvall * Distinguish CPU types 58062387023Sdduvall * 58162387023Sdduvall * These use to distinguish AMD64 or Intel EM64T of CPU running mode. 58262387023Sdduvall * If CPU runs on Intel EM64T mode,the 64bit operation cannot works fine 58362387023Sdduvall * for PCI-Express based network interface card. This is the work-around 58462387023Sdduvall * for those nics. 58562387023Sdduvall */ 58662387023Sdduvall static boolean_t bge_get_em64t_type(void); 58762387023Sdduvall #pragma inline(bge_get_em64t_type) 58862387023Sdduvall 58962387023Sdduvall static boolean_t 59062387023Sdduvall bge_get_em64t_type(void) 59162387023Sdduvall { 59262387023Sdduvall 59362387023Sdduvall return (x86_vendor == X86_VENDOR_Intel); 59462387023Sdduvall } 59562387023Sdduvall #endif 59662387023Sdduvall 59762387023Sdduvall /* 59862387023Sdduvall * Operating register get/set access routines 59962387023Sdduvall */ 60062387023Sdduvall 60162387023Sdduvall uint32_t bge_reg_get32(bge_t *bgep, bge_regno_t regno); 60262387023Sdduvall #pragma inline(bge_reg_get32) 60362387023Sdduvall 60462387023Sdduvall uint32_t 60562387023Sdduvall bge_reg_get32(bge_t *bgep, bge_regno_t regno) 60662387023Sdduvall { 60762387023Sdduvall BGE_TRACE(("bge_reg_get32($%p, 0x%lx)", 60862387023Sdduvall (void *)bgep, regno)); 60962387023Sdduvall 61062387023Sdduvall return (ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno))); 61162387023Sdduvall } 61262387023Sdduvall 61362387023Sdduvall void bge_reg_put32(bge_t *bgep, bge_regno_t regno, uint32_t data); 61462387023Sdduvall #pragma inline(bge_reg_put32) 61562387023Sdduvall 61662387023Sdduvall void 61762387023Sdduvall bge_reg_put32(bge_t *bgep, bge_regno_t regno, uint32_t data) 61862387023Sdduvall { 61962387023Sdduvall BGE_TRACE(("bge_reg_put32($%p, 0x%lx, 0x%x)", 62062387023Sdduvall (void *)bgep, regno, data)); 62162387023Sdduvall 62262387023Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, regno), data); 62362387023Sdduvall BGE_PCICHK(bgep); 62462387023Sdduvall } 62562387023Sdduvall 62662387023Sdduvall void bge_reg_set32(bge_t *bgep, bge_regno_t regno, uint32_t bits); 62762387023Sdduvall #pragma inline(bge_reg_set32) 62862387023Sdduvall 62962387023Sdduvall void 63062387023Sdduvall bge_reg_set32(bge_t *bgep, bge_regno_t regno, uint32_t bits) 63162387023Sdduvall { 63262387023Sdduvall uint32_t regval; 63362387023Sdduvall 63462387023Sdduvall BGE_TRACE(("bge_reg_set32($%p, 0x%lx, 0x%x)", 63562387023Sdduvall (void *)bgep, regno, bits)); 63662387023Sdduvall 63762387023Sdduvall regval = bge_reg_get32(bgep, regno); 63862387023Sdduvall regval |= bits; 63962387023Sdduvall bge_reg_put32(bgep, regno, regval); 64062387023Sdduvall } 64162387023Sdduvall 64262387023Sdduvall void bge_reg_clr32(bge_t *bgep, bge_regno_t regno, uint32_t bits); 64362387023Sdduvall #pragma inline(bge_reg_clr32) 64462387023Sdduvall 64562387023Sdduvall void 64662387023Sdduvall bge_reg_clr32(bge_t *bgep, bge_regno_t regno, uint32_t bits) 64762387023Sdduvall { 64862387023Sdduvall uint32_t regval; 64962387023Sdduvall 65062387023Sdduvall BGE_TRACE(("bge_reg_clr32($%p, 0x%lx, 0x%x)", 65162387023Sdduvall (void *)bgep, regno, bits)); 65262387023Sdduvall 65362387023Sdduvall regval = bge_reg_get32(bgep, regno); 65462387023Sdduvall regval &= ~bits; 65562387023Sdduvall bge_reg_put32(bgep, regno, regval); 65662387023Sdduvall } 65762387023Sdduvall 65862387023Sdduvall static uint64_t bge_reg_get64(bge_t *bgep, bge_regno_t regno); 65962387023Sdduvall #pragma inline(bge_reg_get64) 66062387023Sdduvall 66162387023Sdduvall static uint64_t 66262387023Sdduvall bge_reg_get64(bge_t *bgep, bge_regno_t regno) 66362387023Sdduvall { 66462387023Sdduvall uint64_t regval; 66562387023Sdduvall 66662387023Sdduvall #ifdef __amd64 667087a28d1SDavid Gwynne if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 668087a28d1SDavid Gwynne bge_get_em64t_type() || 669087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 670087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 67162387023Sdduvall regval = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno + 4)); 67262387023Sdduvall regval <<= 32; 67362387023Sdduvall regval |= ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno)); 67462387023Sdduvall } else { 67562387023Sdduvall regval = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, regno)); 67662387023Sdduvall } 67700d84294Syong tan - Sun Microsystems - Beijing China #elif defined(__sparc) 678dc3f9a75Syong tan - Sun Microsystems - Beijing China if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 679087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 680087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 68100d84294Syong tan - Sun Microsystems - Beijing China regval = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno)); 68200d84294Syong tan - Sun Microsystems - Beijing China regval <<= 32; 68300d84294Syong tan - Sun Microsystems - Beijing China regval |= ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno + 4)); 68400d84294Syong tan - Sun Microsystems - Beijing China } else { 68500d84294Syong tan - Sun Microsystems - Beijing China regval = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, regno)); 68600d84294Syong tan - Sun Microsystems - Beijing China } 68762387023Sdduvall #else 68862387023Sdduvall regval = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, regno)); 68962387023Sdduvall #endif 69062387023Sdduvall 69162387023Sdduvall #ifdef _LITTLE_ENDIAN 69262387023Sdduvall regval = (regval >> 32) | (regval << 32); 69362387023Sdduvall #endif /* _LITTLE_ENDIAN */ 69462387023Sdduvall 69562387023Sdduvall BGE_TRACE(("bge_reg_get64($%p, 0x%lx) = 0x%016llx", 69662387023Sdduvall (void *)bgep, regno, regval)); 69762387023Sdduvall 69862387023Sdduvall return (regval); 69962387023Sdduvall } 70062387023Sdduvall 70162387023Sdduvall static void bge_reg_put64(bge_t *bgep, bge_regno_t regno, uint64_t data); 70262387023Sdduvall #pragma inline(bge_reg_put64) 70362387023Sdduvall 70462387023Sdduvall static void 70562387023Sdduvall bge_reg_put64(bge_t *bgep, bge_regno_t regno, uint64_t data) 70662387023Sdduvall { 70762387023Sdduvall BGE_TRACE(("bge_reg_put64($%p, 0x%lx, 0x%016llx)", 70862387023Sdduvall (void *)bgep, regno, data)); 70962387023Sdduvall 71062387023Sdduvall #ifdef _LITTLE_ENDIAN 71162387023Sdduvall data = ((data >> 32) | (data << 32)); 71262387023Sdduvall #endif /* _LITTLE_ENDIAN */ 71362387023Sdduvall 71462387023Sdduvall #ifdef __amd64 715087a28d1SDavid Gwynne if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 716087a28d1SDavid Gwynne bge_get_em64t_type() || 717087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 718087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 71962387023Sdduvall ddi_put32(bgep->io_handle, 72062387023Sdduvall PIO_ADDR(bgep, regno), (uint32_t)data); 72162387023Sdduvall BGE_PCICHK(bgep); 72262387023Sdduvall ddi_put32(bgep->io_handle, 72362387023Sdduvall PIO_ADDR(bgep, regno + 4), (uint32_t)(data >> 32)); 72462387023Sdduvall 72562387023Sdduvall } else { 72662387023Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, regno), data); 72762387023Sdduvall } 72800d84294Syong tan - Sun Microsystems - Beijing China #elif defined(__sparc) 729dc3f9a75Syong tan - Sun Microsystems - Beijing China if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 730087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 731087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 73200d84294Syong tan - Sun Microsystems - Beijing China ddi_put32(bgep->io_handle, 73300d84294Syong tan - Sun Microsystems - Beijing China PIO_ADDR(bgep, regno + 4), (uint32_t)data); 73400d84294Syong tan - Sun Microsystems - Beijing China BGE_PCICHK(bgep); 73500d84294Syong tan - Sun Microsystems - Beijing China ddi_put32(bgep->io_handle, 73600d84294Syong tan - Sun Microsystems - Beijing China PIO_ADDR(bgep, regno), (uint32_t)(data >> 32)); 73700d84294Syong tan - Sun Microsystems - Beijing China } else { 73800d84294Syong tan - Sun Microsystems - Beijing China ddi_put64(bgep->io_handle, PIO_ADDR(bgep, regno), data); 73900d84294Syong tan - Sun Microsystems - Beijing China } 74062387023Sdduvall #else 74162387023Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, regno), data); 74262387023Sdduvall #endif 74362387023Sdduvall 74462387023Sdduvall BGE_PCICHK(bgep); 74562387023Sdduvall } 74662387023Sdduvall 74762387023Sdduvall /* 74862387023Sdduvall * The DDI doesn't provide get/put functions for 128 bit data 74962387023Sdduvall * so we put RCBs out as two 64-bit chunks instead. 75062387023Sdduvall */ 75162387023Sdduvall static void bge_reg_putrcb(bge_t *bgep, bge_regno_t addr, bge_rcb_t *rcbp); 75262387023Sdduvall #pragma inline(bge_reg_putrcb) 75362387023Sdduvall 75462387023Sdduvall static void 75562387023Sdduvall bge_reg_putrcb(bge_t *bgep, bge_regno_t addr, bge_rcb_t *rcbp) 75662387023Sdduvall { 75762387023Sdduvall uint64_t *p; 75862387023Sdduvall 75962387023Sdduvall BGE_TRACE(("bge_reg_putrcb($%p, 0x%lx, 0x%016llx:%04x:%04x:%08x)", 76062387023Sdduvall (void *)bgep, addr, rcbp->host_ring_addr, 76162387023Sdduvall rcbp->max_len, rcbp->flags, rcbp->nic_ring_addr)); 76262387023Sdduvall 76362387023Sdduvall ASSERT((addr % sizeof (*rcbp)) == 0); 76462387023Sdduvall 76562387023Sdduvall p = (void *)rcbp; 76662387023Sdduvall bge_reg_put64(bgep, addr, *p++); 76762387023Sdduvall bge_reg_put64(bgep, addr+8, *p); 76862387023Sdduvall } 76962387023Sdduvall 77062387023Sdduvall void bge_mbx_put(bge_t *bgep, bge_regno_t regno, uint64_t data); 77162387023Sdduvall #pragma inline(bge_mbx_put) 77262387023Sdduvall 77362387023Sdduvall void 77462387023Sdduvall bge_mbx_put(bge_t *bgep, bge_regno_t regno, uint64_t data) 77562387023Sdduvall { 7765a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 7775a506a18Syong tan - Sun Microsystems - Beijing China regno += INTERRUPT_LP_MBOX_0_REG - INTERRUPT_MBOX_0_REG + 4; 7785a506a18Syong tan - Sun Microsystems - Beijing China 77962387023Sdduvall BGE_TRACE(("bge_mbx_put($%p, 0x%lx, 0x%016llx)", 78062387023Sdduvall (void *)bgep, regno, data)); 78162387023Sdduvall 78262387023Sdduvall /* 78362387023Sdduvall * Mailbox registers are nominally 64 bits on the 5701, but 78462387023Sdduvall * the MSW isn't used. On the 5703, they're only 32 bits 78562387023Sdduvall * anyway. So here we just write the lower(!) 32 bits - 78662387023Sdduvall * remembering that the chip is big-endian, even though the 78762387023Sdduvall * PCI bus is little-endian ... 78862387023Sdduvall */ 78962387023Sdduvall #ifdef _BIG_ENDIAN 79062387023Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, regno+4), (uint32_t)data); 79162387023Sdduvall #else 79262387023Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, regno), (uint32_t)data); 79362387023Sdduvall #endif /* _BIG_ENDIAN */ 79462387023Sdduvall BGE_PCICHK(bgep); 79562387023Sdduvall } 79662387023Sdduvall 797dca582a1Sgh162552 uint32_t bge_mbx_get(bge_t *bgep, bge_regno_t regno); 798dca582a1Sgh162552 #pragma inline(bge_mbx_get) 799dca582a1Sgh162552 800dca582a1Sgh162552 uint32_t 801dca582a1Sgh162552 bge_mbx_get(bge_t *bgep, bge_regno_t regno) 802dca582a1Sgh162552 { 803dca582a1Sgh162552 uint32_t val32; 804dca582a1Sgh162552 8055a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 8065a506a18Syong tan - Sun Microsystems - Beijing China regno += INTERRUPT_LP_MBOX_0_REG - INTERRUPT_MBOX_0_REG + 4; 8075a506a18Syong tan - Sun Microsystems - Beijing China 808dca582a1Sgh162552 BGE_TRACE(("bge_mbx_get($%p, 0x%lx)", 809dca582a1Sgh162552 (void *)bgep, regno)); 810dca582a1Sgh162552 811dca582a1Sgh162552 #ifdef _BIG_ENDIAN 812dca582a1Sgh162552 val32 = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno+4)); 813dca582a1Sgh162552 #else 814dca582a1Sgh162552 val32 = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno)); 815dca582a1Sgh162552 #endif /* _BIG_ENDIAN */ 816dca582a1Sgh162552 BGE_PCICHK(bgep); 817dca582a1Sgh162552 818dc3f9a75Syong tan - Sun Microsystems - Beijing China BGE_DEBUG(("bge_mbx_get($%p, 0x%lx) => 0x%08x", 819dc3f9a75Syong tan - Sun Microsystems - Beijing China (void *)bgep, regno, val32)); 820dc3f9a75Syong tan - Sun Microsystems - Beijing China 821dca582a1Sgh162552 return (val32); 822dca582a1Sgh162552 } 823dca582a1Sgh162552 824dca582a1Sgh162552 82562387023Sdduvall #if BGE_DEBUGGING 82662387023Sdduvall 82762387023Sdduvall void bge_led_mark(bge_t *bgep); 82862387023Sdduvall #pragma no_inline(bge_led_mark) 82962387023Sdduvall 83062387023Sdduvall void 83162387023Sdduvall bge_led_mark(bge_t *bgep) 83262387023Sdduvall { 83362387023Sdduvall uint32_t led_ctrl = LED_CONTROL_OVERRIDE_LINK | 83462387023Sdduvall LED_CONTROL_1000MBPS_LED | 83562387023Sdduvall LED_CONTROL_100MBPS_LED | 83662387023Sdduvall LED_CONTROL_10MBPS_LED; 83762387023Sdduvall 83862387023Sdduvall /* 83962387023Sdduvall * Blink all three LINK LEDs on simultaneously, then all off, 84062387023Sdduvall * then restore to automatic hardware control. This is used 84162387023Sdduvall * in laboratory testing to trigger a logic analyser or scope. 84262387023Sdduvall */ 84362387023Sdduvall bge_reg_set32(bgep, ETHERNET_MAC_LED_CONTROL_REG, led_ctrl); 84462387023Sdduvall led_ctrl ^= LED_CONTROL_OVERRIDE_LINK; 84562387023Sdduvall bge_reg_clr32(bgep, ETHERNET_MAC_LED_CONTROL_REG, led_ctrl); 84662387023Sdduvall led_ctrl = LED_CONTROL_OVERRIDE_LINK; 84762387023Sdduvall bge_reg_clr32(bgep, ETHERNET_MAC_LED_CONTROL_REG, led_ctrl); 84862387023Sdduvall } 84962387023Sdduvall 85062387023Sdduvall #endif /* BGE_DEBUGGING */ 85162387023Sdduvall 85262387023Sdduvall /* 85362387023Sdduvall * NIC on-chip memory access routines 85462387023Sdduvall * 85562387023Sdduvall * Only 32K of NIC memory is visible at a time, controlled by the 85662387023Sdduvall * Memory Window Base Address Register (in PCI config space). Once 85762387023Sdduvall * this is set, the 32K region of NIC-local memory that it refers 85862387023Sdduvall * to can be directly addressed in the upper 32K of the 64K of PCI 85962387023Sdduvall * memory space used for the device. 86062387023Sdduvall */ 86162387023Sdduvall 86262387023Sdduvall static void bge_nic_setwin(bge_t *bgep, bge_regno_t base); 86362387023Sdduvall #pragma inline(bge_nic_setwin) 86462387023Sdduvall 86562387023Sdduvall static void 86662387023Sdduvall bge_nic_setwin(bge_t *bgep, bge_regno_t base) 86762387023Sdduvall { 868990f1831Svivek chip_id_t *cidp; 869990f1831Svivek 87062387023Sdduvall BGE_TRACE(("bge_nic_setwin($%p, 0x%lx)", 87162387023Sdduvall (void *)bgep, base)); 87262387023Sdduvall 87362387023Sdduvall ASSERT((base & MWBAR_GRANULE_MASK) == 0); 874990f1831Svivek 875990f1831Svivek /* 876990f1831Svivek * Don't do repeated zero data writes, 877990f1831Svivek * if the device is BCM5714C/15C. 878990f1831Svivek */ 879990f1831Svivek cidp = &bgep->chipid; 880990f1831Svivek if ((cidp->device == DEVICE_ID_5714C) || 881990f1831Svivek (cidp->device == DEVICE_ID_5715C)) { 882990f1831Svivek if (bgep->lastWriteZeroData && (base == (bge_regno_t)0)) 883990f1831Svivek return; 884990f1831Svivek /* Adjust lastWriteZeroData */ 885990f1831Svivek bgep->lastWriteZeroData = ((base == (bge_regno_t)0) ? 886990f1831Svivek B_TRUE : B_FALSE); 887990f1831Svivek } 888dc3f9a75Syong tan - Sun Microsystems - Beijing China #ifdef __sparc 889087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 890087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 891dc3f9a75Syong tan - Sun Microsystems - Beijing China base = LE_32(base); 892087a28d1SDavid Gwynne } 893dc3f9a75Syong tan - Sun Microsystems - Beijing China #endif 89462387023Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, base); 89562387023Sdduvall } 89662387023Sdduvall 89762387023Sdduvall static uint32_t bge_nic_get32(bge_t *bgep, bge_regno_t addr); 89862387023Sdduvall #pragma inline(bge_nic_get32) 89962387023Sdduvall 90062387023Sdduvall static uint32_t 90162387023Sdduvall bge_nic_get32(bge_t *bgep, bge_regno_t addr) 90262387023Sdduvall { 90362387023Sdduvall uint32_t data; 90462387023Sdduvall 905a4de4ba2Sml149210 #if defined(BGE_IPMI_ASF) && !defined(__sparc) 90667f02347Srandyf if (bgep->asf_enabled && !bgep->asf_wordswapped) { 90767f02347Srandyf /* workaround for word swap error */ 90867f02347Srandyf if (addr & 4) 90967f02347Srandyf addr = addr - 4; 91067f02347Srandyf else 91167f02347Srandyf addr = addr + 4; 91267f02347Srandyf } 91367f02347Srandyf #endif 91467f02347Srandyf 915a4de4ba2Sml149210 #ifdef __sparc 916a4de4ba2Sml149210 data = bge_nic_read32(bgep, addr); 917a4de4ba2Sml149210 #else 91862387023Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 91962387023Sdduvall addr &= MWBAR_GRANULE_MASK; 92062387023Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 92162387023Sdduvall 92262387023Sdduvall data = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, addr)); 923a4de4ba2Sml149210 #endif 92462387023Sdduvall 92562387023Sdduvall BGE_TRACE(("bge_nic_get32($%p, 0x%lx) = 0x%08x", 92662387023Sdduvall (void *)bgep, addr, data)); 92762387023Sdduvall 92862387023Sdduvall return (data); 92962387023Sdduvall } 93062387023Sdduvall 93167f02347Srandyf void bge_nic_put32(bge_t *bgep, bge_regno_t addr, uint32_t data); 93262387023Sdduvall #pragma inline(bge_nic_put32) 93362387023Sdduvall 93467f02347Srandyf void 93562387023Sdduvall bge_nic_put32(bge_t *bgep, bge_regno_t addr, uint32_t data) 93662387023Sdduvall { 93762387023Sdduvall BGE_TRACE(("bge_nic_put32($%p, 0x%lx, 0x%08x)", 93862387023Sdduvall (void *)bgep, addr, data)); 93962387023Sdduvall 940a4de4ba2Sml149210 #if defined(BGE_IPMI_ASF) && !defined(__sparc) 94167f02347Srandyf if (bgep->asf_enabled && !bgep->asf_wordswapped) { 94267f02347Srandyf /* workaround for word swap error */ 94367f02347Srandyf if (addr & 4) 94467f02347Srandyf addr = addr - 4; 94567f02347Srandyf else 94667f02347Srandyf addr = addr + 4; 94767f02347Srandyf } 94867f02347Srandyf #endif 94967f02347Srandyf 950a4de4ba2Sml149210 #ifdef __sparc 951087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 952087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 953dc3f9a75Syong tan - Sun Microsystems - Beijing China addr = LE_32(addr); 954087a28d1SDavid Gwynne } 955a4de4ba2Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, addr); 956a4de4ba2Sml149210 data = LE_32(data); 957a4de4ba2Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWDAR, data); 958a4de4ba2Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, 0); 959a4de4ba2Sml149210 #else 96062387023Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 96162387023Sdduvall addr &= MWBAR_GRANULE_MASK; 96262387023Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 96362387023Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr), data); 96462387023Sdduvall BGE_PCICHK(bgep); 965a4de4ba2Sml149210 #endif 96662387023Sdduvall } 96762387023Sdduvall 96862387023Sdduvall static uint64_t bge_nic_get64(bge_t *bgep, bge_regno_t addr); 96962387023Sdduvall #pragma inline(bge_nic_get64) 97062387023Sdduvall 97162387023Sdduvall static uint64_t 97262387023Sdduvall bge_nic_get64(bge_t *bgep, bge_regno_t addr) 97362387023Sdduvall { 97462387023Sdduvall uint64_t data; 97562387023Sdduvall 97662387023Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 97762387023Sdduvall addr &= MWBAR_GRANULE_MASK; 97862387023Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 97962387023Sdduvall 98062387023Sdduvall #ifdef __amd64 981087a28d1SDavid Gwynne if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 982087a28d1SDavid Gwynne bge_get_em64t_type() || 983087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 984087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 985dc3f9a75Syong tan - Sun Microsystems - Beijing China data = ddi_get32(bgep->io_handle, 98600d84294Syong tan - Sun Microsystems - Beijing China PIO_ADDR(bgep, addr + 4)); 987dc3f9a75Syong tan - Sun Microsystems - Beijing China data <<= 32; 988dc3f9a75Syong tan - Sun Microsystems - Beijing China data |= ddi_get32(bgep->io_handle, PIO_ADDR(bgep, addr)); 98900d84294Syong tan - Sun Microsystems - Beijing China } else { 99000d84294Syong tan - Sun Microsystems - Beijing China data = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, addr)); 99100d84294Syong tan - Sun Microsystems - Beijing China } 99200d84294Syong tan - Sun Microsystems - Beijing China #elif defined(__sparc) 993dc3f9a75Syong tan - Sun Microsystems - Beijing China if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 994087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 995087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 99662387023Sdduvall data = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, addr)); 99762387023Sdduvall data <<= 32; 99862387023Sdduvall data |= ddi_get32(bgep->io_handle, 99962387023Sdduvall PIO_ADDR(bgep, addr + 4)); 100062387023Sdduvall } else { 100162387023Sdduvall data = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, addr)); 100262387023Sdduvall } 100362387023Sdduvall #else 100462387023Sdduvall data = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, addr)); 100562387023Sdduvall #endif 100662387023Sdduvall 100762387023Sdduvall BGE_TRACE(("bge_nic_get64($%p, 0x%lx) = 0x%016llx", 100862387023Sdduvall (void *)bgep, addr, data)); 100962387023Sdduvall 101062387023Sdduvall return (data); 101162387023Sdduvall } 101262387023Sdduvall 101362387023Sdduvall static void bge_nic_put64(bge_t *bgep, bge_regno_t addr, uint64_t data); 101462387023Sdduvall #pragma inline(bge_nic_put64) 101562387023Sdduvall 101662387023Sdduvall static void 101762387023Sdduvall bge_nic_put64(bge_t *bgep, bge_regno_t addr, uint64_t data) 101862387023Sdduvall { 101962387023Sdduvall BGE_TRACE(("bge_nic_put64($%p, 0x%lx, 0x%016llx)", 102062387023Sdduvall (void *)bgep, addr, data)); 102162387023Sdduvall 102262387023Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 102362387023Sdduvall addr &= MWBAR_GRANULE_MASK; 102462387023Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 102562387023Sdduvall 102662387023Sdduvall #ifdef __amd64 1027087a28d1SDavid Gwynne if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 1028087a28d1SDavid Gwynne bge_get_em64t_type() || 1029087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 1030087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 103162387023Sdduvall ddi_put32(bgep->io_handle, 1032dc3f9a75Syong tan - Sun Microsystems - Beijing China PIO_ADDR(bgep, addr + 4), (uint32_t)data); 103362387023Sdduvall BGE_PCICHK(bgep); 103462387023Sdduvall ddi_put32(bgep->io_handle, 1035dc3f9a75Syong tan - Sun Microsystems - Beijing China PIO_ADDR(bgep, addr), (uint32_t)(data >> 32)); 103662387023Sdduvall } else { 103762387023Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), data); 103862387023Sdduvall } 103900d84294Syong tan - Sun Microsystems - Beijing China #elif defined(__sparc) 1040dc3f9a75Syong tan - Sun Microsystems - Beijing China if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 1041087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 1042087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 104300d84294Syong tan - Sun Microsystems - Beijing China ddi_put32(bgep->io_handle, 104400d84294Syong tan - Sun Microsystems - Beijing China PIO_ADDR(bgep, addr + 4), (uint32_t)data); 104500d84294Syong tan - Sun Microsystems - Beijing China BGE_PCICHK(bgep); 104600d84294Syong tan - Sun Microsystems - Beijing China ddi_put32(bgep->io_handle, 104700d84294Syong tan - Sun Microsystems - Beijing China PIO_ADDR(bgep, addr), (uint32_t)(data >> 32)); 104800d84294Syong tan - Sun Microsystems - Beijing China } else { 104900d84294Syong tan - Sun Microsystems - Beijing China ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), data); 105000d84294Syong tan - Sun Microsystems - Beijing China } 105162387023Sdduvall #else 105262387023Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), data); 105362387023Sdduvall #endif 105462387023Sdduvall 105562387023Sdduvall BGE_PCICHK(bgep); 105662387023Sdduvall } 105762387023Sdduvall 105862387023Sdduvall /* 105962387023Sdduvall * The DDI doesn't provide get/put functions for 128 bit data 106062387023Sdduvall * so we put RCBs out as two 64-bit chunks instead. 106162387023Sdduvall */ 106262387023Sdduvall static void bge_nic_putrcb(bge_t *bgep, bge_regno_t addr, bge_rcb_t *rcbp); 106362387023Sdduvall #pragma inline(bge_nic_putrcb) 106462387023Sdduvall 106562387023Sdduvall static void 106662387023Sdduvall bge_nic_putrcb(bge_t *bgep, bge_regno_t addr, bge_rcb_t *rcbp) 106762387023Sdduvall { 106862387023Sdduvall uint64_t *p; 106962387023Sdduvall 107062387023Sdduvall BGE_TRACE(("bge_nic_putrcb($%p, 0x%lx, 0x%016llx:%04x:%04x:%08x)", 107162387023Sdduvall (void *)bgep, addr, rcbp->host_ring_addr, 107262387023Sdduvall rcbp->max_len, rcbp->flags, rcbp->nic_ring_addr)); 107362387023Sdduvall 107462387023Sdduvall ASSERT((addr % sizeof (*rcbp)) == 0); 107562387023Sdduvall 107662387023Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 107762387023Sdduvall addr &= MWBAR_GRANULE_MASK; 107862387023Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 107962387023Sdduvall 108062387023Sdduvall p = (void *)rcbp; 108162387023Sdduvall #ifdef __amd64 1082087a28d1SDavid Gwynne if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 1083087a28d1SDavid Gwynne bge_get_em64t_type() || 1084087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 1085087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 108662387023Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr), 108762387023Sdduvall (uint32_t)(*p)); 108862387023Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr + 4), 1089dc3f9a75Syong tan - Sun Microsystems - Beijing China (uint32_t)(*p++ >> 32)); 109062387023Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr + 8), 1091dc3f9a75Syong tan - Sun Microsystems - Beijing China (uint32_t)(*p)); 109262387023Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr + 12), 109362387023Sdduvall (uint32_t)(*p >> 32)); 109462387023Sdduvall 109562387023Sdduvall } else { 109662387023Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), *p++); 109762387023Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr+8), *p); 109862387023Sdduvall } 109900d84294Syong tan - Sun Microsystems - Beijing China #elif defined(__sparc) 1100dc3f9a75Syong tan - Sun Microsystems - Beijing China if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 1101087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 1102087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 110300d84294Syong tan - Sun Microsystems - Beijing China ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr + 4), 110400d84294Syong tan - Sun Microsystems - Beijing China (uint32_t)(*p)); 110500d84294Syong tan - Sun Microsystems - Beijing China ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr), 1106dc3f9a75Syong tan - Sun Microsystems - Beijing China (uint32_t)(*p++ >> 32)); 110700d84294Syong tan - Sun Microsystems - Beijing China ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr + 12), 1108dc3f9a75Syong tan - Sun Microsystems - Beijing China (uint32_t)(*p)); 110900d84294Syong tan - Sun Microsystems - Beijing China ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr + 8), 111000d84294Syong tan - Sun Microsystems - Beijing China (uint32_t)(*p >> 32)); 111100d84294Syong tan - Sun Microsystems - Beijing China } else { 111200d84294Syong tan - Sun Microsystems - Beijing China ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), *p++); 111300d84294Syong tan - Sun Microsystems - Beijing China ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr + 8), *p); 111400d84294Syong tan - Sun Microsystems - Beijing China } 111562387023Sdduvall #else 111662387023Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), *p++); 111762387023Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr + 8), *p); 111862387023Sdduvall #endif 111962387023Sdduvall 112062387023Sdduvall BGE_PCICHK(bgep); 112162387023Sdduvall } 112262387023Sdduvall 112362387023Sdduvall static void bge_nic_zero(bge_t *bgep, bge_regno_t addr, uint32_t nbytes); 112462387023Sdduvall #pragma inline(bge_nic_zero) 112562387023Sdduvall 112662387023Sdduvall static void 112762387023Sdduvall bge_nic_zero(bge_t *bgep, bge_regno_t addr, uint32_t nbytes) 112862387023Sdduvall { 112962387023Sdduvall BGE_TRACE(("bge_nic_zero($%p, 0x%lx, 0x%x)", 113062387023Sdduvall (void *)bgep, addr, nbytes)); 113162387023Sdduvall 113262387023Sdduvall ASSERT((addr & ~MWBAR_GRANULE_MASK) == 113362387023Sdduvall ((addr+nbytes) & ~MWBAR_GRANULE_MASK)); 113462387023Sdduvall 113562387023Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 113662387023Sdduvall addr &= MWBAR_GRANULE_MASK; 113762387023Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 113862387023Sdduvall 113962387023Sdduvall (void) ddi_device_zero(bgep->io_handle, PIO_ADDR(bgep, addr), 114062387023Sdduvall nbytes, 1, DDI_DATA_SZ08_ACC); 114162387023Sdduvall BGE_PCICHK(bgep); 114262387023Sdduvall } 114362387023Sdduvall 114462387023Sdduvall /* 114562387023Sdduvall * MII (PHY) register get/set access routines 114662387023Sdduvall * 114762387023Sdduvall * These use the chip's MII auto-access method, controlled by the 114862387023Sdduvall * MII Communication register at 0x044c, so the CPU doesn't have 114962387023Sdduvall * to fiddle with the individual bits. 115062387023Sdduvall */ 115162387023Sdduvall 115262387023Sdduvall #undef BGE_DBG 115362387023Sdduvall #define BGE_DBG BGE_DBG_MII /* debug flag for this code */ 115462387023Sdduvall 115562387023Sdduvall static uint16_t bge_mii_access(bge_t *bgep, bge_regno_t regno, 115662387023Sdduvall uint16_t data, uint32_t cmd); 115762387023Sdduvall #pragma no_inline(bge_mii_access) 115862387023Sdduvall 115962387023Sdduvall static uint16_t 116062387023Sdduvall bge_mii_access(bge_t *bgep, bge_regno_t regno, uint16_t data, uint32_t cmd) 116162387023Sdduvall { 116262387023Sdduvall uint32_t timeout; 116362387023Sdduvall uint32_t regval1; 116462387023Sdduvall uint32_t regval2; 116562387023Sdduvall 116662387023Sdduvall BGE_TRACE(("bge_mii_access($%p, 0x%lx, 0x%x, 0x%x)", 116762387023Sdduvall (void *)bgep, regno, data, cmd)); 116862387023Sdduvall 116962387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 117062387023Sdduvall 117162387023Sdduvall /* 117262387023Sdduvall * Assemble the command ... 117362387023Sdduvall */ 117462387023Sdduvall cmd |= data << MI_COMMS_DATA_SHIFT; 117562387023Sdduvall cmd |= regno << MI_COMMS_REGISTER_SHIFT; 117662387023Sdduvall cmd |= bgep->phy_mii_addr << MI_COMMS_ADDRESS_SHIFT; 117762387023Sdduvall cmd |= MI_COMMS_START; 117862387023Sdduvall 117962387023Sdduvall /* 118062387023Sdduvall * Wait for any command already in progress ... 118162387023Sdduvall * 118262387023Sdduvall * Note: this *shouldn't* ever find that there is a command 118362387023Sdduvall * in progress, because we already hold the <genlock> mutex. 118462387023Sdduvall * Nonetheless, we have sometimes seen the MI_COMMS_START 118562387023Sdduvall * bit set here -- it seems that the chip can initiate MII 118662387023Sdduvall * accesses internally, even with polling OFF. 118762387023Sdduvall */ 118862387023Sdduvall regval1 = regval2 = bge_reg_get32(bgep, MI_COMMS_REG); 118900d0963fSdilpreet for (timeout = 100; ; ) { 119062387023Sdduvall if ((regval2 & MI_COMMS_START) == 0) { 119162387023Sdduvall bge_reg_put32(bgep, MI_COMMS_REG, cmd); 119262387023Sdduvall break; 119362387023Sdduvall } 119462387023Sdduvall if (--timeout == 0) 119562387023Sdduvall break; 119662387023Sdduvall drv_usecwait(10); 119762387023Sdduvall regval2 = bge_reg_get32(bgep, MI_COMMS_REG); 119862387023Sdduvall } 119962387023Sdduvall 120062387023Sdduvall if (timeout == 0) 120162387023Sdduvall return ((uint16_t)~0u); 120262387023Sdduvall 120300d0963fSdilpreet if (timeout != 100) 120400d0963fSdilpreet BGE_REPORT((bgep, "bge_mii_access: cmd 0x%x -- " 120500d0963fSdilpreet "MI_COMMS_START set for %d us; 0x%x->0x%x", 120600d0963fSdilpreet cmd, 10*(100-timeout), regval1, regval2)); 120700d0963fSdilpreet 120862387023Sdduvall regval1 = bge_reg_get32(bgep, MI_COMMS_REG); 120962387023Sdduvall for (timeout = 1000; ; ) { 121062387023Sdduvall if ((regval1 & MI_COMMS_START) == 0) 121162387023Sdduvall break; 121262387023Sdduvall if (--timeout == 0) 121362387023Sdduvall break; 121462387023Sdduvall drv_usecwait(10); 121562387023Sdduvall regval1 = bge_reg_get32(bgep, MI_COMMS_REG); 121662387023Sdduvall } 121762387023Sdduvall 121862387023Sdduvall /* 121962387023Sdduvall * Drop out early if the READ FAILED bit is set -- this chip 122062387023Sdduvall * could be a 5703/4S, with a SerDes instead of a PHY! 122162387023Sdduvall */ 122262387023Sdduvall if (regval2 & MI_COMMS_READ_FAILED) 122362387023Sdduvall return ((uint16_t)~0u); 122462387023Sdduvall 122562387023Sdduvall if (timeout == 0) 122662387023Sdduvall return ((uint16_t)~0u); 122762387023Sdduvall 122862387023Sdduvall /* 122962387023Sdduvall * The PRM says to wait 5us after seeing the START bit clear 123062387023Sdduvall * and then re-read the register to get the final value of the 123162387023Sdduvall * data field, in order to avoid a race condition where the 123262387023Sdduvall * START bit is clear but the data field isn't yet valid. 123362387023Sdduvall * 123462387023Sdduvall * Note: we don't actually seem to be encounter this race; 123562387023Sdduvall * except when the START bit is seen set again (see below), 123662387023Sdduvall * the data field doesn't change during this 5us interval. 123762387023Sdduvall */ 123862387023Sdduvall drv_usecwait(5); 123962387023Sdduvall regval2 = bge_reg_get32(bgep, MI_COMMS_REG); 124062387023Sdduvall 124162387023Sdduvall /* 124262387023Sdduvall * Unfortunately, when following the PRMs instructions above, 124362387023Sdduvall * we have occasionally seen the START bit set again(!) in the 124462387023Sdduvall * value read after the 5us delay. This seems to be due to the 124562387023Sdduvall * chip autonomously starting another MII access internally. 124662387023Sdduvall * In such cases, the command/data/etc fields relate to the 124762387023Sdduvall * internal command, rather than the one that we thought had 124862387023Sdduvall * just finished. So in this case, we fall back to returning 124962387023Sdduvall * the data from the original read that showed START clear. 125062387023Sdduvall */ 125162387023Sdduvall if (regval2 & MI_COMMS_START) { 125262387023Sdduvall BGE_REPORT((bgep, "bge_mii_access: cmd 0x%x -- " 125362387023Sdduvall "MI_COMMS_START set after transaction; 0x%x->0x%x", 125462387023Sdduvall cmd, regval1, regval2)); 125562387023Sdduvall regval2 = regval1; 125662387023Sdduvall } 125762387023Sdduvall 125862387023Sdduvall if (regval2 & MI_COMMS_START) 125962387023Sdduvall return ((uint16_t)~0u); 126062387023Sdduvall 126162387023Sdduvall if (regval2 & MI_COMMS_READ_FAILED) 126262387023Sdduvall return ((uint16_t)~0u); 126362387023Sdduvall 126462387023Sdduvall return ((regval2 & MI_COMMS_DATA_MASK) >> MI_COMMS_DATA_SHIFT); 126562387023Sdduvall } 126662387023Sdduvall 126762387023Sdduvall uint16_t bge_mii_get16(bge_t *bgep, bge_regno_t regno); 126862387023Sdduvall #pragma no_inline(bge_mii_get16) 126962387023Sdduvall 127062387023Sdduvall uint16_t 127162387023Sdduvall bge_mii_get16(bge_t *bgep, bge_regno_t regno) 127262387023Sdduvall { 127362387023Sdduvall BGE_TRACE(("bge_mii_get16($%p, 0x%lx)", 127462387023Sdduvall (void *)bgep, regno)); 127562387023Sdduvall 127662387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 127762387023Sdduvall 12785a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep) && ((regno == MII_AUX_CONTROL) || 1279bdb9230aSGarrett D'Amore (regno == MII_MSCONTROL))) 12805a506a18Syong tan - Sun Microsystems - Beijing China return (0); 12815a506a18Syong tan - Sun Microsystems - Beijing China 128262387023Sdduvall return (bge_mii_access(bgep, regno, 0, MI_COMMS_COMMAND_READ)); 128362387023Sdduvall } 128462387023Sdduvall 128562387023Sdduvall void bge_mii_put16(bge_t *bgep, bge_regno_t regno, uint16_t data); 128662387023Sdduvall #pragma no_inline(bge_mii_put16) 128762387023Sdduvall 128862387023Sdduvall void 128962387023Sdduvall bge_mii_put16(bge_t *bgep, bge_regno_t regno, uint16_t data) 129062387023Sdduvall { 129162387023Sdduvall BGE_TRACE(("bge_mii_put16($%p, 0x%lx, 0x%x)", 129262387023Sdduvall (void *)bgep, regno, data)); 129362387023Sdduvall 129462387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 129562387023Sdduvall 12965a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep) && ((regno == MII_AUX_CONTROL) || 1297bdb9230aSGarrett D'Amore (regno == MII_MSCONTROL))) 12985a506a18Syong tan - Sun Microsystems - Beijing China return; 12995a506a18Syong tan - Sun Microsystems - Beijing China 130062387023Sdduvall (void) bge_mii_access(bgep, regno, data, MI_COMMS_COMMAND_WRITE); 130162387023Sdduvall } 130262387023Sdduvall 1303087a28d1SDavid Gwynne uint16_t 1304087a28d1SDavid Gwynne bge_phydsp_read(bge_t *bgep, bge_regno_t regno) 1305087a28d1SDavid Gwynne { 1306087a28d1SDavid Gwynne BGE_TRACE(("bge_phydsp_read($%p, 0x%lx)", 1307087a28d1SDavid Gwynne (void *)bgep, regno)); 1308087a28d1SDavid Gwynne 1309087a28d1SDavid Gwynne ASSERT(mutex_owned(bgep->genlock)); 1310087a28d1SDavid Gwynne 1311087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_DSP_ADDRESS, regno); 1312087a28d1SDavid Gwynne return bge_mii_get16(bgep, MII_DSP_RW_PORT); 1313087a28d1SDavid Gwynne } 1314087a28d1SDavid Gwynne 1315087a28d1SDavid Gwynne #pragma no_inline(bge_phydsp_write) 1316087a28d1SDavid Gwynne 1317087a28d1SDavid Gwynne void 1318087a28d1SDavid Gwynne bge_phydsp_write(bge_t *bgep, bge_regno_t regno, uint16_t data) 1319087a28d1SDavid Gwynne { 1320087a28d1SDavid Gwynne BGE_TRACE(("bge_phydsp_write($%p, 0x%lx, 0x%x)", 1321087a28d1SDavid Gwynne (void *)bgep, regno, data)); 1322087a28d1SDavid Gwynne 1323087a28d1SDavid Gwynne ASSERT(mutex_owned(bgep->genlock)); 1324087a28d1SDavid Gwynne 1325087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_DSP_ADDRESS, regno); 1326087a28d1SDavid Gwynne bge_mii_put16(bgep, MII_DSP_RW_PORT, data); 1327087a28d1SDavid Gwynne } 1328087a28d1SDavid Gwynne 132962387023Sdduvall #undef BGE_DBG 133062387023Sdduvall #define BGE_DBG BGE_DBG_SEEPROM /* debug flag for this code */ 133162387023Sdduvall 133262387023Sdduvall #if BGE_SEE_IO32 || BGE_FLASH_IO32 133362387023Sdduvall 133462387023Sdduvall /* 133562387023Sdduvall * Basic SEEPROM get/set access routine 133662387023Sdduvall * 133762387023Sdduvall * This uses the chip's SEEPROM auto-access method, controlled by the 133862387023Sdduvall * Serial EEPROM Address/Data Registers at 0x6838/683c, so the CPU 133962387023Sdduvall * doesn't have to fiddle with the individual bits. 134062387023Sdduvall * 134162387023Sdduvall * The caller should hold <genlock> and *also* have already acquired 134262387023Sdduvall * the right to access the SEEPROM, via bge_nvmem_acquire() above. 134362387023Sdduvall * 134462387023Sdduvall * Return value: 134562387023Sdduvall * 0 on success, 134662387023Sdduvall * ENODATA on access timeout (maybe retryable: device may just be busy) 134762387023Sdduvall * EPROTO on other h/w or s/w errors. 134862387023Sdduvall * 134962387023Sdduvall * <*dp> is an input to a SEEPROM_ACCESS_WRITE operation, or an output 135062387023Sdduvall * from a (successful) SEEPROM_ACCESS_READ. 135162387023Sdduvall */ 135262387023Sdduvall static int bge_seeprom_access(bge_t *bgep, uint32_t cmd, bge_regno_t addr, 135362387023Sdduvall uint32_t *dp); 135462387023Sdduvall #pragma no_inline(bge_seeprom_access) 135562387023Sdduvall 135662387023Sdduvall static int 135762387023Sdduvall bge_seeprom_access(bge_t *bgep, uint32_t cmd, bge_regno_t addr, uint32_t *dp) 135862387023Sdduvall { 135962387023Sdduvall uint32_t tries; 136062387023Sdduvall uint32_t regval; 136162387023Sdduvall 136262387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 136362387023Sdduvall 136462387023Sdduvall /* 136562387023Sdduvall * On the newer chips that support both SEEPROM & Flash, we need 136662387023Sdduvall * to specifically enable SEEPROM access (Flash is the default). 136762387023Sdduvall * On older chips, we don't; SEEPROM is the only NVtype supported, 136862387023Sdduvall * and the NVM control registers don't exist ... 136962387023Sdduvall */ 137062387023Sdduvall switch (bgep->chipid.nvtype) { 137162387023Sdduvall case BGE_NVTYPE_NONE: 137262387023Sdduvall case BGE_NVTYPE_UNKNOWN: 137362387023Sdduvall _NOTE(NOTREACHED) 137462387023Sdduvall case BGE_NVTYPE_SEEPROM: 137562387023Sdduvall break; 137662387023Sdduvall 137762387023Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 137862387023Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 137962387023Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 138062387023Sdduvall default: 138162387023Sdduvall bge_reg_set32(bgep, NVM_CONFIG1_REG, 138262387023Sdduvall NVM_CFG1_LEGACY_SEEPROM_MODE); 138362387023Sdduvall break; 138462387023Sdduvall } 138562387023Sdduvall 138662387023Sdduvall /* 138762387023Sdduvall * Check there's no command in progress. 138862387023Sdduvall * 138962387023Sdduvall * Note: this *shouldn't* ever find that there is a command 139062387023Sdduvall * in progress, because we already hold the <genlock> mutex. 139162387023Sdduvall * Also, to ensure we don't have a conflict with the chip's 139262387023Sdduvall * internal firmware or a process accessing the same (shared) 139362387023Sdduvall * SEEPROM through the other port of a 5704, we've already 139462387023Sdduvall * been through the "software arbitration" protocol. 139562387023Sdduvall * So this is just a final consistency check: we shouldn't 139662387023Sdduvall * see EITHER the START bit (command started but not complete) 139762387023Sdduvall * OR the COMPLETE bit (command completed but not cleared). 139862387023Sdduvall */ 139962387023Sdduvall regval = bge_reg_get32(bgep, SERIAL_EEPROM_ADDRESS_REG); 140062387023Sdduvall if (regval & SEEPROM_ACCESS_START) 140162387023Sdduvall return (EPROTO); 140262387023Sdduvall if (regval & SEEPROM_ACCESS_COMPLETE) 140362387023Sdduvall return (EPROTO); 140462387023Sdduvall 140562387023Sdduvall /* 140662387023Sdduvall * Assemble the command ... 140762387023Sdduvall */ 140862387023Sdduvall cmd |= addr & SEEPROM_ACCESS_ADDRESS_MASK; 140962387023Sdduvall addr >>= SEEPROM_ACCESS_ADDRESS_SIZE; 141062387023Sdduvall addr <<= SEEPROM_ACCESS_DEVID_SHIFT; 141162387023Sdduvall cmd |= addr & SEEPROM_ACCESS_DEVID_MASK; 141262387023Sdduvall cmd |= SEEPROM_ACCESS_START; 141362387023Sdduvall cmd |= SEEPROM_ACCESS_COMPLETE; 141462387023Sdduvall cmd |= regval & SEEPROM_ACCESS_HALFCLOCK_MASK; 141562387023Sdduvall 141662387023Sdduvall bge_reg_put32(bgep, SERIAL_EEPROM_DATA_REG, *dp); 141762387023Sdduvall bge_reg_put32(bgep, SERIAL_EEPROM_ADDRESS_REG, cmd); 141862387023Sdduvall 141962387023Sdduvall /* 142062387023Sdduvall * By observation, a successful access takes ~20us on a 5703/4, 142162387023Sdduvall * but apparently much longer (up to 1000us) on the obsolescent 142262387023Sdduvall * BCM5700/BCM5701. We want to be sure we don't get any false 142362387023Sdduvall * timeouts here; but OTOH, we don't want a bogus access to lock 142462387023Sdduvall * out interrupts for longer than necessary. So we'll allow up 142562387023Sdduvall * to 1000us ... 142662387023Sdduvall */ 142762387023Sdduvall for (tries = 0; tries < 1000; ++tries) { 142862387023Sdduvall regval = bge_reg_get32(bgep, SERIAL_EEPROM_ADDRESS_REG); 142962387023Sdduvall if (regval & SEEPROM_ACCESS_COMPLETE) 143062387023Sdduvall break; 143162387023Sdduvall drv_usecwait(1); 143262387023Sdduvall } 143362387023Sdduvall 143462387023Sdduvall if (regval & SEEPROM_ACCESS_COMPLETE) { 143562387023Sdduvall /* 143662387023Sdduvall * All OK; read the SEEPROM data register, then write back 143762387023Sdduvall * the value read from the address register in order to 143862387023Sdduvall * clear the <complete> bit and leave the SEEPROM access 143962387023Sdduvall * state machine idle, ready for the next access ... 144062387023Sdduvall */ 144162387023Sdduvall BGE_DEBUG(("bge_seeprom_access: complete after %d us", tries)); 144262387023Sdduvall *dp = bge_reg_get32(bgep, SERIAL_EEPROM_DATA_REG); 144362387023Sdduvall bge_reg_put32(bgep, SERIAL_EEPROM_ADDRESS_REG, regval); 144462387023Sdduvall return (0); 144562387023Sdduvall } 144662387023Sdduvall 144762387023Sdduvall /* 144862387023Sdduvall * Hmm ... what happened here? 144962387023Sdduvall * 1450256e438eSzh199473 * Most likely, the user addressed a non-existent SEEPROM. Or 145162387023Sdduvall * maybe the SEEPROM was busy internally (e.g. processing a write) 145262387023Sdduvall * and didn't respond to being addressed. Either way, it's left 145362387023Sdduvall * the SEEPROM access state machine wedged. So we'll reset it 145462387023Sdduvall * before we leave, so it's ready for next time ... 145562387023Sdduvall */ 145662387023Sdduvall BGE_DEBUG(("bge_seeprom_access: timed out after %d us", tries)); 145762387023Sdduvall bge_reg_set32(bgep, SERIAL_EEPROM_ADDRESS_REG, SEEPROM_ACCESS_INIT); 145862387023Sdduvall return (ENODATA); 145962387023Sdduvall } 146062387023Sdduvall 146162387023Sdduvall /* 146262387023Sdduvall * Basic Flash get/set access routine 146362387023Sdduvall * 146462387023Sdduvall * These use the chip's Flash auto-access method, controlled by the 146562387023Sdduvall * Flash Access Registers at 0x7000-701c, so the CPU doesn't have to 146662387023Sdduvall * fiddle with the individual bits. 146762387023Sdduvall * 146862387023Sdduvall * The caller should hold <genlock> and *also* have already acquired 146962387023Sdduvall * the right to access the Flash, via bge_nvmem_acquire() above. 147062387023Sdduvall * 147162387023Sdduvall * Return value: 147262387023Sdduvall * 0 on success, 147362387023Sdduvall * ENODATA on access timeout (maybe retryable: device may just be busy) 147462387023Sdduvall * ENODEV if the NVmem device is missing or otherwise unusable 147562387023Sdduvall * 147662387023Sdduvall * <*dp> is an input to a NVM_FLASH_CMD_WR operation, or an output 147762387023Sdduvall * from a (successful) NVM_FLASH_CMD_RD. 147862387023Sdduvall */ 147962387023Sdduvall static int bge_flash_access(bge_t *bgep, uint32_t cmd, bge_regno_t addr, 148062387023Sdduvall uint32_t *dp); 148162387023Sdduvall #pragma no_inline(bge_flash_access) 148262387023Sdduvall 148362387023Sdduvall static int 148462387023Sdduvall bge_flash_access(bge_t *bgep, uint32_t cmd, bge_regno_t addr, uint32_t *dp) 148562387023Sdduvall { 148662387023Sdduvall uint32_t tries; 148762387023Sdduvall uint32_t regval; 148862387023Sdduvall 148962387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 149062387023Sdduvall 149162387023Sdduvall /* 149262387023Sdduvall * On the newer chips that support both SEEPROM & Flash, we need 149362387023Sdduvall * to specifically disable SEEPROM access while accessing Flash. 149462387023Sdduvall * The older chips don't support Flash, and the NVM registers don't 149562387023Sdduvall * exist, so we shouldn't be here at all! 149662387023Sdduvall */ 149762387023Sdduvall switch (bgep->chipid.nvtype) { 149862387023Sdduvall case BGE_NVTYPE_NONE: 149962387023Sdduvall case BGE_NVTYPE_UNKNOWN: 150062387023Sdduvall _NOTE(NOTREACHED) 150162387023Sdduvall case BGE_NVTYPE_SEEPROM: 150262387023Sdduvall return (ENODEV); 150362387023Sdduvall 150462387023Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 150562387023Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 150662387023Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 150762387023Sdduvall default: 150862387023Sdduvall bge_reg_clr32(bgep, NVM_CONFIG1_REG, 150962387023Sdduvall NVM_CFG1_LEGACY_SEEPROM_MODE); 151062387023Sdduvall break; 151162387023Sdduvall } 151262387023Sdduvall 151362387023Sdduvall /* 151462387023Sdduvall * Assemble the command ... 151562387023Sdduvall */ 151662387023Sdduvall addr &= NVM_FLASH_ADDR_MASK; 151762387023Sdduvall cmd |= NVM_FLASH_CMD_DOIT; 151862387023Sdduvall cmd |= NVM_FLASH_CMD_FIRST; 151962387023Sdduvall cmd |= NVM_FLASH_CMD_LAST; 152062387023Sdduvall cmd |= NVM_FLASH_CMD_DONE; 152162387023Sdduvall 152262387023Sdduvall bge_reg_put32(bgep, NVM_FLASH_WRITE_REG, *dp); 152362387023Sdduvall bge_reg_put32(bgep, NVM_FLASH_ADDR_REG, addr); 152462387023Sdduvall bge_reg_put32(bgep, NVM_FLASH_CMD_REG, cmd); 152562387023Sdduvall 152662387023Sdduvall /* 152762387023Sdduvall * Allow up to 1000ms ... 152862387023Sdduvall */ 152962387023Sdduvall for (tries = 0; tries < 1000; ++tries) { 153062387023Sdduvall regval = bge_reg_get32(bgep, NVM_FLASH_CMD_REG); 153162387023Sdduvall if (regval & NVM_FLASH_CMD_DONE) 153262387023Sdduvall break; 153362387023Sdduvall drv_usecwait(1); 153462387023Sdduvall } 153562387023Sdduvall 153662387023Sdduvall if (regval & NVM_FLASH_CMD_DONE) { 153762387023Sdduvall /* 153862387023Sdduvall * All OK; read the data from the Flash read register 153962387023Sdduvall */ 154062387023Sdduvall BGE_DEBUG(("bge_flash_access: complete after %d us", tries)); 154162387023Sdduvall *dp = bge_reg_get32(bgep, NVM_FLASH_READ_REG); 154262387023Sdduvall return (0); 154362387023Sdduvall } 154462387023Sdduvall 154562387023Sdduvall /* 154662387023Sdduvall * Hmm ... what happened here? 154762387023Sdduvall * 1548256e438eSzh199473 * Most likely, the user addressed a non-existent Flash. Or 154962387023Sdduvall * maybe the Flash was busy internally (e.g. processing a write) 155062387023Sdduvall * and didn't respond to being addressed. Either way, there's 155162387023Sdduvall * nothing we can here ... 155262387023Sdduvall */ 155362387023Sdduvall BGE_DEBUG(("bge_flash_access: timed out after %d us", tries)); 155462387023Sdduvall return (ENODATA); 155562387023Sdduvall } 155662387023Sdduvall 155762387023Sdduvall /* 155862387023Sdduvall * The next two functions regulate access to the NVram (if fitted). 155962387023Sdduvall * 156062387023Sdduvall * On a 5704 (dual core) chip, there's only one SEEPROM and one Flash 156162387023Sdduvall * (SPI) interface, but they can be accessed through either port. These 156262387023Sdduvall * are managed by different instance of this driver and have no software 156362387023Sdduvall * state in common. 156462387023Sdduvall * 156562387023Sdduvall * In addition (and even on a single core chip) the chip's internal 156662387023Sdduvall * firmware can access the SEEPROM/Flash, most notably after a RESET 156762387023Sdduvall * when it may download code to run internally. 156862387023Sdduvall * 156962387023Sdduvall * So we need to arbitrate between these various software agents. For 157062387023Sdduvall * this purpose, the chip provides the Software Arbitration Register, 157162387023Sdduvall * which implements hardware(!) arbitration. 157262387023Sdduvall * 157362387023Sdduvall * This functionality didn't exist on older (5700/5701) chips, so there's 157462387023Sdduvall * nothing we can do by way of arbitration on those; also, if there's no 157562387023Sdduvall * SEEPROM/Flash fitted (or we couldn't determine what type), there's also 157662387023Sdduvall * nothing to do. 157762387023Sdduvall * 157862387023Sdduvall * The internal firmware appears to use Request 0, which is the highest 157962387023Sdduvall * priority. So we'd like to use Request 2, leaving one higher and one 158062387023Sdduvall * lower for any future developments ... but apparently this doesn't 158162387023Sdduvall * always work. So for now, the code uses Request 1 ;-( 158262387023Sdduvall */ 158362387023Sdduvall 158462387023Sdduvall #define NVM_READ_REQ NVM_READ_REQ1 158562387023Sdduvall #define NVM_RESET_REQ NVM_RESET_REQ1 158662387023Sdduvall #define NVM_SET_REQ NVM_SET_REQ1 158762387023Sdduvall 158862387023Sdduvall static void bge_nvmem_relinquish(bge_t *bgep); 158962387023Sdduvall #pragma no_inline(bge_nvmem_relinquish) 159062387023Sdduvall 159162387023Sdduvall static void 159262387023Sdduvall bge_nvmem_relinquish(bge_t *bgep) 159362387023Sdduvall { 159462387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 159562387023Sdduvall 159662387023Sdduvall switch (bgep->chipid.nvtype) { 159762387023Sdduvall case BGE_NVTYPE_NONE: 159862387023Sdduvall case BGE_NVTYPE_UNKNOWN: 159962387023Sdduvall _NOTE(NOTREACHED) 160062387023Sdduvall return; 160162387023Sdduvall 160262387023Sdduvall case BGE_NVTYPE_SEEPROM: 160362387023Sdduvall /* 160462387023Sdduvall * No arbitration performed, no release needed 160562387023Sdduvall */ 160662387023Sdduvall return; 160762387023Sdduvall 160862387023Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 160962387023Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 161062387023Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 161162387023Sdduvall default: 161262387023Sdduvall break; 161362387023Sdduvall } 161462387023Sdduvall 161562387023Sdduvall /* 161662387023Sdduvall * Our own request should be present (whether or not granted) ... 161762387023Sdduvall */ 161800d0963fSdilpreet (void) bge_reg_get32(bgep, NVM_SW_ARBITRATION_REG); 161962387023Sdduvall 162062387023Sdduvall /* 162162387023Sdduvall * ... this will make it go away. 162262387023Sdduvall */ 162362387023Sdduvall bge_reg_put32(bgep, NVM_SW_ARBITRATION_REG, NVM_RESET_REQ); 162400d0963fSdilpreet (void) bge_reg_get32(bgep, NVM_SW_ARBITRATION_REG); 162562387023Sdduvall } 162662387023Sdduvall 162762387023Sdduvall /* 162862387023Sdduvall * Arbitrate for access to the NVmem, if necessary 162962387023Sdduvall * 163062387023Sdduvall * Return value: 163162387023Sdduvall * 0 on success 163262387023Sdduvall * EAGAIN if the device is in use (retryable) 163362387023Sdduvall * ENODEV if the NVmem device is missing or otherwise unusable 163462387023Sdduvall */ 163562387023Sdduvall static int bge_nvmem_acquire(bge_t *bgep); 163662387023Sdduvall #pragma no_inline(bge_nvmem_acquire) 163762387023Sdduvall 163862387023Sdduvall static int 163962387023Sdduvall bge_nvmem_acquire(bge_t *bgep) 164062387023Sdduvall { 164162387023Sdduvall uint32_t regval; 164262387023Sdduvall uint32_t tries; 164362387023Sdduvall 164462387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 164562387023Sdduvall 164662387023Sdduvall switch (bgep->chipid.nvtype) { 164762387023Sdduvall case BGE_NVTYPE_NONE: 164862387023Sdduvall case BGE_NVTYPE_UNKNOWN: 164962387023Sdduvall /* 165062387023Sdduvall * Access denied: no (recognisable) device fitted 165162387023Sdduvall */ 165262387023Sdduvall return (ENODEV); 165362387023Sdduvall 165462387023Sdduvall case BGE_NVTYPE_SEEPROM: 165562387023Sdduvall /* 165662387023Sdduvall * Access granted: no arbitration needed (or possible) 165762387023Sdduvall */ 165862387023Sdduvall return (0); 165962387023Sdduvall 166062387023Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 166162387023Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 166262387023Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 166362387023Sdduvall default: 166462387023Sdduvall /* 166562387023Sdduvall * Access conditional: conduct arbitration protocol 166662387023Sdduvall */ 166762387023Sdduvall break; 166862387023Sdduvall } 166962387023Sdduvall 167062387023Sdduvall /* 167162387023Sdduvall * We're holding the per-port mutex <genlock>, so no-one other 1672256e438eSzh199473 * thread can be attempting to access the NVmem through *this* 167362387023Sdduvall * port. But it could be in use by the *other* port (of a 5704), 167462387023Sdduvall * or by the chip's internal firmware, so we have to go through 167562387023Sdduvall * the full (hardware) arbitration protocol ... 167662387023Sdduvall * 167762387023Sdduvall * Note that *because* we're holding <genlock>, the interrupt handler 167862387023Sdduvall * won't be able to progress. So we're only willing to spin for a 167962387023Sdduvall * fairly short time. Specifically: 168062387023Sdduvall * 168162387023Sdduvall * We *must* wait long enough for the hardware to resolve all 168262387023Sdduvall * requests and determine the winner. Fortunately, this is 168362387023Sdduvall * "almost instantaneous", even as observed by GHz CPUs. 168462387023Sdduvall * 168562387023Sdduvall * A successful access by another Solaris thread (via either 168662387023Sdduvall * port) typically takes ~20us. So waiting a bit longer than 168762387023Sdduvall * that will give a good chance of success, if the other user 168862387023Sdduvall * *is* another thread on the other port. 168962387023Sdduvall * 169062387023Sdduvall * However, the internal firmware can hold on to the NVmem 169162387023Sdduvall * for *much* longer: at least 10 milliseconds just after a 169262387023Sdduvall * RESET, and maybe even longer if the NVmem actually contains 169362387023Sdduvall * code to download and run on the internal CPUs. 169462387023Sdduvall * 169562387023Sdduvall * So, we'll allow 50us; if that's not enough then it's up to the 169662387023Sdduvall * caller to retry later (hence the choice of return code EAGAIN). 169762387023Sdduvall */ 169862387023Sdduvall regval = bge_reg_get32(bgep, NVM_SW_ARBITRATION_REG); 169962387023Sdduvall bge_reg_put32(bgep, NVM_SW_ARBITRATION_REG, NVM_SET_REQ); 170062387023Sdduvall 170162387023Sdduvall for (tries = 0; tries < 50; ++tries) { 170262387023Sdduvall regval = bge_reg_get32(bgep, NVM_SW_ARBITRATION_REG); 170362387023Sdduvall if (regval & NVM_WON_REQ1) 170462387023Sdduvall break; 170562387023Sdduvall drv_usecwait(1); 170662387023Sdduvall } 170762387023Sdduvall 170862387023Sdduvall if (regval & NVM_WON_REQ1) { 170962387023Sdduvall BGE_DEBUG(("bge_nvmem_acquire: won after %d us", tries)); 171062387023Sdduvall return (0); 171162387023Sdduvall } 171262387023Sdduvall 171362387023Sdduvall /* 171462387023Sdduvall * Somebody else must be accessing the NVmem, so abandon our 171562387023Sdduvall * attempt take control of it. The caller can try again later ... 171662387023Sdduvall */ 171762387023Sdduvall BGE_DEBUG(("bge_nvmem_acquire: lost after %d us", tries)); 171862387023Sdduvall bge_nvmem_relinquish(bgep); 171962387023Sdduvall return (EAGAIN); 172062387023Sdduvall } 172162387023Sdduvall 172262387023Sdduvall /* 172362387023Sdduvall * This code assumes that the GPIO1 bit has been wired up to the NVmem 172462387023Sdduvall * write protect line in such a way that the NVmem is protected when 172562387023Sdduvall * GPIO1 is an input, or is an output but driven high. Thus, to make the 172662387023Sdduvall * NVmem writable we have to change GPIO1 to an output AND drive it low. 172762387023Sdduvall * 172862387023Sdduvall * Note: there's only one set of GPIO pins on a 5704, even though they 172962387023Sdduvall * can be accessed through either port. So the chip has to resolve what 173062387023Sdduvall * happens if the two ports program a single pin differently ... the rule 173162387023Sdduvall * it uses is that if the ports disagree about the *direction* of a pin, 173262387023Sdduvall * "output" wins over "input", but if they disagree about its *value* as 173362387023Sdduvall * an output, then the pin is TRISTATED instead! In such a case, no-one 173462387023Sdduvall * wins, and the external signal does whatever the external circuitry 173562387023Sdduvall * defines as the default -- which we've assumed is the PROTECTED state. 173662387023Sdduvall * So, we always change GPIO1 back to being an *input* whenever we're not 173762387023Sdduvall * specifically using it to unprotect the NVmem. This allows either port 1738256e438eSzh199473 * to update the NVmem, although obviously only one at a time! 173962387023Sdduvall * 174062387023Sdduvall * The caller should hold <genlock> and *also* have already acquired the 174162387023Sdduvall * right to access the NVmem, via bge_nvmem_acquire() above. 174262387023Sdduvall */ 174362387023Sdduvall static void bge_nvmem_protect(bge_t *bgep, boolean_t protect); 174462387023Sdduvall #pragma inline(bge_nvmem_protect) 174562387023Sdduvall 174662387023Sdduvall static void 174762387023Sdduvall bge_nvmem_protect(bge_t *bgep, boolean_t protect) 174862387023Sdduvall { 174962387023Sdduvall uint32_t regval; 175062387023Sdduvall 175162387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 175262387023Sdduvall 175362387023Sdduvall regval = bge_reg_get32(bgep, MISC_LOCAL_CONTROL_REG); 175462387023Sdduvall if (protect) { 175562387023Sdduvall regval |= MLCR_MISC_PINS_OUTPUT_1; 175662387023Sdduvall regval &= ~MLCR_MISC_PINS_OUTPUT_ENABLE_1; 175762387023Sdduvall } else { 175862387023Sdduvall regval &= ~MLCR_MISC_PINS_OUTPUT_1; 175962387023Sdduvall regval |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 176062387023Sdduvall } 176162387023Sdduvall bge_reg_put32(bgep, MISC_LOCAL_CONTROL_REG, regval); 176262387023Sdduvall } 176362387023Sdduvall 176462387023Sdduvall /* 176562387023Sdduvall * Now put it all together ... 176662387023Sdduvall * 176762387023Sdduvall * Try to acquire control of the NVmem; if successful, then: 176862387023Sdduvall * unprotect it (if we want to write to it) 176962387023Sdduvall * perform the requested access 177062387023Sdduvall * reprotect it (after a write) 177162387023Sdduvall * relinquish control 177262387023Sdduvall * 177362387023Sdduvall * Return value: 177462387023Sdduvall * 0 on success, 177562387023Sdduvall * EAGAIN if the device is in use (retryable) 177662387023Sdduvall * ENODATA on access timeout (maybe retryable: device may just be busy) 177762387023Sdduvall * ENODEV if the NVmem device is missing or otherwise unusable 177862387023Sdduvall * EPROTO on other h/w or s/w errors. 177962387023Sdduvall */ 178062387023Sdduvall static int 178162387023Sdduvall bge_nvmem_rw32(bge_t *bgep, uint32_t cmd, bge_regno_t addr, uint32_t *dp) 178262387023Sdduvall { 178362387023Sdduvall int err; 178462387023Sdduvall 178562387023Sdduvall if ((err = bge_nvmem_acquire(bgep)) == 0) { 178662387023Sdduvall switch (cmd) { 178762387023Sdduvall case BGE_SEE_READ: 178862387023Sdduvall err = bge_seeprom_access(bgep, 178962387023Sdduvall SEEPROM_ACCESS_READ, addr, dp); 179062387023Sdduvall break; 179162387023Sdduvall 179262387023Sdduvall case BGE_SEE_WRITE: 179362387023Sdduvall bge_nvmem_protect(bgep, B_FALSE); 179462387023Sdduvall err = bge_seeprom_access(bgep, 179562387023Sdduvall SEEPROM_ACCESS_WRITE, addr, dp); 179662387023Sdduvall bge_nvmem_protect(bgep, B_TRUE); 179762387023Sdduvall break; 179862387023Sdduvall 179962387023Sdduvall case BGE_FLASH_READ: 180062387023Sdduvall if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 180100d84294Syong tan - Sun Microsystems - Beijing China DEVICE_5723_SERIES_CHIPSETS(bgep) || 1802dc3f9a75Syong tan - Sun Microsystems - Beijing China DEVICE_5717_SERIES_CHIPSETS(bgep) || 1803087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) || 180462387023Sdduvall DEVICE_5714_SERIES_CHIPSETS(bgep)) { 180562387023Sdduvall bge_reg_set32(bgep, NVM_ACCESS_REG, 180662387023Sdduvall NVM_ACCESS_ENABLE); 180762387023Sdduvall } 180862387023Sdduvall err = bge_flash_access(bgep, 180962387023Sdduvall NVM_FLASH_CMD_RD, addr, dp); 181062387023Sdduvall if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 181100d84294Syong tan - Sun Microsystems - Beijing China DEVICE_5723_SERIES_CHIPSETS(bgep) || 1812dc3f9a75Syong tan - Sun Microsystems - Beijing China DEVICE_5717_SERIES_CHIPSETS(bgep) || 1813087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) || 181462387023Sdduvall DEVICE_5714_SERIES_CHIPSETS(bgep)) { 181562387023Sdduvall bge_reg_clr32(bgep, NVM_ACCESS_REG, 181662387023Sdduvall NVM_ACCESS_ENABLE); 181762387023Sdduvall } 181862387023Sdduvall break; 181962387023Sdduvall 182062387023Sdduvall case BGE_FLASH_WRITE: 182162387023Sdduvall if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 182200d84294Syong tan - Sun Microsystems - Beijing China DEVICE_5723_SERIES_CHIPSETS(bgep) || 1823dc3f9a75Syong tan - Sun Microsystems - Beijing China DEVICE_5717_SERIES_CHIPSETS(bgep) || 1824087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) || 182562387023Sdduvall DEVICE_5714_SERIES_CHIPSETS(bgep)) { 182662387023Sdduvall bge_reg_set32(bgep, NVM_ACCESS_REG, 182762387023Sdduvall NVM_WRITE_ENABLE|NVM_ACCESS_ENABLE); 182862387023Sdduvall } 182962387023Sdduvall bge_nvmem_protect(bgep, B_FALSE); 183062387023Sdduvall err = bge_flash_access(bgep, 183162387023Sdduvall NVM_FLASH_CMD_WR, addr, dp); 183262387023Sdduvall bge_nvmem_protect(bgep, B_TRUE); 183362387023Sdduvall if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 183400d84294Syong tan - Sun Microsystems - Beijing China DEVICE_5723_SERIES_CHIPSETS(bgep) || 1835dc3f9a75Syong tan - Sun Microsystems - Beijing China DEVICE_5717_SERIES_CHIPSETS(bgep) || 1836087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) || 183762387023Sdduvall DEVICE_5714_SERIES_CHIPSETS(bgep)) { 183862387023Sdduvall bge_reg_clr32(bgep, NVM_ACCESS_REG, 183962387023Sdduvall NVM_WRITE_ENABLE|NVM_ACCESS_ENABLE); 184062387023Sdduvall } 184162387023Sdduvall 184262387023Sdduvall break; 184362387023Sdduvall 184462387023Sdduvall default: 184562387023Sdduvall _NOTE(NOTREACHED) 184662387023Sdduvall break; 184762387023Sdduvall } 184862387023Sdduvall bge_nvmem_relinquish(bgep); 184962387023Sdduvall } 185062387023Sdduvall 185162387023Sdduvall BGE_DEBUG(("bge_nvmem_rw32: err %d", err)); 185262387023Sdduvall return (err); 185362387023Sdduvall } 185462387023Sdduvall 1855087a28d1SDavid Gwynne static uint32_t 1856087a28d1SDavid Gwynne bge_nvmem_access_cmd(bge_t *bgep, boolean_t read) 1857087a28d1SDavid Gwynne { 1858087a28d1SDavid Gwynne switch (bgep->chipid.nvtype) { 1859087a28d1SDavid Gwynne case BGE_NVTYPE_NONE: 1860087a28d1SDavid Gwynne case BGE_NVTYPE_UNKNOWN: 1861087a28d1SDavid Gwynne default: 1862087a28d1SDavid Gwynne return 0; 1863087a28d1SDavid Gwynne 1864087a28d1SDavid Gwynne case BGE_NVTYPE_SEEPROM: 1865087a28d1SDavid Gwynne case BGE_NVTYPE_LEGACY_SEEPROM: 1866087a28d1SDavid Gwynne return (read ? BGE_SEE_READ : BGE_SEE_WRITE); 1867087a28d1SDavid Gwynne 1868087a28d1SDavid Gwynne case BGE_NVTYPE_UNBUFFERED_FLASH: 1869087a28d1SDavid Gwynne case BGE_NVTYPE_BUFFERED_FLASH: 1870087a28d1SDavid Gwynne return (read ? BGE_FLASH_READ : BGE_FLASH_WRITE); 1871087a28d1SDavid Gwynne } 1872087a28d1SDavid Gwynne } 1873087a28d1SDavid Gwynne 1874087a28d1SDavid Gwynne 1875087a28d1SDavid Gwynne int 1876087a28d1SDavid Gwynne bge_nvmem_read32(bge_t *bgep, bge_regno_t addr, uint32_t *dp) 1877087a28d1SDavid Gwynne { 1878087a28d1SDavid Gwynne return (bge_nvmem_rw32(bgep, bge_nvmem_access_cmd(bgep, B_TRUE), 1879087a28d1SDavid Gwynne addr, dp)); 1880087a28d1SDavid Gwynne } 1881087a28d1SDavid Gwynne 1882087a28d1SDavid Gwynne 1883087a28d1SDavid Gwynne int 1884087a28d1SDavid Gwynne bge_nvmem_write32(bge_t *bgep, bge_regno_t addr, uint32_t *dp) 1885087a28d1SDavid Gwynne { 1886087a28d1SDavid Gwynne return (bge_nvmem_rw32(bgep, bge_nvmem_access_cmd(bgep, B_FALSE), 1887087a28d1SDavid Gwynne addr, dp)); 1888087a28d1SDavid Gwynne } 1889087a28d1SDavid Gwynne 1890087a28d1SDavid Gwynne 189162387023Sdduvall /* 189262387023Sdduvall * Attempt to get a MAC address from the SEEPROM or Flash, if any 189362387023Sdduvall */ 189462387023Sdduvall static uint64_t bge_get_nvmac(bge_t *bgep); 189562387023Sdduvall #pragma no_inline(bge_get_nvmac) 189662387023Sdduvall 189762387023Sdduvall static uint64_t 189862387023Sdduvall bge_get_nvmac(bge_t *bgep) 189962387023Sdduvall { 190062387023Sdduvall uint32_t mac_high; 190162387023Sdduvall uint32_t mac_low; 190262387023Sdduvall uint32_t addr; 190362387023Sdduvall uint32_t cmd; 190462387023Sdduvall uint64_t mac; 190562387023Sdduvall 190662387023Sdduvall BGE_TRACE(("bge_get_nvmac($%p)", 190762387023Sdduvall (void *)bgep)); 190862387023Sdduvall 190962387023Sdduvall switch (bgep->chipid.nvtype) { 191062387023Sdduvall case BGE_NVTYPE_NONE: 191162387023Sdduvall case BGE_NVTYPE_UNKNOWN: 191262387023Sdduvall default: 191362387023Sdduvall return (0ULL); 191462387023Sdduvall 191562387023Sdduvall case BGE_NVTYPE_SEEPROM: 191662387023Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 191762387023Sdduvall cmd = BGE_SEE_READ; 191862387023Sdduvall break; 191962387023Sdduvall 192062387023Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 192162387023Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 192262387023Sdduvall cmd = BGE_FLASH_READ; 192362387023Sdduvall break; 192462387023Sdduvall } 192562387023Sdduvall 19265a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 19275a506a18Syong tan - Sun Microsystems - Beijing China addr = NVMEM_DATA_MAC_ADDRESS_5906; 19285a506a18Syong tan - Sun Microsystems - Beijing China else 192962387023Sdduvall addr = NVMEM_DATA_MAC_ADDRESS; 19305a506a18Syong tan - Sun Microsystems - Beijing China 193162387023Sdduvall if (bge_nvmem_rw32(bgep, cmd, addr, &mac_high)) 193262387023Sdduvall return (0ULL); 193362387023Sdduvall addr += 4; 193462387023Sdduvall if (bge_nvmem_rw32(bgep, cmd, addr, &mac_low)) 193562387023Sdduvall return (0ULL); 193662387023Sdduvall 193762387023Sdduvall /* 193862387023Sdduvall * The Broadcom chip is natively BIG-endian, so that's how the 193962387023Sdduvall * MAC address is represented in NVmem. We may need to swap it 194062387023Sdduvall * around on a little-endian host ... 194162387023Sdduvall */ 194262387023Sdduvall #ifdef _BIG_ENDIAN 194362387023Sdduvall mac = mac_high; 194462387023Sdduvall mac = mac << 32; 194562387023Sdduvall mac |= mac_low; 194662387023Sdduvall #else 194762387023Sdduvall mac = BGE_BSWAP_32(mac_high); 194862387023Sdduvall mac = mac << 32; 194962387023Sdduvall mac |= BGE_BSWAP_32(mac_low); 195062387023Sdduvall #endif /* _BIG_ENDIAN */ 195162387023Sdduvall 195262387023Sdduvall return (mac); 195362387023Sdduvall } 195462387023Sdduvall 195562387023Sdduvall #else /* BGE_SEE_IO32 || BGE_FLASH_IO32 */ 195662387023Sdduvall 195762387023Sdduvall /* 195862387023Sdduvall * Dummy version for when we're not supporting NVmem access 195962387023Sdduvall */ 196062387023Sdduvall static uint64_t bge_get_nvmac(bge_t *bgep); 196162387023Sdduvall #pragma inline(bge_get_nvmac) 196262387023Sdduvall 196362387023Sdduvall static uint64_t 196462387023Sdduvall bge_get_nvmac(bge_t *bgep) 196562387023Sdduvall { 196662387023Sdduvall _NOTE(ARGUNUSED(bgep)) 196762387023Sdduvall return (0ULL); 196862387023Sdduvall } 196962387023Sdduvall 197062387023Sdduvall #endif /* BGE_SEE_IO32 || BGE_FLASH_IO32 */ 197162387023Sdduvall 197262387023Sdduvall /* 197362387023Sdduvall * Determine the type of NVmem that is (or may be) attached to this chip, 197462387023Sdduvall */ 197562387023Sdduvall static enum bge_nvmem_type bge_nvmem_id(bge_t *bgep); 197662387023Sdduvall #pragma no_inline(bge_nvmem_id) 197762387023Sdduvall 197862387023Sdduvall static enum bge_nvmem_type 197962387023Sdduvall bge_nvmem_id(bge_t *bgep) 198062387023Sdduvall { 198162387023Sdduvall enum bge_nvmem_type nvtype; 198262387023Sdduvall uint32_t config1; 198362387023Sdduvall 198462387023Sdduvall BGE_TRACE(("bge_nvmem_id($%p)", 198562387023Sdduvall (void *)bgep)); 198662387023Sdduvall 198762387023Sdduvall switch (bgep->chipid.device) { 198862387023Sdduvall default: 198962387023Sdduvall /* 199062387023Sdduvall * We shouldn't get here; it means we don't recognise 199162387023Sdduvall * the chip, which means we don't know how to determine 199262387023Sdduvall * what sort of NVmem (if any) it has. So we'll say 199362387023Sdduvall * NONE, to disable the NVmem access code ... 199462387023Sdduvall */ 199562387023Sdduvall nvtype = BGE_NVTYPE_NONE; 199662387023Sdduvall break; 199762387023Sdduvall 199862387023Sdduvall case DEVICE_ID_5700: 199962387023Sdduvall case DEVICE_ID_5700x: 200062387023Sdduvall case DEVICE_ID_5701: 200162387023Sdduvall /* 200262387023Sdduvall * These devices support *only* SEEPROMs 200362387023Sdduvall */ 200462387023Sdduvall nvtype = BGE_NVTYPE_SEEPROM; 200562387023Sdduvall break; 200662387023Sdduvall 200762387023Sdduvall case DEVICE_ID_5702: 200862387023Sdduvall case DEVICE_ID_5702fe: 200962387023Sdduvall case DEVICE_ID_5703C: 201062387023Sdduvall case DEVICE_ID_5703S: 201162387023Sdduvall case DEVICE_ID_5704C: 201262387023Sdduvall case DEVICE_ID_5704S: 201362387023Sdduvall case DEVICE_ID_5704: 201462387023Sdduvall case DEVICE_ID_5705M: 201562387023Sdduvall case DEVICE_ID_5705C: 20167c966ec8Sml149210 case DEVICE_ID_5705_2: 2017224ef589Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5717: 2018dc3f9a75Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5718: 2019087a28d1SDavid Gwynne case DEVICE_ID_5719: 2020087a28d1SDavid Gwynne case DEVICE_ID_5720: 2021224ef589Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5724: 2022087a28d1SDavid Gwynne case DEVICE_ID_5725: 2023087a28d1SDavid Gwynne case DEVICE_ID_5727: 2024224ef589Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_57780: 2025feb48d62SGarrett D'Amore case DEVICE_ID_5780: 202662387023Sdduvall case DEVICE_ID_5782: 2027652b4801Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5785: 20287f7c96a6Sml40262 case DEVICE_ID_5787: 20297f7c96a6Sml40262 case DEVICE_ID_5787M: 203062387023Sdduvall case DEVICE_ID_5788: 2031256e438eSzh199473 case DEVICE_ID_5789: 203262387023Sdduvall case DEVICE_ID_5751: 203362387023Sdduvall case DEVICE_ID_5751M: 2034f724721bSzh199473 case DEVICE_ID_5752: 2035f724721bSzh199473 case DEVICE_ID_5752M: 2036ebd66af9Sml149210 case DEVICE_ID_5754: 203703a69b52Sml149210 case DEVICE_ID_5755: 2038dca582a1Sgh162552 case DEVICE_ID_5755M: 203967f41d5aSGordon Ross case DEVICE_ID_5756M: 204062387023Sdduvall case DEVICE_ID_5721: 2041f0a5c2e3SCrisson Guanghao Hu case DEVICE_ID_5722: 204200d84294Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5723: 20437e420006Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5761: 20447e420006Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5761E: 2045d7441963Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5764: 204662387023Sdduvall case DEVICE_ID_5714C: 204762387023Sdduvall case DEVICE_ID_5714S: 204862387023Sdduvall case DEVICE_ID_5715C: 20497c966ec8Sml149210 case DEVICE_ID_5715S: 205062387023Sdduvall config1 = bge_reg_get32(bgep, NVM_CONFIG1_REG); 205162387023Sdduvall if (config1 & NVM_CFG1_FLASH_MODE) 205262387023Sdduvall if (config1 & NVM_CFG1_BUFFERED_MODE) 205362387023Sdduvall nvtype = BGE_NVTYPE_BUFFERED_FLASH; 205462387023Sdduvall else 205562387023Sdduvall nvtype = BGE_NVTYPE_UNBUFFERED_FLASH; 205662387023Sdduvall else 205762387023Sdduvall nvtype = BGE_NVTYPE_LEGACY_SEEPROM; 205862387023Sdduvall break; 20595a506a18Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5906: 20605a506a18Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5906M: 20615a506a18Syong tan - Sun Microsystems - Beijing China nvtype = BGE_NVTYPE_BUFFERED_FLASH; 20625a506a18Syong tan - Sun Microsystems - Beijing China break; 206362387023Sdduvall } 206462387023Sdduvall 206562387023Sdduvall return (nvtype); 206662387023Sdduvall } 206762387023Sdduvall 206862387023Sdduvall #undef BGE_DBG 2069087a28d1SDavid Gwynne #define BGE_DBG BGE_DBG_APE /* debug flag for this code */ 2070087a28d1SDavid Gwynne 2071087a28d1SDavid Gwynne uint32_t bge_ape_get32(bge_t *bgep, bge_regno_t regno); 2072087a28d1SDavid Gwynne #pragma inline(bge_ape_get32) 2073087a28d1SDavid Gwynne 2074087a28d1SDavid Gwynne uint32_t 2075087a28d1SDavid Gwynne bge_ape_get32(bge_t *bgep, bge_regno_t regno) 2076087a28d1SDavid Gwynne { 2077087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_get32($%p, 0x%lx)", 2078087a28d1SDavid Gwynne (void *)bgep, regno)); 2079087a28d1SDavid Gwynne 2080087a28d1SDavid Gwynne return (ddi_get32(bgep->ape_handle, APE_ADDR(bgep, regno))); 2081087a28d1SDavid Gwynne } 2082087a28d1SDavid Gwynne 2083087a28d1SDavid Gwynne void bge_ape_put32(bge_t *bgep, bge_regno_t regno, uint32_t data); 2084087a28d1SDavid Gwynne #pragma inline(bge_ape_put32) 2085087a28d1SDavid Gwynne 2086087a28d1SDavid Gwynne void 2087087a28d1SDavid Gwynne bge_ape_put32(bge_t *bgep, bge_regno_t regno, uint32_t data) 2088087a28d1SDavid Gwynne { 2089087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_put32($%p, 0x%lx, 0x%x)", 2090087a28d1SDavid Gwynne (void *)bgep, regno, data)); 2091087a28d1SDavid Gwynne 2092087a28d1SDavid Gwynne ddi_put32(bgep->ape_handle, APE_ADDR(bgep, regno), data); 2093087a28d1SDavid Gwynne BGE_PCICHK(bgep); 2094087a28d1SDavid Gwynne } 2095087a28d1SDavid Gwynne 2096087a28d1SDavid Gwynne void 2097087a28d1SDavid Gwynne bge_ape_lock_init(bge_t *bgep) 2098087a28d1SDavid Gwynne { 2099087a28d1SDavid Gwynne int i; 2100087a28d1SDavid Gwynne uint32_t regbase; 2101087a28d1SDavid Gwynne uint32_t bit; 2102087a28d1SDavid Gwynne 2103087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_lock_init($%p)", (void *)bgep)); 2104087a28d1SDavid Gwynne 2105087a28d1SDavid Gwynne if (bgep->chipid.device == DEVICE_ID_5761) 2106087a28d1SDavid Gwynne regbase = BGE_APE_LOCK_GRANT; 2107087a28d1SDavid Gwynne else 2108087a28d1SDavid Gwynne regbase = BGE_APE_PER_LOCK_GRANT; 2109087a28d1SDavid Gwynne 2110087a28d1SDavid Gwynne /* Make sure the driver hasn't any stale locks. */ 2111087a28d1SDavid Gwynne for (i = BGE_APE_LOCK_PHY0; i <= BGE_APE_LOCK_GPIO; i++) { 2112087a28d1SDavid Gwynne switch (i) { 2113087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY0: 2114087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY1: 2115087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY2: 2116087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY3: 2117087a28d1SDavid Gwynne bit = APE_LOCK_GRANT_DRIVER; 2118087a28d1SDavid Gwynne break; 2119087a28d1SDavid Gwynne default: 2120087a28d1SDavid Gwynne if (!bgep->pci_func) 2121087a28d1SDavid Gwynne bit = APE_LOCK_GRANT_DRIVER; 2122087a28d1SDavid Gwynne else 2123087a28d1SDavid Gwynne bit = 1 << bgep->pci_func; 2124087a28d1SDavid Gwynne } 2125087a28d1SDavid Gwynne bge_ape_put32(bgep, regbase + 4 * i, bit); 2126087a28d1SDavid Gwynne } 2127087a28d1SDavid Gwynne } 2128087a28d1SDavid Gwynne 2129087a28d1SDavid Gwynne static int 2130087a28d1SDavid Gwynne bge_ape_lock(bge_t *bgep, int locknum) 2131087a28d1SDavid Gwynne { 2132087a28d1SDavid Gwynne int i, off; 2133087a28d1SDavid Gwynne int ret = 0; 2134087a28d1SDavid Gwynne uint32_t status; 2135087a28d1SDavid Gwynne uint32_t req; 2136087a28d1SDavid Gwynne uint32_t gnt; 2137087a28d1SDavid Gwynne uint32_t bit; 2138087a28d1SDavid Gwynne 2139087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_lock($%p, 0x%x)", (void *)bgep, locknum)); 2140087a28d1SDavid Gwynne 2141087a28d1SDavid Gwynne if (!bgep->ape_enabled) 2142087a28d1SDavid Gwynne return (0); 2143087a28d1SDavid Gwynne 2144087a28d1SDavid Gwynne switch (locknum) { 2145087a28d1SDavid Gwynne case BGE_APE_LOCK_GPIO: 2146087a28d1SDavid Gwynne if (bgep->chipid.device == DEVICE_ID_5761) 2147087a28d1SDavid Gwynne return (0); 2148087a28d1SDavid Gwynne case BGE_APE_LOCK_GRC: 2149087a28d1SDavid Gwynne case BGE_APE_LOCK_MEM: 2150087a28d1SDavid Gwynne if (!bgep->pci_func) 2151087a28d1SDavid Gwynne bit = APE_LOCK_REQ_DRIVER; 2152087a28d1SDavid Gwynne else 2153087a28d1SDavid Gwynne bit = 1 << bgep->pci_func; 2154087a28d1SDavid Gwynne break; 2155087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY0: 2156087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY1: 2157087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY2: 2158087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY3: 2159087a28d1SDavid Gwynne bit = APE_LOCK_REQ_DRIVER; 2160087a28d1SDavid Gwynne break; 2161087a28d1SDavid Gwynne default: 2162087a28d1SDavid Gwynne return (-1); 2163087a28d1SDavid Gwynne } 2164087a28d1SDavid Gwynne 2165087a28d1SDavid Gwynne if (bgep->chipid.device == DEVICE_ID_5761) { 2166087a28d1SDavid Gwynne req = BGE_APE_LOCK_REQ; 2167087a28d1SDavid Gwynne gnt = BGE_APE_LOCK_GRANT; 2168087a28d1SDavid Gwynne } else { 2169087a28d1SDavid Gwynne req = BGE_APE_PER_LOCK_REQ; 2170087a28d1SDavid Gwynne gnt = BGE_APE_PER_LOCK_GRANT; 2171087a28d1SDavid Gwynne } 2172087a28d1SDavid Gwynne 2173087a28d1SDavid Gwynne off = 4 * locknum; 2174087a28d1SDavid Gwynne 2175087a28d1SDavid Gwynne bge_ape_put32(bgep, req + off, bit); 2176087a28d1SDavid Gwynne 2177087a28d1SDavid Gwynne /* Wait for up to 1 millisecond to acquire lock. */ 2178087a28d1SDavid Gwynne for (i = 0; i < 100; i++) { 2179087a28d1SDavid Gwynne status = bge_ape_get32(bgep, gnt + off); 2180087a28d1SDavid Gwynne if (status == bit) 2181087a28d1SDavid Gwynne break; 2182087a28d1SDavid Gwynne drv_usecwait(10); 2183087a28d1SDavid Gwynne } 2184087a28d1SDavid Gwynne 2185087a28d1SDavid Gwynne if (status != bit) { 2186087a28d1SDavid Gwynne /* Revoke the lock request. */ 2187087a28d1SDavid Gwynne bge_ape_put32(bgep, gnt + off, bit); 2188087a28d1SDavid Gwynne ret = -1; 2189087a28d1SDavid Gwynne } 2190087a28d1SDavid Gwynne 2191087a28d1SDavid Gwynne return (ret); 2192087a28d1SDavid Gwynne } 2193087a28d1SDavid Gwynne 2194087a28d1SDavid Gwynne static void 2195087a28d1SDavid Gwynne bge_ape_unlock(bge_t *bgep, int locknum) 2196087a28d1SDavid Gwynne { 2197087a28d1SDavid Gwynne uint32_t gnt; 2198087a28d1SDavid Gwynne uint32_t bit; 2199087a28d1SDavid Gwynne 2200087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_unlock($%p, 0x%x)", (void *)bgep, locknum)); 2201087a28d1SDavid Gwynne 2202087a28d1SDavid Gwynne if (!bgep->ape_enabled) 2203087a28d1SDavid Gwynne return; 2204087a28d1SDavid Gwynne 2205087a28d1SDavid Gwynne switch (locknum) { 2206087a28d1SDavid Gwynne case BGE_APE_LOCK_GPIO: 2207087a28d1SDavid Gwynne if (bgep->chipid.device == DEVICE_ID_5761) 2208087a28d1SDavid Gwynne return; 2209087a28d1SDavid Gwynne case BGE_APE_LOCK_GRC: 2210087a28d1SDavid Gwynne case BGE_APE_LOCK_MEM: 2211087a28d1SDavid Gwynne if (!bgep->pci_func) 2212087a28d1SDavid Gwynne bit = APE_LOCK_GRANT_DRIVER; 2213087a28d1SDavid Gwynne else 2214087a28d1SDavid Gwynne bit = 1 << bgep->pci_func; 2215087a28d1SDavid Gwynne break; 2216087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY0: 2217087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY1: 2218087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY2: 2219087a28d1SDavid Gwynne case BGE_APE_LOCK_PHY3: 2220087a28d1SDavid Gwynne bit = APE_LOCK_GRANT_DRIVER; 2221087a28d1SDavid Gwynne break; 2222087a28d1SDavid Gwynne default: 2223087a28d1SDavid Gwynne return; 2224087a28d1SDavid Gwynne } 2225087a28d1SDavid Gwynne 2226087a28d1SDavid Gwynne if (bgep->chipid.device == DEVICE_ID_5761) 2227087a28d1SDavid Gwynne gnt = BGE_APE_LOCK_GRANT; 2228087a28d1SDavid Gwynne else 2229087a28d1SDavid Gwynne gnt = BGE_APE_PER_LOCK_GRANT; 2230087a28d1SDavid Gwynne 2231087a28d1SDavid Gwynne bge_ape_put32(bgep, gnt + 4 * locknum, bit); 2232087a28d1SDavid Gwynne } 2233087a28d1SDavid Gwynne 2234087a28d1SDavid Gwynne /* wait for pending event to finish, if successful returns with MEM locked */ 2235087a28d1SDavid Gwynne static int 2236087a28d1SDavid Gwynne bge_ape_event_lock(bge_t *bgep, uint32_t timeout_us) 2237087a28d1SDavid Gwynne { 2238087a28d1SDavid Gwynne uint32_t apedata; 2239087a28d1SDavid Gwynne 2240087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_event_lock($%p, %d)", (void *)bgep, timeout_us)); 2241087a28d1SDavid Gwynne 2242087a28d1SDavid Gwynne ASSERT(timeout_us > 0); 2243087a28d1SDavid Gwynne 2244087a28d1SDavid Gwynne while (timeout_us) { 2245087a28d1SDavid Gwynne if (bge_ape_lock(bgep, BGE_APE_LOCK_MEM)) 2246087a28d1SDavid Gwynne return (-1); 2247087a28d1SDavid Gwynne 2248087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_EVENT_STATUS); 2249087a28d1SDavid Gwynne if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING)) 2250087a28d1SDavid Gwynne break; 2251087a28d1SDavid Gwynne 2252087a28d1SDavid Gwynne bge_ape_unlock(bgep, BGE_APE_LOCK_MEM); 2253087a28d1SDavid Gwynne 2254087a28d1SDavid Gwynne drv_usecwait(10); 2255087a28d1SDavid Gwynne timeout_us -= (timeout_us > 10) ? 10 : timeout_us; 2256087a28d1SDavid Gwynne } 2257087a28d1SDavid Gwynne 2258087a28d1SDavid Gwynne return (timeout_us ? 0 : -1); 2259087a28d1SDavid Gwynne } 2260087a28d1SDavid Gwynne 2261087a28d1SDavid Gwynne /* wait for pending event to finish, returns non-zero if not finished */ 2262087a28d1SDavid Gwynne static int 2263087a28d1SDavid Gwynne bge_ape_wait_for_event(bge_t *bgep, uint32_t timeout_us) 2264087a28d1SDavid Gwynne { 2265087a28d1SDavid Gwynne uint32_t i; 2266087a28d1SDavid Gwynne uint32_t apedata; 2267087a28d1SDavid Gwynne 2268087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_wait_for_event($%p, %d)", (void *)bgep, timeout_us)); 2269087a28d1SDavid Gwynne 2270087a28d1SDavid Gwynne ASSERT(timeout_us > 0); 2271087a28d1SDavid Gwynne 2272087a28d1SDavid Gwynne for (i = 0; i < timeout_us / 10; i++) { 2273087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_EVENT_STATUS); 2274087a28d1SDavid Gwynne 2275087a28d1SDavid Gwynne if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING)) 2276087a28d1SDavid Gwynne break; 2277087a28d1SDavid Gwynne 2278087a28d1SDavid Gwynne drv_usecwait(10); 2279087a28d1SDavid Gwynne } 2280087a28d1SDavid Gwynne 2281087a28d1SDavid Gwynne return (i == timeout_us / 10); 2282087a28d1SDavid Gwynne } 2283087a28d1SDavid Gwynne 2284087a28d1SDavid Gwynne int 2285087a28d1SDavid Gwynne bge_ape_scratchpad_read(bge_t *bgep, uint32_t *data, uint32_t base_off, 2286087a28d1SDavid Gwynne uint32_t lenToRead) 2287087a28d1SDavid Gwynne { 2288087a28d1SDavid Gwynne int err; 2289087a28d1SDavid Gwynne uint32_t i; 2290087a28d1SDavid Gwynne uint32_t bufoff; 2291087a28d1SDavid Gwynne uint32_t msgoff; 2292087a28d1SDavid Gwynne uint32_t maxlen; 2293087a28d1SDavid Gwynne uint32_t apedata; 2294087a28d1SDavid Gwynne 2295087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_scratchpad_read($%p, %p, 0x%0x, %d)", 2296087a28d1SDavid Gwynne (void *)bgep, (void*)data, base_off, lenToRead)); 2297087a28d1SDavid Gwynne 2298087a28d1SDavid Gwynne if (!bgep->ape_has_ncsi) 2299087a28d1SDavid Gwynne return (0); 2300087a28d1SDavid Gwynne 2301087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_SEG_SIG); 2302087a28d1SDavid Gwynne if (apedata != APE_SEG_SIG_MAGIC) 2303087a28d1SDavid Gwynne return (-1); 2304087a28d1SDavid Gwynne 2305087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_FW_STATUS); 2306087a28d1SDavid Gwynne if (!(apedata & APE_FW_STATUS_READY)) 2307087a28d1SDavid Gwynne return (-1); 2308087a28d1SDavid Gwynne 2309087a28d1SDavid Gwynne bufoff = (bge_ape_get32(bgep, BGE_APE_SEG_MSG_BUF_OFF) + 2310087a28d1SDavid Gwynne BGE_APE_SHMEM_BASE); 2311087a28d1SDavid Gwynne msgoff = bufoff + 2 * sizeof(uint32_t); 2312087a28d1SDavid Gwynne maxlen = bge_ape_get32(bgep, BGE_APE_SEG_MSG_BUF_LEN); 2313087a28d1SDavid Gwynne 2314087a28d1SDavid Gwynne while (lenToRead) { 2315087a28d1SDavid Gwynne uint32_t transferLen; 2316087a28d1SDavid Gwynne 2317087a28d1SDavid Gwynne /* Cap xfer sizes to scratchpad limits. */ 2318087a28d1SDavid Gwynne transferLen = (lenToRead > maxlen) ? maxlen : lenToRead; 2319087a28d1SDavid Gwynne lenToRead -= transferLen; 2320087a28d1SDavid Gwynne 2321087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_FW_STATUS); 2322087a28d1SDavid Gwynne if (!(apedata & APE_FW_STATUS_READY)) 2323087a28d1SDavid Gwynne return (-1); 2324087a28d1SDavid Gwynne 2325087a28d1SDavid Gwynne /* Wait for up to 1 millisecond for APE to service previous event. */ 2326087a28d1SDavid Gwynne err = bge_ape_event_lock(bgep, 1000); 2327087a28d1SDavid Gwynne if (err) 2328087a28d1SDavid Gwynne return (err); 2329087a28d1SDavid Gwynne 2330087a28d1SDavid Gwynne apedata = (APE_EVENT_STATUS_DRIVER_EVNT | 2331087a28d1SDavid Gwynne APE_EVENT_STATUS_SCRTCHPD_READ | 2332087a28d1SDavid Gwynne APE_EVENT_STATUS_EVENT_PENDING); 2333087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_EVENT_STATUS, apedata); 2334087a28d1SDavid Gwynne 2335087a28d1SDavid Gwynne bge_ape_put32(bgep, bufoff, base_off); 2336087a28d1SDavid Gwynne bge_ape_put32(bgep, bufoff + sizeof(uint32_t), transferLen); 2337087a28d1SDavid Gwynne 2338087a28d1SDavid Gwynne bge_ape_unlock(bgep, BGE_APE_LOCK_MEM); 2339087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_EVENT, APE_EVENT_1); 2340087a28d1SDavid Gwynne 2341087a28d1SDavid Gwynne base_off += transferLen; 2342087a28d1SDavid Gwynne 2343087a28d1SDavid Gwynne if (bge_ape_wait_for_event(bgep, 30000)) 2344087a28d1SDavid Gwynne return (-1); 2345087a28d1SDavid Gwynne 2346087a28d1SDavid Gwynne for (i = 0; transferLen; i += 4, transferLen -= 4) { 2347087a28d1SDavid Gwynne uint32_t val = bge_ape_get32(bgep, msgoff + i); 2348087a28d1SDavid Gwynne memcpy(data, &val, sizeof(uint32_t)); 2349087a28d1SDavid Gwynne data++; 2350087a28d1SDavid Gwynne } 2351087a28d1SDavid Gwynne } 2352087a28d1SDavid Gwynne 2353087a28d1SDavid Gwynne return (0); 2354087a28d1SDavid Gwynne } 2355087a28d1SDavid Gwynne 2356087a28d1SDavid Gwynne int 2357087a28d1SDavid Gwynne bge_ape_scratchpad_write(bge_t *bgep, uint32_t dstoff, uint32_t *data, 2358087a28d1SDavid Gwynne uint32_t lenToWrite) 2359087a28d1SDavid Gwynne { 2360087a28d1SDavid Gwynne int err; 2361087a28d1SDavid Gwynne uint32_t i; 2362087a28d1SDavid Gwynne uint32_t bufoff; 2363087a28d1SDavid Gwynne uint32_t msgoff; 2364087a28d1SDavid Gwynne uint32_t maxlen; 2365087a28d1SDavid Gwynne uint32_t apedata; 2366087a28d1SDavid Gwynne 2367087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_scratchpad_write($%p, %d, %p, %d)", 2368087a28d1SDavid Gwynne (void *)bgep, dstoff, data, lenToWrite)); 2369087a28d1SDavid Gwynne 2370087a28d1SDavid Gwynne if (!bgep->ape_has_ncsi) 2371087a28d1SDavid Gwynne return (0); 2372087a28d1SDavid Gwynne 2373087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_SEG_SIG); 2374087a28d1SDavid Gwynne if (apedata != APE_SEG_SIG_MAGIC) 2375087a28d1SDavid Gwynne return (-1); 2376087a28d1SDavid Gwynne 2377087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_FW_STATUS); 2378087a28d1SDavid Gwynne if (!(apedata & APE_FW_STATUS_READY)) 2379087a28d1SDavid Gwynne return (-1); 2380087a28d1SDavid Gwynne 2381087a28d1SDavid Gwynne bufoff = (bge_ape_get32(bgep, BGE_APE_SEG_MSG_BUF_OFF) + 2382087a28d1SDavid Gwynne BGE_APE_SHMEM_BASE); 2383087a28d1SDavid Gwynne msgoff = bufoff + 2 * sizeof(uint32_t); 2384087a28d1SDavid Gwynne maxlen = bge_ape_get32(bgep, BGE_APE_SEG_MSG_BUF_LEN); 2385087a28d1SDavid Gwynne 2386087a28d1SDavid Gwynne while (lenToWrite) { 2387087a28d1SDavid Gwynne uint32_t transferLen; 2388087a28d1SDavid Gwynne 2389087a28d1SDavid Gwynne /* Cap xfer sizes to scratchpad limits. */ 2390087a28d1SDavid Gwynne transferLen = (lenToWrite > maxlen) ? maxlen : lenToWrite; 2391087a28d1SDavid Gwynne lenToWrite -= transferLen; 2392087a28d1SDavid Gwynne 2393087a28d1SDavid Gwynne /* Wait for up to 1 millisecond for 2394087a28d1SDavid Gwynne * APE to service previous event. 2395087a28d1SDavid Gwynne */ 2396087a28d1SDavid Gwynne err = bge_ape_event_lock(bgep, 1000); 2397087a28d1SDavid Gwynne if (err) 2398087a28d1SDavid Gwynne return (err); 2399087a28d1SDavid Gwynne 2400087a28d1SDavid Gwynne bge_ape_put32(bgep, bufoff, dstoff); 2401087a28d1SDavid Gwynne bge_ape_put32(bgep, bufoff + sizeof(uint32_t), transferLen); 2402087a28d1SDavid Gwynne apedata = msgoff; 2403087a28d1SDavid Gwynne 2404087a28d1SDavid Gwynne dstoff += transferLen; 2405087a28d1SDavid Gwynne 2406087a28d1SDavid Gwynne for (i = 0; transferLen; i += 4, transferLen -= 4) { 2407087a28d1SDavid Gwynne bge_ape_put32(bgep, apedata, *data++); 2408087a28d1SDavid Gwynne apedata += sizeof(uint32_t); 2409087a28d1SDavid Gwynne } 2410087a28d1SDavid Gwynne 2411087a28d1SDavid Gwynne apedata = (APE_EVENT_STATUS_DRIVER_EVNT | 2412087a28d1SDavid Gwynne APE_EVENT_STATUS_SCRTCHPD_WRITE | 2413087a28d1SDavid Gwynne APE_EVENT_STATUS_EVENT_PENDING); 2414087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_EVENT_STATUS, apedata); 2415087a28d1SDavid Gwynne 2416087a28d1SDavid Gwynne bge_ape_unlock(bgep, BGE_APE_LOCK_MEM); 2417087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_EVENT, APE_EVENT_1); 2418087a28d1SDavid Gwynne } 2419087a28d1SDavid Gwynne 2420087a28d1SDavid Gwynne return (0); 2421087a28d1SDavid Gwynne } 2422087a28d1SDavid Gwynne 2423087a28d1SDavid Gwynne static int 2424087a28d1SDavid Gwynne bge_ape_send_event(bge_t *bgep, uint32_t event) 2425087a28d1SDavid Gwynne { 2426087a28d1SDavid Gwynne int err; 2427087a28d1SDavid Gwynne uint32_t apedata; 2428087a28d1SDavid Gwynne 2429087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_send_event($%p, %d)", (void *)bgep, event)); 2430087a28d1SDavid Gwynne 2431087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_SEG_SIG); 2432087a28d1SDavid Gwynne if (apedata != APE_SEG_SIG_MAGIC) 2433087a28d1SDavid Gwynne return (-1); 2434087a28d1SDavid Gwynne 2435087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_FW_STATUS); 2436087a28d1SDavid Gwynne if (!(apedata & APE_FW_STATUS_READY)) 2437087a28d1SDavid Gwynne return (-1); 2438087a28d1SDavid Gwynne 2439087a28d1SDavid Gwynne /* Wait for up to 1 millisecond for APE to service previous event. */ 2440087a28d1SDavid Gwynne err = bge_ape_event_lock(bgep, 1000); 2441087a28d1SDavid Gwynne if (err) 2442087a28d1SDavid Gwynne return (err); 2443087a28d1SDavid Gwynne 2444087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_EVENT_STATUS, 2445087a28d1SDavid Gwynne event | APE_EVENT_STATUS_EVENT_PENDING); 2446087a28d1SDavid Gwynne 2447087a28d1SDavid Gwynne bge_ape_unlock(bgep, BGE_APE_LOCK_MEM); 2448087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_EVENT, APE_EVENT_1); 2449087a28d1SDavid Gwynne 2450087a28d1SDavid Gwynne return 0; 2451087a28d1SDavid Gwynne } 2452087a28d1SDavid Gwynne 2453087a28d1SDavid Gwynne static void 2454087a28d1SDavid Gwynne bge_ape_driver_state_change(bge_t *bgep, int mode) 2455087a28d1SDavid Gwynne { 2456087a28d1SDavid Gwynne uint32_t event; 2457087a28d1SDavid Gwynne uint32_t apedata; 2458087a28d1SDavid Gwynne 2459087a28d1SDavid Gwynne BGE_TRACE(("bge_ape_driver_state_change($%p, %d)", 2460087a28d1SDavid Gwynne (void *)bgep, mode)); 2461087a28d1SDavid Gwynne 2462087a28d1SDavid Gwynne if (!bgep->ape_enabled) 2463087a28d1SDavid Gwynne return; 2464087a28d1SDavid Gwynne 2465087a28d1SDavid Gwynne switch (mode) { 2466087a28d1SDavid Gwynne case BGE_INIT_RESET: 2467087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_SEG_SIG, 2468087a28d1SDavid Gwynne APE_HOST_SEG_SIG_MAGIC); 2469087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_SEG_LEN, 2470087a28d1SDavid Gwynne APE_HOST_SEG_LEN_MAGIC); 2471087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_HOST_INIT_COUNT); 2472087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_INIT_COUNT, ++apedata); 2473087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_DRIVER_ID, 2474087a28d1SDavid Gwynne APE_HOST_DRIVER_ID_MAGIC(1, 0)); 2475087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_BEHAVIOR, 2476087a28d1SDavid Gwynne APE_HOST_BEHAV_NO_PHYLOCK); 2477087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_DRVR_STATE, 2478087a28d1SDavid Gwynne BGE_APE_HOST_DRVR_STATE_START); 2479087a28d1SDavid Gwynne 2480087a28d1SDavid Gwynne event = APE_EVENT_STATUS_STATE_START; 2481087a28d1SDavid Gwynne break; 2482087a28d1SDavid Gwynne case BGE_SHUTDOWN_RESET: 2483087a28d1SDavid Gwynne /* With the interface we are currently using, 2484087a28d1SDavid Gwynne * APE does not track driver state. Wiping 2485087a28d1SDavid Gwynne * out the HOST SEGMENT SIGNATURE forces 2486087a28d1SDavid Gwynne * the APE to assume OS absent status. 2487087a28d1SDavid Gwynne */ 2488087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_SEG_SIG, 0x0); 2489087a28d1SDavid Gwynne 2490087a28d1SDavid Gwynne #if 0 2491087a28d1SDavid Gwynne if (WOL supported) { 2492087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_WOL_SPEED, 2493087a28d1SDavid Gwynne BGE_APE_HOST_WOL_SPEED_AUTO); 2494087a28d1SDavid Gwynne apedata = BGE_APE_HOST_DRVR_STATE_WOL; 2495087a28d1SDavid Gwynne } else 2496087a28d1SDavid Gwynne #endif 2497087a28d1SDavid Gwynne apedata = BGE_APE_HOST_DRVR_STATE_UNLOAD; 2498087a28d1SDavid Gwynne 2499087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_DRVR_STATE, apedata); 2500087a28d1SDavid Gwynne 2501087a28d1SDavid Gwynne event = APE_EVENT_STATUS_STATE_UNLOAD; 2502087a28d1SDavid Gwynne break; 2503087a28d1SDavid Gwynne case BGE_SUSPEND_RESET: 2504087a28d1SDavid Gwynne event = APE_EVENT_STATUS_STATE_SUSPEND; 2505087a28d1SDavid Gwynne break; 2506087a28d1SDavid Gwynne default: 2507087a28d1SDavid Gwynne return; 2508087a28d1SDavid Gwynne } 2509087a28d1SDavid Gwynne 2510087a28d1SDavid Gwynne event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE; 2511087a28d1SDavid Gwynne 2512087a28d1SDavid Gwynne bge_ape_send_event(bgep, event); 2513087a28d1SDavid Gwynne } 2514087a28d1SDavid Gwynne 2515087a28d1SDavid Gwynne #undef BGE_DBG 251662387023Sdduvall #define BGE_DBG BGE_DBG_CHIP /* debug flag for this code */ 251762387023Sdduvall 251862387023Sdduvall static void 251962387023Sdduvall bge_init_recv_rule(bge_t *bgep) 252062387023Sdduvall { 2521da14cebeSEric Cheng bge_recv_rule_t *rulep = bgep->recv_rules; 252262387023Sdduvall uint32_t i; 252362387023Sdduvall 252462387023Sdduvall /* 2525da14cebeSEric Cheng * Initialize receive rule registers. 2526da14cebeSEric Cheng * Note that rules may persist across each bge_m_start/stop() call. 252762387023Sdduvall */ 252862387023Sdduvall for (i = 0; i < RECV_RULES_NUM_MAX; i++, rulep++) { 252962387023Sdduvall bge_reg_put32(bgep, RECV_RULE_MASK_REG(i), rulep->mask_value); 253062387023Sdduvall bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i), rulep->control); 253162387023Sdduvall } 253262387023Sdduvall } 253362387023Sdduvall 253462387023Sdduvall /* 253562387023Sdduvall * Using the values captured by bge_chip_cfg_init(), and additional probes 253662387023Sdduvall * as required, characterise the chip fully: determine the label by which 253762387023Sdduvall * to refer to this chip, the correct settings for various registers, and 253862387023Sdduvall * of course whether the device and/or subsystem are supported! 253962387023Sdduvall */ 254000d0963fSdilpreet int bge_chip_id_init(bge_t *bgep); 254162387023Sdduvall #pragma no_inline(bge_chip_id_init) 254262387023Sdduvall 254300d0963fSdilpreet int 254462387023Sdduvall bge_chip_id_init(bge_t *bgep) 254562387023Sdduvall { 254662387023Sdduvall char buf[MAXPATHLEN]; /* any risk of stack overflow? */ 254762387023Sdduvall boolean_t dev_ok; 254862387023Sdduvall chip_id_t *cidp; 254962387023Sdduvall uint32_t subid; 255062387023Sdduvall char *devname; 255162387023Sdduvall char *sysname; 255262387023Sdduvall int *ids; 255362387023Sdduvall int err; 255462387023Sdduvall uint_t i; 255562387023Sdduvall 2556087a28d1SDavid Gwynne dev_ok = B_FALSE; 255762387023Sdduvall cidp = &bgep->chipid; 255862387023Sdduvall 255962387023Sdduvall /* 256062387023Sdduvall * Check the PCI device ID to determine the generic chip type and 256162387023Sdduvall * select parameters that depend on this. 256262387023Sdduvall * 256362387023Sdduvall * Note: because the SPARC platforms in general don't fit the 256462387023Sdduvall * SEEPROM 'behind' the chip, the PCI revision ID register reads 256562387023Sdduvall * as zero - which is why we use <asic_rev> rather than <revision> 256662387023Sdduvall * below ... 256762387023Sdduvall * 256862387023Sdduvall * Note: in general we can't distinguish between the Copper/SerDes 256962387023Sdduvall * versions by ID alone, as some Copper devices (e.g. some but not 257062387023Sdduvall * all 5703Cs) have the same ID as the SerDes equivalents. So we 257162387023Sdduvall * treat them the same here, and the MII code works out the media 257262387023Sdduvall * type later on ... 257362387023Sdduvall */ 257462387023Sdduvall cidp->mbuf_base = bge_mbuf_pool_base; 257562387023Sdduvall cidp->mbuf_length = bge_mbuf_pool_len; 257662387023Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_USED; 257762387023Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl; 257862387023Sdduvall cidp->pci_type = BGE_PCI_X; 257962387023Sdduvall cidp->statistic_type = BGE_STAT_BLK; 25801b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = bge_mbuf_lo_water_rdma; 25811b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = bge_mbuf_lo_water_rmac; 25821b5c96f3Sly149593 cidp->mbuf_hi_water = bge_mbuf_hi_water; 2583e7801d59Ssowmini cidp->rx_ticks_norm = bge_rx_ticks_norm; 2584e7801d59Ssowmini cidp->rx_count_norm = bge_rx_count_norm; 25854d6eaea5Syong tan - Sun Microsystems - Beijing China cidp->tx_ticks_norm = bge_tx_ticks_norm; 25864d6eaea5Syong tan - Sun Microsystems - Beijing China cidp->tx_count_norm = bge_tx_count_norm; 2587dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->mask_pci_int = MHCR_MASK_PCI_INT_OUTPUT; 258862387023Sdduvall 258962387023Sdduvall if (cidp->rx_rings == 0 || cidp->rx_rings > BGE_RECV_RINGS_MAX) 259062387023Sdduvall cidp->rx_rings = BGE_RECV_RINGS_DEFAULT; 259162387023Sdduvall if (cidp->tx_rings == 0 || cidp->tx_rings > BGE_SEND_RINGS_MAX) 259262387023Sdduvall cidp->tx_rings = BGE_SEND_RINGS_DEFAULT; 259362387023Sdduvall 259462387023Sdduvall cidp->msi_enabled = B_FALSE; 259562387023Sdduvall 259662387023Sdduvall switch (cidp->device) { 2597224ef589Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5717: 2598dc3f9a75Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5718: 2599087a28d1SDavid Gwynne case DEVICE_ID_5719: 2600087a28d1SDavid Gwynne case DEVICE_ID_5720: 2601224ef589Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5724: 2602087a28d1SDavid Gwynne case DEVICE_ID_5725: 2603087a28d1SDavid Gwynne case DEVICE_ID_5727: 2604087a28d1SDavid Gwynne if (cidp->device == DEVICE_ID_5717) { 2605224ef589Syong tan - Sun Microsystems - Beijing China cidp->chip_label = 5717; 2606087a28d1SDavid Gwynne } else if (cidp->device == DEVICE_ID_5718) { 2607dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->chip_label = 5718; 2608087a28d1SDavid Gwynne } else if (cidp->device == DEVICE_ID_5719) { 2609087a28d1SDavid Gwynne cidp->chip_label = 5719; 2610087a28d1SDavid Gwynne } else if (cidp->device == DEVICE_ID_5720) { 2611087a28d1SDavid Gwynne if (pci_config_get16(bgep->cfg_handle, PCI_CONF_DEVID) == 2612087a28d1SDavid Gwynne DEVICE_ID_5717_C0) { 2613087a28d1SDavid Gwynne cidp->chip_label = 5717; 2614087a28d1SDavid Gwynne } else { 2615087a28d1SDavid Gwynne cidp->chip_label = 5720; 2616087a28d1SDavid Gwynne } 2617087a28d1SDavid Gwynne } else if (cidp->device == DEVICE_ID_5724) { 2618224ef589Syong tan - Sun Microsystems - Beijing China cidp->chip_label = 5724; 2619087a28d1SDavid Gwynne } else if (cidp->device == DEVICE_ID_5725) { 2620087a28d1SDavid Gwynne cidp->chip_label = 5725; 2621087a28d1SDavid Gwynne } else /* (cidp->device == DEVICE_ID_5727) */ { 2622087a28d1SDavid Gwynne cidp->chip_label = 5727; 2623087a28d1SDavid Gwynne } 2624dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->msi_enabled = bge_enable_msi; 2625dc3f9a75Syong tan - Sun Microsystems - Beijing China #ifdef __sparc 2626dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->mask_pci_int = LE_32(MHCR_MASK_PCI_INT_OUTPUT); 2627dc3f9a75Syong tan - Sun Microsystems - Beijing China #endif 2628dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->bge_dma_rwctrl = LE_32(PDRWCR_VAR_5717); 2629dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->pci_type = BGE_PCI_E; 2630dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 2631dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5717; 2632dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->mbuf_hi_water = MBUF_HIWAT_5717; 2633dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->mbuf_base = bge_mbuf_pool_base_5705; 2634dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->mbuf_length = bge_mbuf_pool_len_5705; 2635dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->recv_slots = BGE_RECV_SLOTS_5705; 2636dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->bge_mlcr_default = MLCR_DEFAULT_5717; 2637dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 2638dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 2639dc3f9a75Syong tan - Sun Microsystems - Beijing China cidp->statistic_type = BGE_STAT_REG; 2640dc3f9a75Syong tan - Sun Microsystems - Beijing China dev_ok = B_TRUE; 2641dc3f9a75Syong tan - Sun Microsystems - Beijing China break; 2642dc3f9a75Syong tan - Sun Microsystems - Beijing China 264362387023Sdduvall case DEVICE_ID_5700: 264462387023Sdduvall case DEVICE_ID_5700x: 264562387023Sdduvall cidp->chip_label = 5700; 2646256e438eSzh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 264762387023Sdduvall break; 264862387023Sdduvall 264962387023Sdduvall case DEVICE_ID_5701: 265062387023Sdduvall cidp->chip_label = 5701; 265162387023Sdduvall dev_ok = B_TRUE; 2652256e438eSzh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 265362387023Sdduvall break; 265462387023Sdduvall 265562387023Sdduvall case DEVICE_ID_5702: 265662387023Sdduvall case DEVICE_ID_5702fe: 265762387023Sdduvall cidp->chip_label = 5702; 265862387023Sdduvall dev_ok = B_TRUE; 2659256e438eSzh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 2660256e438eSzh199473 cidp->pci_type = BGE_PCI; 266162387023Sdduvall break; 266262387023Sdduvall 266362387023Sdduvall case DEVICE_ID_5703C: 266462387023Sdduvall case DEVICE_ID_5703S: 266562387023Sdduvall case DEVICE_ID_5703: 266662387023Sdduvall /* 266762387023Sdduvall * Revision A0 of the 5703/5793 had various errata 266862387023Sdduvall * that we can't or don't work around, so it's not 266962387023Sdduvall * supported, but all later versions are 267062387023Sdduvall */ 267162387023Sdduvall cidp->chip_label = cidp->subven == VENDOR_ID_SUN ? 5793 : 5703; 267262387023Sdduvall if (bgep->chipid.asic_rev != MHCR_CHIP_REV_5703_A0) 267362387023Sdduvall dev_ok = B_TRUE; 2674256e438eSzh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 267562387023Sdduvall break; 267662387023Sdduvall 267762387023Sdduvall case DEVICE_ID_5704C: 267862387023Sdduvall case DEVICE_ID_5704S: 267962387023Sdduvall case DEVICE_ID_5704: 268062387023Sdduvall cidp->chip_label = cidp->subven == VENDOR_ID_SUN ? 5794 : 5704; 268162387023Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5704; 268262387023Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5704; 268362387023Sdduvall dev_ok = B_TRUE; 2684256e438eSzh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 268562387023Sdduvall break; 268662387023Sdduvall 268762387023Sdduvall case DEVICE_ID_5705C: 268862387023Sdduvall case DEVICE_ID_5705M: 268962387023Sdduvall case DEVICE_ID_5705MA3: 269062387023Sdduvall case DEVICE_ID_5705F: 26917c966ec8Sml149210 case DEVICE_ID_5705_2: 2692ebd66af9Sml149210 case DEVICE_ID_5754: 2693ebd66af9Sml149210 if (cidp->device == DEVICE_ID_5754) { 2694ebd66af9Sml149210 cidp->chip_label = 5754; 2695ebd66af9Sml149210 cidp->pci_type = BGE_PCI_E; 2696ebd66af9Sml149210 } else { 269762387023Sdduvall cidp->chip_label = 5705; 2698ebd66af9Sml149210 cidp->pci_type = BGE_PCI; 26999f0e775cSyong tan - Sun Microsystems - Beijing China cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 2700ebd66af9Sml149210 } 27011b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 27021b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 27031b5c96f3Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 270462387023Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5705; 270562387023Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5705; 270662387023Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5705; 270762387023Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 27081b5c96f3Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 270962387023Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 271062387023Sdduvall cidp->statistic_type = BGE_STAT_REG; 271162387023Sdduvall dev_ok = B_TRUE; 271262387023Sdduvall break; 271362387023Sdduvall 27145a506a18Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5906: 27155a506a18Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5906M: 27165a506a18Syong tan - Sun Microsystems - Beijing China cidp->chip_label = 5906; 27175a506a18Syong tan - Sun Microsystems - Beijing China cidp->pci_type = BGE_PCI_E; 27185a506a18Syong tan - Sun Microsystems - Beijing China cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5906; 27195a506a18Syong tan - Sun Microsystems - Beijing China cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5906; 27205a506a18Syong tan - Sun Microsystems - Beijing China cidp->mbuf_hi_water = MBUF_HIWAT_5906; 27215a506a18Syong tan - Sun Microsystems - Beijing China cidp->mbuf_base = bge_mbuf_pool_base; 27225a506a18Syong tan - Sun Microsystems - Beijing China cidp->mbuf_length = bge_mbuf_pool_len; 27235a506a18Syong tan - Sun Microsystems - Beijing China cidp->recv_slots = BGE_RECV_SLOTS_5705; 27245a506a18Syong tan - Sun Microsystems - Beijing China cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 27255a506a18Syong tan - Sun Microsystems - Beijing China cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 27265a506a18Syong tan - Sun Microsystems - Beijing China cidp->flags |= CHIP_FLAG_NO_JUMBO; 27275a506a18Syong tan - Sun Microsystems - Beijing China cidp->statistic_type = BGE_STAT_REG; 27285a506a18Syong tan - Sun Microsystems - Beijing China dev_ok = B_TRUE; 27295a506a18Syong tan - Sun Microsystems - Beijing China break; 27305a506a18Syong tan - Sun Microsystems - Beijing China 2731a0a6bf1cSml149210 case DEVICE_ID_5753: 2732a0a6bf1cSml149210 cidp->chip_label = 5753; 2733a0a6bf1cSml149210 cidp->pci_type = BGE_PCI_E; 2734a0a6bf1cSml149210 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 2735a0a6bf1cSml149210 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 2736a0a6bf1cSml149210 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 2737a0a6bf1cSml149210 cidp->mbuf_base = bge_mbuf_pool_base_5705; 2738a0a6bf1cSml149210 cidp->mbuf_length = bge_mbuf_pool_len_5705; 2739a0a6bf1cSml149210 cidp->recv_slots = BGE_RECV_SLOTS_5705; 2740a0a6bf1cSml149210 cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 2741a0a6bf1cSml149210 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 2742a0a6bf1cSml149210 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 2743a0a6bf1cSml149210 cidp->flags |= CHIP_FLAG_NO_JUMBO; 2744a0a6bf1cSml149210 cidp->statistic_type = BGE_STAT_REG; 2745a0a6bf1cSml149210 dev_ok = B_TRUE; 2746a0a6bf1cSml149210 break; 2747a0a6bf1cSml149210 274803a69b52Sml149210 case DEVICE_ID_5755: 2749dca582a1Sgh162552 case DEVICE_ID_5755M: 275003a69b52Sml149210 cidp->chip_label = 5755; 275103a69b52Sml149210 cidp->pci_type = BGE_PCI_E; 275203a69b52Sml149210 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 275303a69b52Sml149210 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 275403a69b52Sml149210 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 275503a69b52Sml149210 cidp->mbuf_base = bge_mbuf_pool_base_5705; 275603a69b52Sml149210 cidp->mbuf_length = bge_mbuf_pool_len_5705; 275703a69b52Sml149210 cidp->recv_slots = BGE_RECV_SLOTS_5705; 275803a69b52Sml149210 cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 275903a69b52Sml149210 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 276003a69b52Sml149210 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 276103a69b52Sml149210 cidp->flags |= CHIP_FLAG_NO_JUMBO; 27629f0e775cSyong tan - Sun Microsystems - Beijing China if (cidp->device == DEVICE_ID_5755M) 276303a69b52Sml149210 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 276403a69b52Sml149210 cidp->statistic_type = BGE_STAT_REG; 276503a69b52Sml149210 dev_ok = B_TRUE; 276603a69b52Sml149210 break; 276703a69b52Sml149210 276867f41d5aSGordon Ross case DEVICE_ID_5756M: 276967f41d5aSGordon Ross /* 277067f41d5aSGordon Ross * This is nearly identical to the 5755M. 277167f41d5aSGordon Ross * (Actually reports the 5755 chip ID.) 277267f41d5aSGordon Ross */ 277367f41d5aSGordon Ross cidp->chip_label = 5756; 277467f41d5aSGordon Ross cidp->pci_type = BGE_PCI_E; 277567f41d5aSGordon Ross cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 277667f41d5aSGordon Ross cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 277767f41d5aSGordon Ross cidp->mbuf_hi_water = MBUF_HIWAT_5705; 277867f41d5aSGordon Ross cidp->mbuf_base = bge_mbuf_pool_base_5705; 277967f41d5aSGordon Ross cidp->mbuf_length = bge_mbuf_pool_len_5705; 278067f41d5aSGordon Ross cidp->recv_slots = BGE_RECV_SLOTS_5705; 278167f41d5aSGordon Ross cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 278267f41d5aSGordon Ross cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 278367f41d5aSGordon Ross cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 278467f41d5aSGordon Ross cidp->flags |= CHIP_FLAG_NO_JUMBO; 278567f41d5aSGordon Ross cidp->statistic_type = BGE_STAT_REG; 278667f41d5aSGordon Ross dev_ok = B_TRUE; 278767f41d5aSGordon Ross break; 278867f41d5aSGordon Ross 27897f7c96a6Sml40262 case DEVICE_ID_5787: 27907f7c96a6Sml40262 case DEVICE_ID_5787M: 27917f7c96a6Sml40262 cidp->chip_label = 5787; 27927f7c96a6Sml40262 cidp->pci_type = BGE_PCI_E; 27937f7c96a6Sml40262 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 27947f7c96a6Sml40262 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 27957f7c96a6Sml40262 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 27967f7c96a6Sml40262 cidp->mbuf_base = bge_mbuf_pool_base_5705; 27977f7c96a6Sml40262 cidp->mbuf_length = bge_mbuf_pool_len_5705; 27987f7c96a6Sml40262 cidp->recv_slots = BGE_RECV_SLOTS_5705; 27997f7c96a6Sml40262 cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 28007f7c96a6Sml40262 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 28017f7c96a6Sml40262 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 28027f7c96a6Sml40262 cidp->flags |= CHIP_FLAG_NO_JUMBO; 28037f7c96a6Sml40262 cidp->statistic_type = BGE_STAT_REG; 28047f7c96a6Sml40262 dev_ok = B_TRUE; 28057f7c96a6Sml40262 break; 28067f7c96a6Sml40262 280700d84294Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5723: 28087e420006Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5761: 28097e420006Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5761E: 2810224ef589Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_57780: 281100d84294Syong tan - Sun Microsystems - Beijing China cidp->msi_enabled = bge_enable_msi; 2812d7441963Syong tan - Sun Microsystems - Beijing China /* 2813652b4801Syong tan - Sun Microsystems - Beijing China * We don't use MSI for BCM5764 and BCM5785, as the 2814652b4801Syong tan - Sun Microsystems - Beijing China * status block may fail to update when the network 2815652b4801Syong tan - Sun Microsystems - Beijing China * traffic is heavy. 2816d7441963Syong tan - Sun Microsystems - Beijing China */ 2817d7441963Syong tan - Sun Microsystems - Beijing China /* FALLTHRU */ 2818652b4801Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5785: 2819d7441963Syong tan - Sun Microsystems - Beijing China case DEVICE_ID_5764: 2820d7441963Syong tan - Sun Microsystems - Beijing China if (cidp->device == DEVICE_ID_5723) 2821d7441963Syong tan - Sun Microsystems - Beijing China cidp->chip_label = 5723; 2822d7441963Syong tan - Sun Microsystems - Beijing China else if (cidp->device == DEVICE_ID_5764) 2823d7441963Syong tan - Sun Microsystems - Beijing China cidp->chip_label = 5764; 2824652b4801Syong tan - Sun Microsystems - Beijing China else if (cidp->device == DEVICE_ID_5785) 2825652b4801Syong tan - Sun Microsystems - Beijing China cidp->chip_label = 5785; 2826224ef589Syong tan - Sun Microsystems - Beijing China else if (cidp->device == DEVICE_ID_57780) 2827224ef589Syong tan - Sun Microsystems - Beijing China cidp->chip_label = 57780; 2828d7441963Syong tan - Sun Microsystems - Beijing China else 2829d7441963Syong tan - Sun Microsystems - Beijing China cidp->chip_label = 5761; 2830d7441963Syong tan - Sun Microsystems - Beijing China cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721; 283100d84294Syong tan - Sun Microsystems - Beijing China cidp->pci_type = BGE_PCI_E; 283200d84294Syong tan - Sun Microsystems - Beijing China cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 283300d84294Syong tan - Sun Microsystems - Beijing China cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 283400d84294Syong tan - Sun Microsystems - Beijing China cidp->mbuf_hi_water = MBUF_HIWAT_5705; 283500d84294Syong tan - Sun Microsystems - Beijing China cidp->mbuf_base = bge_mbuf_pool_base_5705; 283600d84294Syong tan - Sun Microsystems - Beijing China cidp->mbuf_length = bge_mbuf_pool_len_5705; 283700d84294Syong tan - Sun Microsystems - Beijing China cidp->recv_slots = BGE_RECV_SLOTS_5705; 283800d84294Syong tan - Sun Microsystems - Beijing China cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 283900d84294Syong tan - Sun Microsystems - Beijing China cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 284000d84294Syong tan - Sun Microsystems - Beijing China cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 284162387023Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 284200d84294Syong tan - Sun Microsystems - Beijing China cidp->statistic_type = BGE_STAT_REG; 284300d84294Syong tan - Sun Microsystems - Beijing China dev_ok = B_TRUE; 284462387023Sdduvall break; 284562387023Sdduvall 2846970f2798SCrisson Guanghao Hu /* PCI-X device, identical to 5714 */ 2847feb48d62SGarrett D'Amore case DEVICE_ID_5780: 2848feb48d62SGarrett D'Amore cidp->chip_label = 5780; 2849feb48d62SGarrett D'Amore cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 2850feb48d62SGarrett D'Amore cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 2851feb48d62SGarrett D'Amore cidp->mbuf_hi_water = MBUF_HIWAT_5705; 2852970f2798SCrisson Guanghao Hu cidp->mbuf_base = bge_mbuf_pool_base_5721; 2853970f2798SCrisson Guanghao Hu cidp->mbuf_length = bge_mbuf_pool_len_5721; 2854970f2798SCrisson Guanghao Hu cidp->recv_slots = BGE_RECV_SLOTS_5721; 2855feb48d62SGarrett D'Amore cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 2856feb48d62SGarrett D'Amore cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 2857feb48d62SGarrett D'Amore cidp->statistic_type = BGE_STAT_REG; 2858feb48d62SGarrett D'Amore dev_ok = B_TRUE; 2859feb48d62SGarrett D'Amore break; 2860feb48d62SGarrett D'Amore 286162387023Sdduvall case DEVICE_ID_5782: 286262387023Sdduvall /* 286362387023Sdduvall * Apart from the label, we treat this as a 5705(?) 286462387023Sdduvall */ 286562387023Sdduvall cidp->chip_label = 5782; 28661b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 28671b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 28681b5c96f3Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 286962387023Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5705; 287062387023Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5705; 287162387023Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5705; 287262387023Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 28731b5c96f3Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 287462387023Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 2875256e438eSzh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 287662387023Sdduvall cidp->statistic_type = BGE_STAT_REG; 287762387023Sdduvall dev_ok = B_TRUE; 287862387023Sdduvall break; 287962387023Sdduvall 288062387023Sdduvall case DEVICE_ID_5788: 288162387023Sdduvall /* 288262387023Sdduvall * Apart from the label, we treat this as a 5705(?) 288362387023Sdduvall */ 288462387023Sdduvall cidp->chip_label = 5788; 28851b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 28861b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 28871b5c96f3Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 288862387023Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5705; 288962387023Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5705; 289062387023Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5705; 289162387023Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 28921b5c96f3Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 289362387023Sdduvall cidp->statistic_type = BGE_STAT_REG; 289462387023Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 289562387023Sdduvall dev_ok = B_TRUE; 289662387023Sdduvall break; 289762387023Sdduvall 289862387023Sdduvall case DEVICE_ID_5714C: 289962387023Sdduvall if (cidp->revision >= REVISION_ID_5714_A2) 290062387023Sdduvall cidp->msi_enabled = bge_enable_msi; 290162387023Sdduvall /* FALLTHRU */ 290262387023Sdduvall case DEVICE_ID_5714S: 290362387023Sdduvall cidp->chip_label = 5714; 29041b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 29051b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 29061b5c96f3Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 290762387023Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5721; 290862387023Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5721; 290962387023Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5721; 291062387023Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl_5714; 291162387023Sdduvall cidp->bge_mlcr_default = bge_mlcr_default_5714; 291262387023Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 29131b5c96f3Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 291462387023Sdduvall cidp->pci_type = BGE_PCI_E; 291562387023Sdduvall cidp->statistic_type = BGE_STAT_REG; 291662387023Sdduvall dev_ok = B_TRUE; 291762387023Sdduvall break; 291862387023Sdduvall 291962387023Sdduvall case DEVICE_ID_5715C: 29207c966ec8Sml149210 case DEVICE_ID_5715S: 292162387023Sdduvall cidp->chip_label = 5715; 29221b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 29231b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 29241b5c96f3Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 292562387023Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5721; 292662387023Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5721; 292762387023Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5721; 292862387023Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl_5715; 292962387023Sdduvall cidp->bge_mlcr_default = bge_mlcr_default_5714; 293062387023Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 29311b5c96f3Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 293262387023Sdduvall cidp->pci_type = BGE_PCI_E; 293362387023Sdduvall cidp->statistic_type = BGE_STAT_REG; 29341b5c96f3Sly149593 if (cidp->revision >= REVISION_ID_5715_A2) 29351b5c96f3Sly149593 cidp->msi_enabled = bge_enable_msi; 293662387023Sdduvall dev_ok = B_TRUE; 293762387023Sdduvall break; 293862387023Sdduvall 293962387023Sdduvall case DEVICE_ID_5721: 294062387023Sdduvall cidp->chip_label = 5721; 29411b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 29421b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 29431b5c96f3Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 294462387023Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5721; 294562387023Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5721; 294662387023Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5721; 294762387023Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721; 294862387023Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 29491b5c96f3Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 295062387023Sdduvall cidp->pci_type = BGE_PCI_E; 295162387023Sdduvall cidp->statistic_type = BGE_STAT_REG; 295262387023Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 295362387023Sdduvall dev_ok = B_TRUE; 295462387023Sdduvall break; 295562387023Sdduvall 2956f0a5c2e3SCrisson Guanghao Hu case DEVICE_ID_5722: 2957f0a5c2e3SCrisson Guanghao Hu cidp->chip_label = 5722; 2958f0a5c2e3SCrisson Guanghao Hu cidp->pci_type = BGE_PCI_E; 2959f0a5c2e3SCrisson Guanghao Hu cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 2960f0a5c2e3SCrisson Guanghao Hu cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 2961f0a5c2e3SCrisson Guanghao Hu cidp->mbuf_hi_water = MBUF_HIWAT_5705; 2962f0a5c2e3SCrisson Guanghao Hu cidp->mbuf_base = bge_mbuf_pool_base_5705; 2963f0a5c2e3SCrisson Guanghao Hu cidp->mbuf_length = bge_mbuf_pool_len_5705; 2964f0a5c2e3SCrisson Guanghao Hu cidp->recv_slots = BGE_RECV_SLOTS_5705; 2965f0a5c2e3SCrisson Guanghao Hu cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 2966f0a5c2e3SCrisson Guanghao Hu cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 2967f0a5c2e3SCrisson Guanghao Hu cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 2968f0a5c2e3SCrisson Guanghao Hu cidp->flags |= CHIP_FLAG_NO_JUMBO; 2969f0a5c2e3SCrisson Guanghao Hu cidp->statistic_type = BGE_STAT_REG; 2970f0a5c2e3SCrisson Guanghao Hu dev_ok = B_TRUE; 2971f0a5c2e3SCrisson Guanghao Hu break; 2972f0a5c2e3SCrisson Guanghao Hu 297362387023Sdduvall case DEVICE_ID_5751: 297462387023Sdduvall case DEVICE_ID_5751M: 297562387023Sdduvall cidp->chip_label = 5751; 29761b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 29771b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 29781b5c96f3Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 297962387023Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5721; 298062387023Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5721; 298162387023Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5721; 298262387023Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721; 298362387023Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 29841b5c96f3Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 298562387023Sdduvall cidp->pci_type = BGE_PCI_E; 298662387023Sdduvall cidp->statistic_type = BGE_STAT_REG; 298762387023Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 298862387023Sdduvall dev_ok = B_TRUE; 298962387023Sdduvall break; 299062387023Sdduvall 2991f724721bSzh199473 case DEVICE_ID_5752: 2992f724721bSzh199473 case DEVICE_ID_5752M: 2993f724721bSzh199473 cidp->chip_label = 5752; 2994f724721bSzh199473 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 2995f724721bSzh199473 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 2996f724721bSzh199473 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 2997f724721bSzh199473 cidp->mbuf_base = bge_mbuf_pool_base_5721; 2998f724721bSzh199473 cidp->mbuf_length = bge_mbuf_pool_len_5721; 2999f724721bSzh199473 cidp->recv_slots = BGE_RECV_SLOTS_5721; 3000f724721bSzh199473 cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721; 3001f724721bSzh199473 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 3002f724721bSzh199473 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 3003f724721bSzh199473 cidp->pci_type = BGE_PCI_E; 3004f724721bSzh199473 cidp->statistic_type = BGE_STAT_REG; 3005f724721bSzh199473 cidp->flags |= CHIP_FLAG_NO_JUMBO; 3006f724721bSzh199473 dev_ok = B_TRUE; 3007f724721bSzh199473 break; 3008f724721bSzh199473 3009256e438eSzh199473 case DEVICE_ID_5789: 3010256e438eSzh199473 cidp->chip_label = 5789; 3011256e438eSzh199473 cidp->mbuf_base = bge_mbuf_pool_base_5721; 3012256e438eSzh199473 cidp->mbuf_length = bge_mbuf_pool_len_5721; 3013256e438eSzh199473 cidp->recv_slots = BGE_RECV_SLOTS_5721; 3014256e438eSzh199473 cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721; 3015256e438eSzh199473 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 3016256e438eSzh199473 cidp->tx_rings = BGE_RECV_RINGS_MAX_5705; 3017256e438eSzh199473 cidp->pci_type = BGE_PCI_E; 3018256e438eSzh199473 cidp->statistic_type = BGE_STAT_REG; 3019256e438eSzh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 3020256e438eSzh199473 cidp->flags |= CHIP_FLAG_NO_JUMBO; 3021256e438eSzh199473 cidp->msi_enabled = B_TRUE; 3022256e438eSzh199473 dev_ok = B_TRUE; 3023256e438eSzh199473 break; 3024256e438eSzh199473 302562387023Sdduvall } 302662387023Sdduvall 302762387023Sdduvall /* 302862387023Sdduvall * Setup the default jumbo parameter. 302962387023Sdduvall */ 303062387023Sdduvall cidp->ethmax_size = ETHERMAX; 303162387023Sdduvall cidp->snd_buff_size = BGE_SEND_BUFF_SIZE_DEFAULT; 30321b5c96f3Sly149593 cidp->std_buf_size = BGE_STD_BUFF_SIZE; 303362387023Sdduvall 303462387023Sdduvall /* 303562387023Sdduvall * If jumbo is enabled and this kind of chipset supports jumbo feature, 303662387023Sdduvall * setup below jumbo specific parameters. 30371b5c96f3Sly149593 * 30381b5c96f3Sly149593 * For BCM5714/5715, there is only one standard receive ring. So the 30391b5c96f3Sly149593 * std buffer size should be set to BGE_JUMBO_BUFF_SIZE when jumbo 30401b5c96f3Sly149593 * feature is enabled. 3041087a28d1SDavid Gwynne * 3042087a28d1SDavid Gwynne * For the BCM5718 family we hijack the standard receive ring for 3043087a28d1SDavid Gwynne * the jumboframe traffic, keeps it simple. 304462387023Sdduvall */ 304535bff3c2Syong tan - Sun Microsystems - Beijing China if (!(cidp->flags & CHIP_FLAG_NO_JUMBO) && 30466e6ed1baSyong tan - Sun Microsystems - Beijing China (cidp->default_mtu > BGE_DEFAULT_MTU)) { 3047087a28d1SDavid Gwynne if (DEVICE_5714_SERIES_CHIPSETS(bgep) || 3048087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 3049087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 30501b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = 30511b5c96f3Sly149593 RDMA_MBUF_LOWAT_5714_JUMBO; 30521b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = 30531b5c96f3Sly149593 MAC_RX_MBUF_LOWAT_5714_JUMBO; 30541b5c96f3Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5714_JUMBO; 30551b5c96f3Sly149593 cidp->jumbo_slots = 0; 30561b5c96f3Sly149593 cidp->std_buf_size = BGE_JUMBO_BUFF_SIZE; 30571b5c96f3Sly149593 } else { 30581b5c96f3Sly149593 cidp->mbuf_lo_water_rdma = 30591b5c96f3Sly149593 RDMA_MBUF_LOWAT_JUMBO; 30601b5c96f3Sly149593 cidp->mbuf_lo_water_rmac = 30611b5c96f3Sly149593 MAC_RX_MBUF_LOWAT_JUMBO; 306262387023Sdduvall cidp->mbuf_hi_water = MBUF_HIWAT_JUMBO; 30631b5c96f3Sly149593 cidp->jumbo_slots = BGE_JUMBO_SLOTS_USED; 30641b5c96f3Sly149593 } 306562387023Sdduvall cidp->recv_jumbo_size = BGE_JUMBO_BUFF_SIZE; 306662387023Sdduvall cidp->snd_buff_size = BGE_SEND_BUFF_SIZE_JUMBO; 306762387023Sdduvall cidp->ethmax_size = cidp->default_mtu + 306862387023Sdduvall sizeof (struct ether_header); 306962387023Sdduvall } 307062387023Sdduvall 307162387023Sdduvall /* 307262387023Sdduvall * Identify the NV memory type: SEEPROM or Flash? 307362387023Sdduvall */ 307462387023Sdduvall cidp->nvtype = bge_nvmem_id(bgep); 307562387023Sdduvall 307662387023Sdduvall /* 307762387023Sdduvall * Now check what we've discovered: is this truly a supported 307862387023Sdduvall * chip on (the motherboard of) a supported platform? 307962387023Sdduvall * 308062387023Sdduvall * Possible problems here: 30817e420006Syong tan - Sun Microsystems - Beijing China * 1) it's a completely unheard-of chip 308262387023Sdduvall * 2) it's a recognised but unsupported chip (e.g. 5701, 5703C-A0) 308362387023Sdduvall * 3) it's a chip we would support if it were on the motherboard 308462387023Sdduvall * of a Sun platform, but this one isn't ;-( 308562387023Sdduvall */ 308662387023Sdduvall if (cidp->chip_label == 0) 308762387023Sdduvall bge_problem(bgep, 308862387023Sdduvall "Device 'pci%04x,%04x' not recognized (%d?)", 308962387023Sdduvall cidp->vendor, cidp->device, cidp->device); 309062387023Sdduvall else if (!dev_ok) 309162387023Sdduvall bge_problem(bgep, 309262387023Sdduvall "Device 'pci%04x,%04x' (%d) revision %d not supported", 309362387023Sdduvall cidp->vendor, cidp->device, cidp->chip_label, 309462387023Sdduvall cidp->revision); 309562387023Sdduvall else 309662387023Sdduvall cidp->flags |= CHIP_FLAG_SUPPORTED; 3097087a28d1SDavid Gwynne 309800d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 309900d0963fSdilpreet return (EIO); 3100087a28d1SDavid Gwynne 310100d0963fSdilpreet return (0); 310262387023Sdduvall } 310362387023Sdduvall 310462387023Sdduvall void 310562387023Sdduvall bge_chip_msi_trig(bge_t *bgep) 310662387023Sdduvall { 310762387023Sdduvall uint32_t regval; 310862387023Sdduvall 310962387023Sdduvall regval = bgep->param_msi_cnt<<4; 311062387023Sdduvall bge_reg_set32(bgep, HOST_COALESCE_MODE_REG, regval); 311162387023Sdduvall BGE_DEBUG(("bge_chip_msi_trig:data = %d", regval)); 311262387023Sdduvall } 311362387023Sdduvall 311462387023Sdduvall /* 311562387023Sdduvall * Various registers that control the chip's internal engines (state 311662387023Sdduvall * machines) have a <reset> and <enable> bits (fortunately, in the 311762387023Sdduvall * same place in each such register :-). 311862387023Sdduvall * 311962387023Sdduvall * To reset the state machine, the <reset> bit must be written with 1; 312062387023Sdduvall * it will then read back as 1 while the reset is in progress, but 312162387023Sdduvall * self-clear to 0 when the reset completes. 312262387023Sdduvall * 312362387023Sdduvall * To enable a state machine, one must set the <enable> bit, which 312462387023Sdduvall * will continue to read back as 0 until the state machine is running. 312562387023Sdduvall * 312662387023Sdduvall * To disable a state machine, the <enable> bit must be cleared, but 312762387023Sdduvall * it will continue to read back as 1 until the state machine actually 312862387023Sdduvall * stops. 312962387023Sdduvall * 313062387023Sdduvall * This routine implements polling for completion of a reset, enable 313162387023Sdduvall * or disable operation, returning B_TRUE on success (bit reached the 313262387023Sdduvall * required state) or B_FALSE on timeout (200*100us == 20ms). 313362387023Sdduvall */ 313462387023Sdduvall static boolean_t bge_chip_poll_engine(bge_t *bgep, bge_regno_t regno, 313562387023Sdduvall uint32_t mask, uint32_t val); 313662387023Sdduvall #pragma no_inline(bge_chip_poll_engine) 313762387023Sdduvall 313862387023Sdduvall static boolean_t 313962387023Sdduvall bge_chip_poll_engine(bge_t *bgep, bge_regno_t regno, 314062387023Sdduvall uint32_t mask, uint32_t val) 314162387023Sdduvall { 314262387023Sdduvall uint32_t regval; 314362387023Sdduvall uint32_t n; 314462387023Sdduvall 314562387023Sdduvall BGE_TRACE(("bge_chip_poll_engine($%p, 0x%lx, 0x%x, 0x%x)", 314662387023Sdduvall (void *)bgep, regno, mask, val)); 314762387023Sdduvall 314862387023Sdduvall for (n = 200; n; --n) { 314962387023Sdduvall regval = bge_reg_get32(bgep, regno); 315062387023Sdduvall if ((regval & mask) == val) 315162387023Sdduvall return (B_TRUE); 315262387023Sdduvall drv_usecwait(100); 315362387023Sdduvall } 315462387023Sdduvall 315546ffce64Syong tan - Sun Microsystems - Beijing China bge_problem(bgep, "bge_chip_poll_engine failed: regno = 0x%lx", regno); 315600d0963fSdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE); 315762387023Sdduvall return (B_FALSE); 315862387023Sdduvall } 315962387023Sdduvall 316062387023Sdduvall /* 316162387023Sdduvall * Various registers that control the chip's internal engines (state 316262387023Sdduvall * machines) have a <reset> bit (fortunately, in the same place in 316362387023Sdduvall * each such register :-). To reset the state machine, this bit must 316462387023Sdduvall * be written with 1; it will then read back as 1 while the reset is 316562387023Sdduvall * in progress, but self-clear to 0 when the reset completes. 316662387023Sdduvall * 316762387023Sdduvall * This code sets the bit, then polls for it to read back as zero. 316862387023Sdduvall * The return value is B_TRUE on success (reset bit cleared itself), 316962387023Sdduvall * or B_FALSE if the state machine didn't recover :( 317062387023Sdduvall * 317162387023Sdduvall * NOTE: the Core reset is similar to other resets, except that we 317262387023Sdduvall * can't poll for completion, since the Core reset disables memory 317362387023Sdduvall * access! So we just have to assume that it will all complete in 317462387023Sdduvall * 100us. See Broadcom document 570X-PG102-R, p102, steps 4-5. 317562387023Sdduvall */ 317662387023Sdduvall static boolean_t bge_chip_reset_engine(bge_t *bgep, bge_regno_t regno); 317762387023Sdduvall #pragma no_inline(bge_chip_reset_engine) 317862387023Sdduvall 317962387023Sdduvall static boolean_t 318062387023Sdduvall bge_chip_reset_engine(bge_t *bgep, bge_regno_t regno) 318162387023Sdduvall { 318262387023Sdduvall uint32_t regval; 3183087a28d1SDavid Gwynne uint16_t val16; 318462387023Sdduvall uint32_t val32; 3185087a28d1SDavid Gwynne uint32_t mhcr; 318662387023Sdduvall 318762387023Sdduvall regval = bge_reg_get32(bgep, regno); 318862387023Sdduvall 318962387023Sdduvall BGE_TRACE(("bge_chip_reset_engine($%p, 0x%lx)", 319062387023Sdduvall (void *)bgep, regno)); 319162387023Sdduvall BGE_DEBUG(("bge_chip_reset_engine: 0x%lx before reset = 0x%08x", 319262387023Sdduvall regno, regval)); 319362387023Sdduvall 319462387023Sdduvall regval |= STATE_MACHINE_RESET_BIT; 319562387023Sdduvall 319662387023Sdduvall switch (regno) { 319762387023Sdduvall case MISC_CONFIG_REG: 319862387023Sdduvall /* 319962387023Sdduvall * BCM5714/5721/5751 pcie chip special case. In order to avoid 320062387023Sdduvall * resetting PCIE block and bringing PCIE link down, bit 29 320162387023Sdduvall * in the register needs to be set first, and then set it again 320262387023Sdduvall * while the reset bit is written. 320362387023Sdduvall * See:P500 of 57xx-PG102-RDS.pdf. 320462387023Sdduvall */ 320562387023Sdduvall if (DEVICE_5705_SERIES_CHIPSETS(bgep) || 3206dc3f9a75Syong tan - Sun Microsystems - Beijing China DEVICE_5717_SERIES_CHIPSETS(bgep) || 3207087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) || 320862387023Sdduvall DEVICE_5721_SERIES_CHIPSETS(bgep) || 320900d84294Syong tan - Sun Microsystems - Beijing China DEVICE_5723_SERIES_CHIPSETS(bgep) || 32105a506a18Syong tan - Sun Microsystems - Beijing China DEVICE_5714_SERIES_CHIPSETS(bgep) || 32115a506a18Syong tan - Sun Microsystems - Beijing China DEVICE_5906_SERIES_CHIPSETS(bgep)) { 321262387023Sdduvall regval |= MISC_CONFIG_GPHY_POWERDOWN_OVERRIDE; 321362387023Sdduvall if (bgep->chipid.pci_type == BGE_PCI_E) { 321462387023Sdduvall if (bgep->chipid.asic_rev == 321562387023Sdduvall MHCR_CHIP_REV_5751_A0 || 321662387023Sdduvall bgep->chipid.asic_rev == 321703a69b52Sml149210 MHCR_CHIP_REV_5721_A0 || 321803a69b52Sml149210 bgep->chipid.asic_rev == 321903a69b52Sml149210 MHCR_CHIP_REV_5755_A0) { 322062387023Sdduvall val32 = bge_reg_get32(bgep, 322162387023Sdduvall PHY_TEST_CTRL_REG); 322262387023Sdduvall if (val32 == (PHY_PCIE_SCRAM_MODE | 322362387023Sdduvall PHY_PCIE_LTASS_MODE)) 322462387023Sdduvall bge_reg_put32(bgep, 322562387023Sdduvall PHY_TEST_CTRL_REG, 322662387023Sdduvall PHY_PCIE_SCRAM_MODE); 322762387023Sdduvall val32 = pci_config_get32 322862387023Sdduvall (bgep->cfg_handle, 322962387023Sdduvall PCI_CONF_BGE_CLKCTL); 323062387023Sdduvall val32 |= CLKCTL_PCIE_A0_FIX; 323162387023Sdduvall pci_config_put32(bgep->cfg_handle, 323262387023Sdduvall PCI_CONF_BGE_CLKCTL, val32); 323362387023Sdduvall } 323462387023Sdduvall bge_reg_set32(bgep, regno, 323562387023Sdduvall MISC_CONFIG_GRC_RESET_DISABLE); 323662387023Sdduvall regval |= MISC_CONFIG_GRC_RESET_DISABLE; 323762387023Sdduvall } 323862387023Sdduvall } 323962387023Sdduvall 324062387023Sdduvall /* 324162387023Sdduvall * Special case - causes Core reset 324262387023Sdduvall * 324362387023Sdduvall * On SPARC v9 we want to ensure that we don't start 324462387023Sdduvall * timing until the I/O access has actually reached 324562387023Sdduvall * the chip, otherwise we might make the next access 324662387023Sdduvall * too early. And we can't just force the write out 324762387023Sdduvall * by following it with a read (even to config space) 324862387023Sdduvall * because that would cause the fault we're trying 324962387023Sdduvall * to avoid. Hence the need for membar_sync() here. 325062387023Sdduvall */ 325162387023Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, regno), regval); 325262387023Sdduvall #ifdef __sparcv9 325362387023Sdduvall membar_sync(); 325462387023Sdduvall #endif /* __sparcv9 */ 325562387023Sdduvall /* 325662387023Sdduvall * On some platforms,system need about 300us for 325762387023Sdduvall * link setup. 325862387023Sdduvall */ 325962387023Sdduvall drv_usecwait(300); 32605a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { 32615a506a18Syong tan - Sun Microsystems - Beijing China bge_reg_set32(bgep, VCPU_STATUS_REG, VCPU_DRV_RESET); 32625a506a18Syong tan - Sun Microsystems - Beijing China bge_reg_clr32( 32635a506a18Syong tan - Sun Microsystems - Beijing China bgep, VCPU_EXT_CTL, VCPU_EXT_CTL_HALF); 32645a506a18Syong tan - Sun Microsystems - Beijing China } 326562387023Sdduvall 326662387023Sdduvall if (bgep->chipid.pci_type == BGE_PCI_E) { 326762387023Sdduvall /* PCI-E device need more reset time */ 326862387023Sdduvall drv_usecwait(120000); 326962387023Sdduvall 3270087a28d1SDavid Gwynne /* 3271087a28d1SDavid Gwynne * (re)Disable interrupts as the bit can be reset after a 3272087a28d1SDavid Gwynne * core clock reset. 3273087a28d1SDavid Gwynne */ 3274087a28d1SDavid Gwynne mhcr = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MHCR); 3275087a28d1SDavid Gwynne pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, 3276087a28d1SDavid Gwynne mhcr | MHCR_MASK_PCI_INT_OUTPUT); 3277087a28d1SDavid Gwynne 327862387023Sdduvall /* Set PCIE max payload size and clear error status. */ 3279256e438eSzh199473 if ((bgep->chipid.chip_label == 5721) || 3280256e438eSzh199473 (bgep->chipid.chip_label == 5751) || 3281f724721bSzh199473 (bgep->chipid.chip_label == 5752) || 32825a506a18Syong tan - Sun Microsystems - Beijing China (bgep->chipid.chip_label == 5789) || 32835a506a18Syong tan - Sun Microsystems - Beijing China (bgep->chipid.chip_label == 5906)) { 328462387023Sdduvall pci_config_put16(bgep->cfg_handle, 328562387023Sdduvall PCI_CONF_DEV_CTRL, READ_REQ_SIZE_MAX); 328662387023Sdduvall pci_config_put16(bgep->cfg_handle, 328762387023Sdduvall PCI_CONF_DEV_STUS, DEVICE_ERROR_STUS); 328862387023Sdduvall } 328900d84294Syong tan - Sun Microsystems - Beijing China 32907e420006Syong tan - Sun Microsystems - Beijing China if ((bgep->chipid.chip_label == 5723) || 32917e420006Syong tan - Sun Microsystems - Beijing China (bgep->chipid.chip_label == 5761)) { 329200d84294Syong tan - Sun Microsystems - Beijing China pci_config_put16(bgep->cfg_handle, 329300d84294Syong tan - Sun Microsystems - Beijing China PCI_CONF_DEV_CTRL_5723, READ_REQ_SIZE_MAX); 329400d84294Syong tan - Sun Microsystems - Beijing China pci_config_put16(bgep->cfg_handle, 329500d84294Syong tan - Sun Microsystems - Beijing China PCI_CONF_DEV_STUS_5723, DEVICE_ERROR_STUS); 329600d84294Syong tan - Sun Microsystems - Beijing China } 3297087a28d1SDavid Gwynne 3298087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 3299087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 3300087a28d1SDavid Gwynne val16 = pci_config_get16(bgep->cfg_handle, 3301087a28d1SDavid Gwynne PCI_CONF_DEV_CTRL_5717); 3302087a28d1SDavid Gwynne val16 &= ~READ_REQ_SIZE_MASK; 3303087a28d1SDavid Gwynne val16 |= READ_REQ_SIZE_2K; 3304087a28d1SDavid Gwynne pci_config_put16(bgep->cfg_handle, 3305087a28d1SDavid Gwynne PCI_CONF_DEV_CTRL_5717, val16); 3306087a28d1SDavid Gwynne } 330762387023Sdduvall } 330862387023Sdduvall 330962387023Sdduvall BGE_PCICHK(bgep); 331062387023Sdduvall return (B_TRUE); 331162387023Sdduvall 331262387023Sdduvall default: 331362387023Sdduvall bge_reg_put32(bgep, regno, regval); 331462387023Sdduvall return (bge_chip_poll_engine(bgep, regno, 331562387023Sdduvall STATE_MACHINE_RESET_BIT, 0)); 331662387023Sdduvall } 331762387023Sdduvall } 331862387023Sdduvall 331962387023Sdduvall /* 332062387023Sdduvall * Various registers that control the chip's internal engines (state 332162387023Sdduvall * machines) have an <enable> bit (fortunately, in the same place in 332262387023Sdduvall * each such register :-). To stop the state machine, this bit must 332362387023Sdduvall * be written with 0, then polled to see when the state machine has 332462387023Sdduvall * actually stopped. 332562387023Sdduvall * 332662387023Sdduvall * The return value is B_TRUE on success (enable bit cleared), or 332762387023Sdduvall * B_FALSE if the state machine didn't stop :( 332862387023Sdduvall */ 332962387023Sdduvall static boolean_t bge_chip_disable_engine(bge_t *bgep, bge_regno_t regno, 333062387023Sdduvall uint32_t morebits); 333162387023Sdduvall #pragma no_inline(bge_chip_disable_engine) 333262387023Sdduvall 333362387023Sdduvall static boolean_t 333462387023Sdduvall bge_chip_disable_engine(bge_t *bgep, bge_regno_t regno, uint32_t morebits) 333562387023Sdduvall { 333662387023Sdduvall uint32_t regval; 333762387023Sdduvall 333862387023Sdduvall BGE_TRACE(("bge_chip_disable_engine($%p, 0x%lx, 0x%x)", 333962387023Sdduvall (void *)bgep, regno, morebits)); 334062387023Sdduvall 334162387023Sdduvall switch (regno) { 334262387023Sdduvall case FTQ_RESET_REG: 334362387023Sdduvall /* 3344a4de4ba2Sml149210 * For Schumacher's bugfix CR6490108 3345a4de4ba2Sml149210 */ 3346a4de4ba2Sml149210 #ifdef BGE_IPMI_ASF 3347a4de4ba2Sml149210 #ifdef BGE_NETCONSOLE 3348a4de4ba2Sml149210 if (bgep->asf_enabled) 3349a4de4ba2Sml149210 return (B_TRUE); 3350a4de4ba2Sml149210 #endif 3351a4de4ba2Sml149210 #endif 3352a4de4ba2Sml149210 /* 335362387023Sdduvall * Not quite like the others; it doesn't 335462387023Sdduvall * have an <enable> bit, but instead we 335562387023Sdduvall * have to set and then clear all the bits 335662387023Sdduvall */ 335762387023Sdduvall bge_reg_put32(bgep, regno, ~(uint32_t)0); 335862387023Sdduvall drv_usecwait(100); 335962387023Sdduvall bge_reg_put32(bgep, regno, 0); 336062387023Sdduvall return (B_TRUE); 336162387023Sdduvall 336262387023Sdduvall default: 3363087a28d1SDavid Gwynne if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 3364087a28d1SDavid Gwynne break; 3365087a28d1SDavid Gwynne } 3366087a28d1SDavid Gwynne 3367087a28d1SDavid Gwynne if ((regno == RCV_LIST_SELECTOR_MODE_REG) || 3368087a28d1SDavid Gwynne (regno == DMA_COMPLETION_MODE_REG) || 3369087a28d1SDavid Gwynne (regno == MBUF_CLUSTER_FREE_MODE_REG) || 3370087a28d1SDavid Gwynne (regno == BUFFER_MANAGER_MODE_REG) || 3371087a28d1SDavid Gwynne (regno == MEMORY_ARBITER_MODE_REG)) { 3372087a28d1SDavid Gwynne return B_TRUE; 3373087a28d1SDavid Gwynne } 3374087a28d1SDavid Gwynne 3375087a28d1SDavid Gwynne break; 3376087a28d1SDavid Gwynne } 3377087a28d1SDavid Gwynne 337862387023Sdduvall regval = bge_reg_get32(bgep, regno); 337962387023Sdduvall regval &= ~STATE_MACHINE_ENABLE_BIT; 338062387023Sdduvall regval &= ~morebits; 338162387023Sdduvall bge_reg_put32(bgep, regno, regval); 3382087a28d1SDavid Gwynne 3383087a28d1SDavid Gwynne return bge_chip_poll_engine(bgep, regno, STATE_MACHINE_ENABLE_BIT, 0); 338462387023Sdduvall } 338562387023Sdduvall 338662387023Sdduvall /* 338762387023Sdduvall * Various registers that control the chip's internal engines (state 338862387023Sdduvall * machines) have an <enable> bit (fortunately, in the same place in 338962387023Sdduvall * each such register :-). To start the state machine, this bit must 339062387023Sdduvall * be written with 1, then polled to see when the state machine has 339162387023Sdduvall * actually started. 339262387023Sdduvall * 339362387023Sdduvall * The return value is B_TRUE on success (enable bit set), or 339462387023Sdduvall * B_FALSE if the state machine didn't start :( 339562387023Sdduvall */ 339662387023Sdduvall static boolean_t bge_chip_enable_engine(bge_t *bgep, bge_regno_t regno, 339762387023Sdduvall uint32_t morebits); 339862387023Sdduvall #pragma no_inline(bge_chip_enable_engine) 339962387023Sdduvall 340062387023Sdduvall static boolean_t 340162387023Sdduvall bge_chip_enable_engine(bge_t *bgep, bge_regno_t regno, uint32_t morebits) 340262387023Sdduvall { 340362387023Sdduvall uint32_t regval; 340462387023Sdduvall 340562387023Sdduvall BGE_TRACE(("bge_chip_enable_engine($%p, 0x%lx, 0x%x)", 340662387023Sdduvall (void *)bgep, regno, morebits)); 340762387023Sdduvall 340862387023Sdduvall switch (regno) { 340962387023Sdduvall case FTQ_RESET_REG: 3410a4de4ba2Sml149210 #ifdef BGE_IPMI_ASF 3411a4de4ba2Sml149210 #ifdef BGE_NETCONSOLE 3412a4de4ba2Sml149210 if (bgep->asf_enabled) 3413a4de4ba2Sml149210 return (B_TRUE); 3414a4de4ba2Sml149210 #endif 3415a4de4ba2Sml149210 #endif 341662387023Sdduvall /* 341762387023Sdduvall * Not quite like the others; it doesn't 341862387023Sdduvall * have an <enable> bit, but instead we 341962387023Sdduvall * have to set and then clear all the bits 342062387023Sdduvall */ 342162387023Sdduvall bge_reg_put32(bgep, regno, ~(uint32_t)0); 342262387023Sdduvall drv_usecwait(100); 342362387023Sdduvall bge_reg_put32(bgep, regno, 0); 342462387023Sdduvall return (B_TRUE); 342562387023Sdduvall 342662387023Sdduvall default: 342762387023Sdduvall regval = bge_reg_get32(bgep, regno); 342862387023Sdduvall regval |= STATE_MACHINE_ENABLE_BIT; 342962387023Sdduvall regval |= morebits; 343062387023Sdduvall bge_reg_put32(bgep, regno, regval); 343162387023Sdduvall return (bge_chip_poll_engine(bgep, regno, 343262387023Sdduvall STATE_MACHINE_ENABLE_BIT, STATE_MACHINE_ENABLE_BIT)); 343362387023Sdduvall } 343462387023Sdduvall } 343562387023Sdduvall 343662387023Sdduvall /* 343762387023Sdduvall * Reprogram the Ethernet, Transmit, and Receive MAC 343862387023Sdduvall * modes to match the param_* variables 343962387023Sdduvall */ 3440e7801d59Ssowmini void bge_sync_mac_modes(bge_t *bgep); 344162387023Sdduvall #pragma no_inline(bge_sync_mac_modes) 344262387023Sdduvall 3443e7801d59Ssowmini void 344462387023Sdduvall bge_sync_mac_modes(bge_t *bgep) 344562387023Sdduvall { 344662387023Sdduvall uint32_t macmode; 344762387023Sdduvall uint32_t regval; 344862387023Sdduvall 344962387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 345062387023Sdduvall 345162387023Sdduvall /* 345262387023Sdduvall * Reprogram the Ethernet MAC mode ... 345362387023Sdduvall */ 345462387023Sdduvall macmode = regval = bge_reg_get32(bgep, ETHERNET_MAC_MODE_REG); 345562387023Sdduvall macmode &= ~ETHERNET_MODE_LINK_POLARITY; 345662387023Sdduvall macmode &= ~ETHERNET_MODE_PORTMODE_MASK; 345762387023Sdduvall if ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 34581a719488SCrisson Guanghao Hu (bgep->param_loop_mode != BGE_LOOP_INTERNAL_MAC)) { 3459087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 3460087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep) || 3461087a28d1SDavid Gwynne DEVICE_5714_SERIES_CHIPSETS(bgep)) 34621a719488SCrisson Guanghao Hu macmode |= ETHERNET_MODE_PORTMODE_GMII; 34631a719488SCrisson Guanghao Hu else 346462387023Sdduvall macmode |= ETHERNET_MODE_PORTMODE_TBI; 34651a719488SCrisson Guanghao Hu } else if (bgep->param_link_speed == 10 || 34661a719488SCrisson Guanghao Hu bgep->param_link_speed == 100) 346762387023Sdduvall macmode |= ETHERNET_MODE_PORTMODE_MII; 346862387023Sdduvall else 346962387023Sdduvall macmode |= ETHERNET_MODE_PORTMODE_GMII; 347062387023Sdduvall if (bgep->param_link_duplex == LINK_DUPLEX_HALF) 347162387023Sdduvall macmode |= ETHERNET_MODE_HALF_DUPLEX; 347262387023Sdduvall else 347362387023Sdduvall macmode &= ~ETHERNET_MODE_HALF_DUPLEX; 347462387023Sdduvall if (bgep->param_loop_mode == BGE_LOOP_INTERNAL_MAC) 347562387023Sdduvall macmode |= ETHERNET_MODE_MAC_LOOPBACK; 347662387023Sdduvall else 347762387023Sdduvall macmode &= ~ETHERNET_MODE_MAC_LOOPBACK; 347862387023Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, macmode); 347962387023Sdduvall BGE_DEBUG(("bge_sync_mac_modes($%p) Ethernet MAC mode 0x%x => 0x%x", 348062387023Sdduvall (void *)bgep, regval, macmode)); 348162387023Sdduvall 348262387023Sdduvall /* 348362387023Sdduvall * ... the Transmit MAC mode ... 348462387023Sdduvall */ 348562387023Sdduvall macmode = regval = bge_reg_get32(bgep, TRANSMIT_MAC_MODE_REG); 348662387023Sdduvall if (bgep->param_link_tx_pause) 348762387023Sdduvall macmode |= TRANSMIT_MODE_FLOW_CONTROL; 348862387023Sdduvall else 348962387023Sdduvall macmode &= ~TRANSMIT_MODE_FLOW_CONTROL; 349062387023Sdduvall bge_reg_put32(bgep, TRANSMIT_MAC_MODE_REG, macmode); 349162387023Sdduvall BGE_DEBUG(("bge_sync_mac_modes($%p) Transmit MAC mode 0x%x => 0x%x", 349262387023Sdduvall (void *)bgep, regval, macmode)); 349362387023Sdduvall 349462387023Sdduvall /* 349562387023Sdduvall * ... and the Receive MAC mode 349662387023Sdduvall */ 349762387023Sdduvall macmode = regval = bge_reg_get32(bgep, RECEIVE_MAC_MODE_REG); 349862387023Sdduvall if (bgep->param_link_rx_pause) 349962387023Sdduvall macmode |= RECEIVE_MODE_FLOW_CONTROL; 350062387023Sdduvall else 350162387023Sdduvall macmode &= ~RECEIVE_MODE_FLOW_CONTROL; 350262387023Sdduvall bge_reg_put32(bgep, RECEIVE_MAC_MODE_REG, macmode); 350362387023Sdduvall BGE_DEBUG(("bge_sync_mac_modes($%p) Receive MAC mode 0x%x => 0x%x", 350462387023Sdduvall (void *)bgep, regval, macmode)); 3505652b4801Syong tan - Sun Microsystems - Beijing China 3506652b4801Syong tan - Sun Microsystems - Beijing China /* 3507652b4801Syong tan - Sun Microsystems - Beijing China * For BCM5785, we need to configure the link status in the MI Status 3508652b4801Syong tan - Sun Microsystems - Beijing China * register with a write command when auto-polling is disabled. 3509652b4801Syong tan - Sun Microsystems - Beijing China */ 3510652b4801Syong tan - Sun Microsystems - Beijing China if (bgep->chipid.device == DEVICE_ID_5785) 3511652b4801Syong tan - Sun Microsystems - Beijing China if (bgep->param_link_speed == 10) 3512652b4801Syong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, MI_STATUS_REG, MI_STATUS_LINK 3513652b4801Syong tan - Sun Microsystems - Beijing China | MI_STATUS_10MBPS); 3514652b4801Syong tan - Sun Microsystems - Beijing China else 3515652b4801Syong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, MI_STATUS_REG, MI_STATUS_LINK); 351662387023Sdduvall } 351762387023Sdduvall 351862387023Sdduvall /* 351962387023Sdduvall * bge_chip_sync() -- program the chip with the unicast MAC address, 352062387023Sdduvall * the multicast hash table, the required level of promiscuity, and 352162387023Sdduvall * the current loopback mode ... 352262387023Sdduvall */ 352367f02347Srandyf #ifdef BGE_IPMI_ASF 352400d0963fSdilpreet int bge_chip_sync(bge_t *bgep, boolean_t asf_keeplive); 352567f02347Srandyf #else 352600d0963fSdilpreet int bge_chip_sync(bge_t *bgep); 352767f02347Srandyf #endif 352862387023Sdduvall #pragma no_inline(bge_chip_sync) 352962387023Sdduvall 353000d0963fSdilpreet int 353167f02347Srandyf #ifdef BGE_IPMI_ASF 353267f02347Srandyf bge_chip_sync(bge_t *bgep, boolean_t asf_keeplive) 353367f02347Srandyf #else 353462387023Sdduvall bge_chip_sync(bge_t *bgep) 353567f02347Srandyf #endif 353662387023Sdduvall { 353762387023Sdduvall void (*opfn)(bge_t *bgep, bge_regno_t reg, uint32_t bits); 353862387023Sdduvall boolean_t promisc; 353962387023Sdduvall uint64_t macaddr; 354027c3238fSyong tan - Sun Microsystems - Beijing China uint32_t fill = 0; 3541ed8845d8Skrgopi int i, j; 354200d0963fSdilpreet int retval = DDI_SUCCESS; 354362387023Sdduvall 354462387023Sdduvall BGE_TRACE(("bge_chip_sync($%p)", 354562387023Sdduvall (void *)bgep)); 354662387023Sdduvall 354762387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 354862387023Sdduvall 354962387023Sdduvall promisc = B_FALSE; 355062387023Sdduvall fill = ~(uint32_t)0; 355162387023Sdduvall 355262387023Sdduvall if (bgep->promisc) 355362387023Sdduvall promisc = B_TRUE; 355462387023Sdduvall else 355562387023Sdduvall fill = (uint32_t)0; 355662387023Sdduvall 355762387023Sdduvall /* 355862387023Sdduvall * If the TX/RX MAC engines are already running, we should stop 355962387023Sdduvall * them (and reset the RX engine) before changing the parameters. 356062387023Sdduvall * If they're not running, this will have no effect ... 356162387023Sdduvall * 356262387023Sdduvall * NOTE: this is currently disabled by default because stopping 356362387023Sdduvall * and restarting the Tx engine may cause an outgoing packet in 356462387023Sdduvall * transit to be truncated. Also, stopping and restarting the 356562387023Sdduvall * Rx engine seems to not work correctly on the 5705. Testing 356662387023Sdduvall * has not (yet!) revealed any problems with NOT stopping and 356762387023Sdduvall * restarting these engines (and Broadcom say their drivers don't 356862387023Sdduvall * do this), but if it is found to cause problems, this variable 356962387023Sdduvall * can be patched to re-enable the old behaviour ... 357062387023Sdduvall */ 357162387023Sdduvall if (bge_stop_start_on_sync) { 357267f02347Srandyf #ifdef BGE_IPMI_ASF 357300d0963fSdilpreet if (!bgep->asf_enabled) { 357400d0963fSdilpreet if (!bge_chip_disable_engine(bgep, 357500d0963fSdilpreet RECEIVE_MAC_MODE_REG, RECEIVE_MODE_KEEP_VLAN_TAG)) 357600d0963fSdilpreet retval = DDI_FAILURE; 357767f02347Srandyf } else { 357800d0963fSdilpreet if (!bge_chip_disable_engine(bgep, 357900d0963fSdilpreet RECEIVE_MAC_MODE_REG, 0)) 358000d0963fSdilpreet retval = DDI_FAILURE; 358167f02347Srandyf } 358267f02347Srandyf #else 358300d0963fSdilpreet if (!bge_chip_disable_engine(bgep, RECEIVE_MAC_MODE_REG, 358400d0963fSdilpreet RECEIVE_MODE_KEEP_VLAN_TAG)) 358500d0963fSdilpreet retval = DDI_FAILURE; 358667f02347Srandyf #endif 358700d0963fSdilpreet if (!bge_chip_disable_engine(bgep, TRANSMIT_MAC_MODE_REG, 0)) 358800d0963fSdilpreet retval = DDI_FAILURE; 358900d0963fSdilpreet if (!bge_chip_reset_engine(bgep, RECEIVE_MAC_MODE_REG)) 359000d0963fSdilpreet retval = DDI_FAILURE; 359162387023Sdduvall } 359262387023Sdduvall 359362387023Sdduvall /* 359462387023Sdduvall * Reprogram the hashed multicast address table ... 359562387023Sdduvall */ 359662387023Sdduvall for (i = 0; i < BGE_HASH_TABLE_SIZE/32; ++i) 3597dca582a1Sgh162552 bge_reg_put32(bgep, MAC_HASH_REG(i), 0); 3598dca582a1Sgh162552 3599dca582a1Sgh162552 for (i = 0; i < BGE_HASH_TABLE_SIZE/32; ++i) 360062387023Sdduvall bge_reg_put32(bgep, MAC_HASH_REG(i), 360162387023Sdduvall bgep->mcast_hash[i] | fill); 360262387023Sdduvall 360367f02347Srandyf #ifdef BGE_IPMI_ASF 360467f02347Srandyf if (!bgep->asf_enabled || !asf_keeplive) { 360567f02347Srandyf #endif 360662387023Sdduvall /* 3607ed8845d8Skrgopi * Transform the MAC address(es) from host to chip format, then 360862387023Sdduvall * reprogram the transmit random backoff seed and the unicast 360962387023Sdduvall * MAC address(es) ... 361062387023Sdduvall */ 3611ed8845d8Skrgopi for (j = 0; j < MAC_ADDRESS_REGS_MAX; j++) { 361227c3238fSyong tan - Sun Microsystems - Beijing China for (i = 0, macaddr = 0ull; 3613ed8845d8Skrgopi i < ETHERADDRL; ++i) { 361462387023Sdduvall macaddr <<= 8; 3615ed8845d8Skrgopi macaddr |= bgep->curr_addr[j].addr[i]; 361662387023Sdduvall } 361727c3238fSyong tan - Sun Microsystems - Beijing China fill += (macaddr >> 16) + (macaddr & 0xffffffff); 3618ed8845d8Skrgopi bge_reg_put64(bgep, MAC_ADDRESS_REG(j), macaddr); 361962387023Sdduvall 3620da14cebeSEric Cheng BGE_DEBUG(("bge_chip_sync($%p) " 3621da14cebeSEric Cheng "setting MAC address %012llx", 362262387023Sdduvall (void *)bgep, macaddr)); 3623da14cebeSEric Cheng } 362467f02347Srandyf #ifdef BGE_IPMI_ASF 362567f02347Srandyf } 362667f02347Srandyf #endif 362727c3238fSyong tan - Sun Microsystems - Beijing China /* 362827c3238fSyong tan - Sun Microsystems - Beijing China * Set random seed of backoff interval 362927c3238fSyong tan - Sun Microsystems - Beijing China * - Writing zero means no backoff interval 363027c3238fSyong tan - Sun Microsystems - Beijing China */ 363127c3238fSyong tan - Sun Microsystems - Beijing China fill = ((fill >> 20) + (fill >> 10) + fill) & 0x3ff; 363227c3238fSyong tan - Sun Microsystems - Beijing China if (fill == 0) 363327c3238fSyong tan - Sun Microsystems - Beijing China fill = 1; 363427c3238fSyong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, MAC_TX_RANDOM_BACKOFF_REG, fill); 363562387023Sdduvall 363662387023Sdduvall /* 363762387023Sdduvall * Set or clear the PROMISCUOUS mode bit 363862387023Sdduvall */ 363962387023Sdduvall opfn = promisc ? bge_reg_set32 : bge_reg_clr32; 364062387023Sdduvall (*opfn)(bgep, RECEIVE_MAC_MODE_REG, RECEIVE_MODE_PROMISCUOUS); 364162387023Sdduvall 364262387023Sdduvall /* 364362387023Sdduvall * Sync the rest of the MAC modes too ... 364462387023Sdduvall */ 364562387023Sdduvall bge_sync_mac_modes(bgep); 364662387023Sdduvall 364762387023Sdduvall /* 364862387023Sdduvall * Restart RX/TX MAC engines if required ... 364962387023Sdduvall */ 365062387023Sdduvall if (bgep->bge_chip_state == BGE_CHIP_RUNNING) { 365100d0963fSdilpreet if (!bge_chip_enable_engine(bgep, TRANSMIT_MAC_MODE_REG, 0)) 365200d0963fSdilpreet retval = DDI_FAILURE; 365367f02347Srandyf #ifdef BGE_IPMI_ASF 365400d0963fSdilpreet if (!bgep->asf_enabled) { 365500d0963fSdilpreet if (!bge_chip_enable_engine(bgep, 365600d0963fSdilpreet RECEIVE_MAC_MODE_REG, RECEIVE_MODE_KEEP_VLAN_TAG)) 365700d0963fSdilpreet retval = DDI_FAILURE; 365867f02347Srandyf } else { 365900d0963fSdilpreet if (!bge_chip_enable_engine(bgep, 366000d0963fSdilpreet RECEIVE_MAC_MODE_REG, 0)) 366100d0963fSdilpreet retval = DDI_FAILURE; 366267f02347Srandyf } 366367f02347Srandyf #else 366400d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RECEIVE_MAC_MODE_REG, 366500d0963fSdilpreet RECEIVE_MODE_KEEP_VLAN_TAG)) 366600d0963fSdilpreet retval = DDI_FAILURE; 366767f02347Srandyf #endif 366862387023Sdduvall } 366900d0963fSdilpreet return (retval); 367062387023Sdduvall } 367162387023Sdduvall 367219397407SSherry Moore #ifndef __sparc 367319397407SSherry Moore static bge_regno_t quiesce_regs[] = { 367419397407SSherry Moore READ_DMA_MODE_REG, 367519397407SSherry Moore DMA_COMPLETION_MODE_REG, 367619397407SSherry Moore WRITE_DMA_MODE_REG, 367719397407SSherry Moore BGE_REGNO_NONE 367819397407SSherry Moore }; 367919397407SSherry Moore 368019397407SSherry Moore void bge_chip_stop_nonblocking(bge_t *bgep); 368119397407SSherry Moore #pragma no_inline(bge_chip_stop_nonblocking) 368219397407SSherry Moore 368319397407SSherry Moore /* 368419397407SSherry Moore * This function is called by bge_quiesce(). We 368519397407SSherry Moore * turn off all the DMA engines here. 368619397407SSherry Moore */ 368719397407SSherry Moore void 368819397407SSherry Moore bge_chip_stop_nonblocking(bge_t *bgep) 368919397407SSherry Moore { 369019397407SSherry Moore bge_regno_t *rbp; 369119397407SSherry Moore 369219397407SSherry Moore /* 369319397407SSherry Moore * Flag that no more activity may be initiated 369419397407SSherry Moore */ 369519397407SSherry Moore bgep->progress &= ~PROGRESS_READY; 369619397407SSherry Moore 369719397407SSherry Moore rbp = quiesce_regs; 369819397407SSherry Moore while (*rbp != BGE_REGNO_NONE) { 369919397407SSherry Moore (void) bge_chip_disable_engine(bgep, *rbp, 0); 370019397407SSherry Moore ++rbp; 370119397407SSherry Moore } 370219397407SSherry Moore 370319397407SSherry Moore bgep->bge_chip_state = BGE_CHIP_STOPPED; 370419397407SSherry Moore } 370519397407SSherry Moore 370619397407SSherry Moore #endif 370719397407SSherry Moore 370862387023Sdduvall /* 370962387023Sdduvall * bge_chip_stop() -- stop all chip processing 371062387023Sdduvall * 371162387023Sdduvall * If the <fault> parameter is B_TRUE, we're stopping the chip because 371262387023Sdduvall * we've detected a problem internally; otherwise, this is a normal 371362387023Sdduvall * (clean) stop (at user request i.e. the last STREAM has been closed). 371462387023Sdduvall */ 371562387023Sdduvall void bge_chip_stop(bge_t *bgep, boolean_t fault); 371662387023Sdduvall #pragma no_inline(bge_chip_stop) 371762387023Sdduvall 371862387023Sdduvall void 371962387023Sdduvall bge_chip_stop(bge_t *bgep, boolean_t fault) 372062387023Sdduvall { 372162387023Sdduvall bge_regno_t regno; 372262387023Sdduvall bge_regno_t *rbp; 3723087a28d1SDavid Gwynne boolean_t ok = B_TRUE; 372462387023Sdduvall 372562387023Sdduvall BGE_TRACE(("bge_chip_stop($%p)", 372662387023Sdduvall (void *)bgep)); 372762387023Sdduvall 372862387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 372962387023Sdduvall 3730087a28d1SDavid Gwynne pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, 3731087a28d1SDavid Gwynne (pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MHCR) | 3732087a28d1SDavid Gwynne MHCR_MASK_PCI_INT_OUTPUT)); 3733087a28d1SDavid Gwynne 3734087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, RECEIVE_MAC_MODE_REG, 0); 3735087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, RCV_BD_INITIATOR_MODE_REG, 0); 3736087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, RCV_LIST_PLACEMENT_MODE_REG, 0); 3737087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, RCV_LIST_SELECTOR_MODE_REG, 0); 3738087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, RCV_DATA_BD_INITIATOR_MODE_REG, 0); 3739087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, RCV_DATA_COMPLETION_MODE_REG, 0); 3740087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, RCV_BD_COMPLETION_MODE_REG, 0); 3741087a28d1SDavid Gwynne 3742087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, SEND_BD_SELECTOR_MODE_REG, 0); 3743087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, SEND_BD_INITIATOR_MODE_REG, 0); 3744087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, SEND_DATA_INITIATOR_MODE_REG, 0); 3745087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, READ_DMA_MODE_REG, 0); 3746087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, SEND_DATA_COMPLETION_MODE_REG, 0); 3747087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, DMA_COMPLETION_MODE_REG, 0); 3748087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, SEND_BD_COMPLETION_MODE_REG, 0); 3749087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, TRANSMIT_MAC_MODE_REG, 0); 3750087a28d1SDavid Gwynne 3751087a28d1SDavid Gwynne bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_ENABLE_TDE); 3752087a28d1SDavid Gwynne drv_usecwait(40); 3753087a28d1SDavid Gwynne 3754087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, HOST_COALESCE_MODE_REG, 0); 3755087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, WRITE_DMA_MODE_REG, 0); 3756087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, MBUF_CLUSTER_FREE_MODE_REG, 0); 3757087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, FTQ_RESET_REG, 0); 3758087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, BUFFER_MANAGER_MODE_REG, 0); 3759087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, MEMORY_ARBITER_MODE_REG, 0); 3760087a28d1SDavid Gwynne ok &= bge_chip_disable_engine(bgep, MEMORY_ARBITER_MODE_REG, 0); 376162387023Sdduvall 376200d0963fSdilpreet if (!ok && !fault) 376300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 376400d0963fSdilpreet 376562387023Sdduvall /* 376662387023Sdduvall * Finally, disable (all) MAC events & clear the MAC status 376762387023Sdduvall */ 376862387023Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_EVENT_ENABLE_REG, 0); 376962387023Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_STATUS_REG, ~0); 377062387023Sdduvall 377162387023Sdduvall /* 377200d0963fSdilpreet * if we're stopping the chip because of a detected fault then do 377300d0963fSdilpreet * appropriate actions 377462387023Sdduvall */ 377500d0963fSdilpreet if (fault) { 377600d0963fSdilpreet if (bgep->bge_chip_state != BGE_CHIP_FAULT) { 377762387023Sdduvall bgep->bge_chip_state = BGE_CHIP_FAULT; 3778e7801d59Ssowmini if (!bgep->manual_reset) 3779e7801d59Ssowmini ddi_fm_service_impact(bgep->devinfo, 3780e7801d59Ssowmini DDI_SERVICE_LOST); 378100d0963fSdilpreet if (bgep->bge_dma_error) { 378200d0963fSdilpreet /* 378300d0963fSdilpreet * need to free buffers in case the fault was 378400d0963fSdilpreet * due to a memory error in a buffer - got to 378500d0963fSdilpreet * do a fair bit of tidying first 378600d0963fSdilpreet */ 378700d0963fSdilpreet if (bgep->progress & PROGRESS_KSTATS) { 378800d0963fSdilpreet bge_fini_kstats(bgep); 378900d0963fSdilpreet bgep->progress &= ~PROGRESS_KSTATS; 379000d0963fSdilpreet } 379100d0963fSdilpreet if (bgep->progress & PROGRESS_INTR) { 379200d0963fSdilpreet bge_intr_disable(bgep); 379300d0963fSdilpreet rw_enter(bgep->errlock, RW_WRITER); 379400d0963fSdilpreet bge_fini_rings(bgep); 379500d0963fSdilpreet rw_exit(bgep->errlock); 379600d0963fSdilpreet bgep->progress &= ~PROGRESS_INTR; 379700d0963fSdilpreet } 379800d0963fSdilpreet if (bgep->progress & PROGRESS_BUFS) { 379900d0963fSdilpreet bge_free_bufs(bgep); 380000d0963fSdilpreet bgep->progress &= ~PROGRESS_BUFS; 380100d0963fSdilpreet } 380200d0963fSdilpreet bgep->bge_dma_error = B_FALSE; 380300d0963fSdilpreet } 380400d0963fSdilpreet } 380500d0963fSdilpreet } else 380662387023Sdduvall bgep->bge_chip_state = BGE_CHIP_STOPPED; 380762387023Sdduvall } 380862387023Sdduvall 380962387023Sdduvall /* 381062387023Sdduvall * Poll for completion of chip's ROM firmware; also, at least on the 381162387023Sdduvall * first time through, find and return the hardware MAC address, if any. 381262387023Sdduvall */ 381362387023Sdduvall static uint64_t bge_poll_firmware(bge_t *bgep); 381462387023Sdduvall #pragma no_inline(bge_poll_firmware) 381562387023Sdduvall 381662387023Sdduvall static uint64_t 381762387023Sdduvall bge_poll_firmware(bge_t *bgep) 381862387023Sdduvall { 381962387023Sdduvall uint64_t magic; 382062387023Sdduvall uint64_t mac; 38215a506a18Syong tan - Sun Microsystems - Beijing China uint32_t gen, val; 382262387023Sdduvall uint32_t i; 382362387023Sdduvall 382462387023Sdduvall /* 382562387023Sdduvall * Step 19: poll for firmware completion (GENCOMM port set 382662387023Sdduvall * to the ones complement of T3_MAGIC_NUMBER). 382762387023Sdduvall * 382862387023Sdduvall * While we're at it, we also read the MAC address register; 3829256e438eSzh199473 * at some stage the firmware will load this with the 383062387023Sdduvall * factory-set value. 383162387023Sdduvall * 383262387023Sdduvall * When both the magic number and the MAC address are set, 383362387023Sdduvall * we're done; but we impose a time limit of one second 383462387023Sdduvall * (1000*1000us) in case the firmware fails in some fashion 383562387023Sdduvall * or the SEEPROM that provides that MAC address isn't fitted. 383662387023Sdduvall * 383762387023Sdduvall * After the first time through (chip state != INITIAL), we 383862387023Sdduvall * don't need the MAC address to be set (we've already got it 383962387023Sdduvall * or not, from the first time), so we don't wait for it, but 384062387023Sdduvall * we still have to wait for the T3_MAGIC_NUMBER. 384162387023Sdduvall * 384262387023Sdduvall * Note: the magic number is only a 32-bit quantity, but the NIC 384362387023Sdduvall * memory is 64-bit (and big-endian) internally. Addressing the 384462387023Sdduvall * GENCOMM word as "the upper half of a 64-bit quantity" makes 384562387023Sdduvall * it work correctly on both big- and little-endian hosts. 384662387023Sdduvall */ 3847087a28d1SDavid Gwynne if (MHCR_CHIP_ASIC_REV(bgep) == MHCR_CHIP_ASIC_REV_5906) { 38485a506a18Syong tan - Sun Microsystems - Beijing China for (i = 0; i < 1000; ++i) { 38495a506a18Syong tan - Sun Microsystems - Beijing China drv_usecwait(1000); 38505a506a18Syong tan - Sun Microsystems - Beijing China val = bge_reg_get32(bgep, VCPU_STATUS_REG); 38515a506a18Syong tan - Sun Microsystems - Beijing China if (val & VCPU_INIT_DONE) 38525a506a18Syong tan - Sun Microsystems - Beijing China break; 38535a506a18Syong tan - Sun Microsystems - Beijing China } 38545a506a18Syong tan - Sun Microsystems - Beijing China BGE_DEBUG(("bge_poll_firmware($%p): return after %d loops", 38555a506a18Syong tan - Sun Microsystems - Beijing China (void *)bgep, i)); 38565a506a18Syong tan - Sun Microsystems - Beijing China mac = bge_reg_get64(bgep, MAC_ADDRESS_REG(0)); 38575a506a18Syong tan - Sun Microsystems - Beijing China } else { 385862387023Sdduvall for (i = 0; i < 1000; ++i) { 385962387023Sdduvall drv_usecwait(1000); 386062387023Sdduvall gen = bge_nic_get64(bgep, NIC_MEM_GENCOMM) >> 32; 3861087a28d1SDavid Gwynne if (i == 0 && DEVICE_5704_SERIES_CHIPSETS(bgep)) 3862087a28d1SDavid Gwynne drv_usecwait(100000); 3863087a28d1SDavid Gwynne mac = bge_reg_get64(bgep, MAC_ADDRESS_REG(0)); 386467f02347Srandyf #ifdef BGE_IPMI_ASF 386567f02347Srandyf if (!bgep->asf_enabled) { 386667f02347Srandyf #endif 386762387023Sdduvall if (gen != ~T3_MAGIC_NUMBER) 386862387023Sdduvall continue; 386967f02347Srandyf #ifdef BGE_IPMI_ASF 387067f02347Srandyf } 387167f02347Srandyf #endif 387262387023Sdduvall if (mac != 0ULL) 387362387023Sdduvall break; 387462387023Sdduvall if (bgep->bge_chip_state != BGE_CHIP_INITIAL) 387562387023Sdduvall break; 387662387023Sdduvall } 38775a506a18Syong tan - Sun Microsystems - Beijing China } 387862387023Sdduvall 387962387023Sdduvall magic = bge_nic_get64(bgep, NIC_MEM_GENCOMM); 388062387023Sdduvall BGE_DEBUG(("bge_poll_firmware($%p): PXE magic 0x%x after %d loops", 388162387023Sdduvall (void *)bgep, gen, i)); 388262387023Sdduvall BGE_DEBUG(("bge_poll_firmware: MAC %016llx, GENCOMM %016llx", 388362387023Sdduvall mac, magic)); 388462387023Sdduvall 388562387023Sdduvall return (mac); 388662387023Sdduvall } 388762387023Sdduvall 38883adfa9cdSzh199473 /* 38893adfa9cdSzh199473 * Maximum times of trying to get the NVRAM access lock 38903adfa9cdSzh199473 * by calling bge_nvmem_acquire() 38913adfa9cdSzh199473 */ 38923adfa9cdSzh199473 #define MAX_TRY_NVMEM_ACQUIRE 10000 38933adfa9cdSzh199473 389467f02347Srandyf #ifdef BGE_IPMI_ASF 389500d0963fSdilpreet int bge_chip_reset(bge_t *bgep, boolean_t enable_dma, uint_t asf_mode); 389667f02347Srandyf #else 389700d0963fSdilpreet int bge_chip_reset(bge_t *bgep, boolean_t enable_dma); 389867f02347Srandyf #endif 389962387023Sdduvall #pragma no_inline(bge_chip_reset) 390062387023Sdduvall 390100d0963fSdilpreet int 390267f02347Srandyf #ifdef BGE_IPMI_ASF 390367f02347Srandyf bge_chip_reset(bge_t *bgep, boolean_t enable_dma, uint_t asf_mode) 390467f02347Srandyf #else 390562387023Sdduvall bge_chip_reset(bge_t *bgep, boolean_t enable_dma) 390667f02347Srandyf #endif 390762387023Sdduvall { 390862387023Sdduvall chip_id_t chipid; 390962387023Sdduvall uint64_t mac; 39101b5c96f3Sly149593 uint64_t magic; 3911087a28d1SDavid Gwynne uint32_t tmp; 3912087a28d1SDavid Gwynne uint32_t mhcr_base; 391362387023Sdduvall uint32_t mhcr; 391462387023Sdduvall uint32_t sx0; 39153adfa9cdSzh199473 uint32_t i, tries; 391667f02347Srandyf #ifdef BGE_IPMI_ASF 391767f02347Srandyf uint32_t mailbox; 391867f02347Srandyf #endif 391900d0963fSdilpreet int retval = DDI_SUCCESS; 392062387023Sdduvall 392162387023Sdduvall BGE_TRACE(("bge_chip_reset($%p, %d)", 392262387023Sdduvall (void *)bgep, enable_dma)); 392362387023Sdduvall 392462387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 392562387023Sdduvall 392662387023Sdduvall BGE_DEBUG(("bge_chip_reset($%p, %d): current state is %d", 392762387023Sdduvall (void *)bgep, enable_dma, bgep->bge_chip_state)); 392862387023Sdduvall 392962387023Sdduvall /* 393062387023Sdduvall * Do we need to stop the chip cleanly before resetting? 393162387023Sdduvall */ 393262387023Sdduvall switch (bgep->bge_chip_state) { 393362387023Sdduvall default: 393462387023Sdduvall _NOTE(NOTREACHED) 393500d0963fSdilpreet return (DDI_FAILURE); 393662387023Sdduvall 393762387023Sdduvall case BGE_CHIP_INITIAL: 393862387023Sdduvall case BGE_CHIP_STOPPED: 393962387023Sdduvall case BGE_CHIP_RESET: 394062387023Sdduvall break; 394162387023Sdduvall 394262387023Sdduvall case BGE_CHIP_RUNNING: 394362387023Sdduvall case BGE_CHIP_ERROR: 394462387023Sdduvall case BGE_CHIP_FAULT: 394562387023Sdduvall bge_chip_stop(bgep, B_FALSE); 394662387023Sdduvall break; 394762387023Sdduvall } 394862387023Sdduvall 3949087a28d1SDavid Gwynne mhcr_base = MHCR_ENABLE_INDIRECT_ACCESS | 3950087a28d1SDavid Gwynne MHCR_ENABLE_PCI_STATE_RW | 3951a4de4ba2Sml149210 MHCR_ENABLE_TAGGED_STATUS_MODE | 3952a4de4ba2Sml149210 MHCR_MASK_INTERRUPT_MODE | 3953a4de4ba2Sml149210 MHCR_MASK_PCI_INT_OUTPUT | 3954087a28d1SDavid Gwynne MHCR_CLEAR_INTERRUPT_INTA; 3955087a28d1SDavid Gwynne 3956087a28d1SDavid Gwynne #ifdef BGE_IPMI_ASF 3957087a28d1SDavid Gwynne if (bgep->asf_enabled) { 3958087a28d1SDavid Gwynne mhcr = mhcr_base; 3959087a28d1SDavid Gwynne #ifdef _BIG_ENDIAN 3960087a28d1SDavid Gwynne mhcr |= (MHCR_ENABLE_ENDIAN_WORD_SWAP | 3961087a28d1SDavid Gwynne MHCR_ENABLE_ENDIAN_BYTE_SWAP); 3962087a28d1SDavid Gwynne #endif 3963a4de4ba2Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcr); 3964087a28d1SDavid Gwynne 3965a4de4ba2Sml149210 bge_reg_put32(bgep, MEMORY_ARBITER_MODE_REG, 3966a4de4ba2Sml149210 bge_reg_get32(bgep, MEMORY_ARBITER_MODE_REG) | 3967a4de4ba2Sml149210 MEMORY_ARBITER_ENABLE); 3968087a28d1SDavid Gwynne 396967f02347Srandyf if (asf_mode == ASF_MODE_INIT) { 397067f02347Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 397167f02347Srandyf } else if (asf_mode == ASF_MODE_SHUTDOWN) { 397267f02347Srandyf bge_asf_pre_reset_operations(bgep, BGE_SHUTDOWN_RESET); 397367f02347Srandyf } 397467f02347Srandyf } 397567f02347Srandyf #endif 3976087a28d1SDavid Gwynne 397762387023Sdduvall /* 397862387023Sdduvall * Adapted from Broadcom document 570X-PG102-R, pp 102-116. 397962387023Sdduvall * Updated to reflect Broadcom document 570X-PG104-R, pp 146-159. 398062387023Sdduvall * 398162387023Sdduvall * Before reset Core clock,it is 398262387023Sdduvall * also required to initialize the Memory Arbiter as specified in step9 398362387023Sdduvall * and Misc Host Control Register as specified in step-13 398462387023Sdduvall * Step 4-5: reset Core clock & wait for completion 398562387023Sdduvall * Steps 6-8: are done by bge_chip_cfg_init() 39861b5c96f3Sly149593 * put the T3_MAGIC_NUMBER into the GENCOMM port before reset 398762387023Sdduvall */ 398800d0963fSdilpreet if (!bge_chip_enable_engine(bgep, MEMORY_ARBITER_MODE_REG, 0)) 398900d0963fSdilpreet retval = DDI_FAILURE; 399062387023Sdduvall 3991087a28d1SDavid Gwynne mhcr = mhcr_base; 399262387023Sdduvall #ifdef _BIG_ENDIAN 3993087a28d1SDavid Gwynne mhcr |= (MHCR_ENABLE_ENDIAN_WORD_SWAP | 3994087a28d1SDavid Gwynne MHCR_ENABLE_ENDIAN_BYTE_SWAP); 3995087a28d1SDavid Gwynne #endif 399662387023Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcr); 3997087a28d1SDavid Gwynne 399867f02347Srandyf #ifdef BGE_IPMI_ASF 399967f02347Srandyf if (bgep->asf_enabled) 400067f02347Srandyf bgep->asf_wordswapped = B_FALSE; 400167f02347Srandyf #endif 4002f724721bSzh199473 /* 4003f724721bSzh199473 * NVRAM Corruption Workaround 4004f724721bSzh199473 */ 40053adfa9cdSzh199473 for (tries = 0; tries < MAX_TRY_NVMEM_ACQUIRE; tries++) 4006542d98abSzh199473 if (bge_nvmem_acquire(bgep) != EAGAIN) 4007f724721bSzh199473 break; 4008c77e0fa5Szh199473 if (tries >= MAX_TRY_NVMEM_ACQUIRE) 4009f724721bSzh199473 BGE_DEBUG(("%s: fail to acquire nvram lock", 4010f724721bSzh199473 bgep->ifname)); 4011f724721bSzh199473 4012087a28d1SDavid Gwynne bge_ape_lock(bgep, BGE_APE_LOCK_GRC); 4013087a28d1SDavid Gwynne 40141b5c96f3Sly149593 #ifdef BGE_IPMI_ASF 40151b5c96f3Sly149593 if (!bgep->asf_enabled) { 40161b5c96f3Sly149593 #endif 40171b5c96f3Sly149593 magic = (uint64_t)T3_MAGIC_NUMBER << 32; 40181b5c96f3Sly149593 bge_nic_put64(bgep, NIC_MEM_GENCOMM, magic); 40191b5c96f3Sly149593 #ifdef BGE_IPMI_ASF 40201b5c96f3Sly149593 } 40211b5c96f3Sly149593 #endif 40221b5c96f3Sly149593 4023087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 4024087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 4025087a28d1SDavid Gwynne bge_reg_set32(bgep, FAST_BOOT_PC, 0); 4026087a28d1SDavid Gwynne if (!bge_chip_enable_engine(bgep, MEMORY_ARBITER_MODE_REG, 0)) 4027087a28d1SDavid Gwynne retval = DDI_FAILURE; 4028087a28d1SDavid Gwynne } 4029087a28d1SDavid Gwynne 4030087a28d1SDavid Gwynne mhcr = mhcr_base; 4031087a28d1SDavid Gwynne #ifdef _BIG_ENDIAN 4032087a28d1SDavid Gwynne mhcr |= (MHCR_ENABLE_ENDIAN_WORD_SWAP | 4033087a28d1SDavid Gwynne MHCR_ENABLE_ENDIAN_BYTE_SWAP); 4034087a28d1SDavid Gwynne #endif 4035087a28d1SDavid Gwynne pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcr); 4036087a28d1SDavid Gwynne 403700d0963fSdilpreet if (!bge_chip_reset_engine(bgep, MISC_CONFIG_REG)) 403800d0963fSdilpreet retval = DDI_FAILURE; 4039087a28d1SDavid Gwynne 404062387023Sdduvall bge_chip_cfg_init(bgep, &chipid, enable_dma); 404162387023Sdduvall 404262387023Sdduvall /* 404362387023Sdduvall * Step 8a: This may belong elsewhere, but BCM5721 needs 404462387023Sdduvall * a bit set to avoid a fifo overflow/underflow bug. 404562387023Sdduvall */ 4046256e438eSzh199473 if ((bgep->chipid.chip_label == 5721) || 4047256e438eSzh199473 (bgep->chipid.chip_label == 5751) || 4048f724721bSzh199473 (bgep->chipid.chip_label == 5752) || 404903a69b52Sml149210 (bgep->chipid.chip_label == 5755) || 405067f41d5aSGordon Ross (bgep->chipid.chip_label == 5756) || 40515a506a18Syong tan - Sun Microsystems - Beijing China (bgep->chipid.chip_label == 5789) || 40525a506a18Syong tan - Sun Microsystems - Beijing China (bgep->chipid.chip_label == 5906)) 405362387023Sdduvall bge_reg_set32(bgep, TLP_CONTROL_REG, TLP_DATA_FIFO_PROTECT); 405462387023Sdduvall 405562387023Sdduvall /* 405662387023Sdduvall * Step 9: enable MAC memory arbiter,bit30 and bit31 of 5714/5715 should 405762387023Sdduvall * not be changed. 405862387023Sdduvall */ 405900d0963fSdilpreet if (!bge_chip_enable_engine(bgep, MEMORY_ARBITER_MODE_REG, 0)) 406000d0963fSdilpreet retval = DDI_FAILURE; 406162387023Sdduvall 406262387023Sdduvall /* 406362387023Sdduvall * Steps 10-11: configure PIO endianness options and 406462387023Sdduvall * enable indirect register access -- already done 406562387023Sdduvall * Steps 12-13: enable writing to the PCI state & clock 406662387023Sdduvall * control registers -- not required; we aren't going to 406762387023Sdduvall * use those features. 406862387023Sdduvall * Steps 14-15: Configure DMA endianness options. See 406962387023Sdduvall * the comments on the setting of the MHCR above. 407062387023Sdduvall */ 4071087a28d1SDavid Gwynne tmp = MODE_WORD_SWAP_FRAME | MODE_BYTE_SWAP_FRAME; 407262387023Sdduvall #ifdef _BIG_ENDIAN 4073087a28d1SDavid Gwynne tmp |= (MODE_WORD_SWAP_NONFRAME | MODE_BYTE_SWAP_NONFRAME); 4074087a28d1SDavid Gwynne #endif 407567f02347Srandyf #ifdef BGE_IPMI_ASF 407667f02347Srandyf if (bgep->asf_enabled) 4077087a28d1SDavid Gwynne tmp |= MODE_HOST_STACK_UP; 407867f02347Srandyf #endif 4079087a28d1SDavid Gwynne bge_reg_put32(bgep, MODE_CONTROL_REG, tmp); 408062387023Sdduvall 408167f02347Srandyf #ifdef BGE_IPMI_ASF 408267f02347Srandyf if (bgep->asf_enabled) { 4083a4de4ba2Sml149210 #ifdef __sparc 4084a4de4ba2Sml149210 bge_reg_put32(bgep, MEMORY_ARBITER_MODE_REG, 4085a4de4ba2Sml149210 MEMORY_ARBITER_ENABLE | 4086a4de4ba2Sml149210 bge_reg_get32(bgep, MEMORY_ARBITER_MODE_REG)); 4087a4de4ba2Sml149210 #endif 4088a4de4ba2Sml149210 4089a4de4ba2Sml149210 #ifdef BGE_NETCONSOLE 4090a4de4ba2Sml149210 if (!bgep->asf_newhandshake) { 4091a4de4ba2Sml149210 if ((asf_mode == ASF_MODE_INIT) || 4092a4de4ba2Sml149210 (asf_mode == ASF_MODE_POST_INIT)) { 4093a4de4ba2Sml149210 bge_asf_post_reset_old_mode(bgep, 4094a4de4ba2Sml149210 BGE_INIT_RESET); 4095a4de4ba2Sml149210 } else { 4096a4de4ba2Sml149210 bge_asf_post_reset_old_mode(bgep, 4097a4de4ba2Sml149210 BGE_SHUTDOWN_RESET); 4098a4de4ba2Sml149210 } 4099a4de4ba2Sml149210 } 4100a4de4ba2Sml149210 #endif 4101a4de4ba2Sml149210 410267f02347Srandyf /* Wait for NVRAM init */ 410367f02347Srandyf i = 0; 410467f02347Srandyf drv_usecwait(5000); 410567f02347Srandyf mailbox = bge_nic_get32(bgep, BGE_FIRMWARE_MAILBOX); 4106a4de4ba2Sml149210 410767f02347Srandyf while ((mailbox != (uint32_t) 410867f02347Srandyf ~BGE_MAGIC_NUM_FIRMWARE_INIT_DONE) && 410967f02347Srandyf (i < 10000)) { 411067f02347Srandyf drv_usecwait(100); 411167f02347Srandyf mailbox = bge_nic_get32(bgep, 411267f02347Srandyf BGE_FIRMWARE_MAILBOX); 411367f02347Srandyf i++; 411467f02347Srandyf } 4115a4de4ba2Sml149210 4116a4de4ba2Sml149210 #ifndef BGE_NETCONSOLE 411767f02347Srandyf if (!bgep->asf_newhandshake) { 411867f02347Srandyf if ((asf_mode == ASF_MODE_INIT) || 411967f02347Srandyf (asf_mode == ASF_MODE_POST_INIT)) { 412067f02347Srandyf 412167f02347Srandyf bge_asf_post_reset_old_mode(bgep, 412267f02347Srandyf BGE_INIT_RESET); 412367f02347Srandyf } else { 412467f02347Srandyf bge_asf_post_reset_old_mode(bgep, 412567f02347Srandyf BGE_SHUTDOWN_RESET); 412667f02347Srandyf } 412767f02347Srandyf } 4128a4de4ba2Sml149210 #endif 412967f02347Srandyf } 413067f02347Srandyf #endif 4131087a28d1SDavid Gwynne 4132087a28d1SDavid Gwynne bge_ape_unlock(bgep, BGE_APE_LOCK_GRC); 4133087a28d1SDavid Gwynne 413462387023Sdduvall /* 413562387023Sdduvall * Steps 16-17: poll for firmware completion 413662387023Sdduvall */ 413762387023Sdduvall mac = bge_poll_firmware(bgep); 413862387023Sdduvall 4139087a28d1SDavid Gwynne if (bgep->chipid.device == DEVICE_ID_5720) { 4140087a28d1SDavid Gwynne tmp = bge_reg_get32(bgep, CPMU_CLCK_ORIDE_REG); 4141087a28d1SDavid Gwynne bge_reg_put32(bgep, CPMU_CLCK_ORIDE_REG, 4142087a28d1SDavid Gwynne (tmp & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN)); 4143087a28d1SDavid Gwynne } 4144087a28d1SDavid Gwynne 414562387023Sdduvall /* 414662387023Sdduvall * Step 18: enable external memory -- doesn't apply. 414762387023Sdduvall * 414862387023Sdduvall * However we take the opportunity to set the MLCR anyway, as 414962387023Sdduvall * this register also controls the SEEPROM auto-access method 415062387023Sdduvall * which we may want to use later ... 415162387023Sdduvall * 415262387023Sdduvall * The proper value here depends on the way the chip is wired 415362387023Sdduvall * into the circuit board, as this register *also* controls which 415462387023Sdduvall * of the "Miscellaneous I/O" pins are driven as outputs and the 415562387023Sdduvall * values driven onto those pins! 415662387023Sdduvall * 415762387023Sdduvall * See also step 74 in the PRM ... 415862387023Sdduvall */ 415962387023Sdduvall bge_reg_put32(bgep, MISC_LOCAL_CONTROL_REG, 416062387023Sdduvall bgep->chipid.bge_mlcr_default); 4161087a28d1SDavid Gwynne 4162087a28d1SDavid Gwynne if ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 4163087a28d1SDavid Gwynne DEVICE_5714_SERIES_CHIPSETS(bgep)) { 4164087a28d1SDavid Gwynne tmp = bge_reg_get32(bgep, SERDES_RX_CONTROL); 4165087a28d1SDavid Gwynne tmp |= SERDES_RX_CONTROL_SIG_DETECT; 4166087a28d1SDavid Gwynne bge_reg_put32(bgep, SERDES_RX_CONTROL, tmp); 4167087a28d1SDavid Gwynne } 4168087a28d1SDavid Gwynne 416962387023Sdduvall bge_reg_set32(bgep, SERIAL_EEPROM_ADDRESS_REG, SEEPROM_ACCESS_INIT); 417062387023Sdduvall 417162387023Sdduvall /* 417262387023Sdduvall * Step 20: clear the Ethernet MAC mode register 417362387023Sdduvall */ 4174087a28d1SDavid Gwynne if (bgep->ape_enabled) 4175087a28d1SDavid Gwynne bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, 4176087a28d1SDavid Gwynne ETHERNET_MODE_APE_TX_EN | ETHERNET_MODE_APE_RX_EN); 4177087a28d1SDavid Gwynne else 417862387023Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, 0); 417962387023Sdduvall 418062387023Sdduvall /* 418162387023Sdduvall * Step 21: restore cache-line-size, latency timer, and 418262387023Sdduvall * subsystem ID registers to their original values (not 418362387023Sdduvall * those read into the local structure <chipid>, 'cos 418462387023Sdduvall * that was after they were cleared by the RESET). 418562387023Sdduvall * 418662387023Sdduvall * Note: the Subsystem Vendor/Device ID registers are not 418762387023Sdduvall * directly writable in config space, so we use the shadow 418862387023Sdduvall * copy in "Page Zero" of register space to restore them 418962387023Sdduvall * both in one go ... 419062387023Sdduvall */ 419162387023Sdduvall pci_config_put8(bgep->cfg_handle, PCI_CONF_CACHE_LINESZ, 419262387023Sdduvall bgep->chipid.clsize); 419362387023Sdduvall pci_config_put8(bgep->cfg_handle, PCI_CONF_LATENCY_TIMER, 419462387023Sdduvall bgep->chipid.latency); 419562387023Sdduvall bge_reg_put32(bgep, PCI_CONF_SUBVENID, 419662387023Sdduvall (bgep->chipid.subdev << 16) | bgep->chipid.subven); 419762387023Sdduvall 419862387023Sdduvall /* 419962387023Sdduvall * The SEND INDEX registers should be reset to zero by the 420062387023Sdduvall * global chip reset; if they're not, there'll be trouble 420100d0963fSdilpreet * later on. 420262387023Sdduvall */ 420362387023Sdduvall sx0 = bge_reg_get32(bgep, NIC_DIAG_SEND_INDEX_REG(0)); 420400d0963fSdilpreet if (sx0 != 0) { 420500d0963fSdilpreet BGE_REPORT((bgep, "SEND INDEX - device didn't RESET")); 420600d0963fSdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE); 42077c966ec8Sml149210 retval = DDI_FAILURE; 420800d0963fSdilpreet } 420962387023Sdduvall 421062387023Sdduvall /* Enable MSI code */ 421162387023Sdduvall if (bgep->intr_type == DDI_INTR_TYPE_MSI) 421262387023Sdduvall bge_reg_set32(bgep, MSI_MODE_REG, 42135952d588Szh199473 MSI_PRI_HIGHEST|MSI_MSI_ENABLE|MSI_ERROR_ATTENTION); 421462387023Sdduvall 421562387023Sdduvall /* 421662387023Sdduvall * On the first time through, save the factory-set MAC address 421762387023Sdduvall * (if any). If bge_poll_firmware() above didn't return one 421862387023Sdduvall * (from a chip register) consider looking in the attached NV 421962387023Sdduvall * memory device, if any. Once we have it, we save it in both 422062387023Sdduvall * register-image (64-bit) and byte-array forms. All-zero and 422162387023Sdduvall * all-one addresses are not valid, and we refuse to stash those. 422262387023Sdduvall */ 422362387023Sdduvall if (bgep->bge_chip_state == BGE_CHIP_INITIAL) { 422462387023Sdduvall if (mac == 0ULL) 422562387023Sdduvall mac = bge_get_nvmac(bgep); 422662387023Sdduvall if (mac != 0ULL && mac != ~0ULL) { 422762387023Sdduvall bgep->chipid.hw_mac_addr = mac; 422862387023Sdduvall for (i = ETHERADDRL; i-- != 0; ) { 422962387023Sdduvall bgep->chipid.vendor_addr.addr[i] = (uchar_t)mac; 423062387023Sdduvall mac >>= 8; 423162387023Sdduvall } 4232ed8845d8Skrgopi bgep->chipid.vendor_addr.set = B_TRUE; 423362387023Sdduvall } 423462387023Sdduvall } 423562387023Sdduvall 423667f02347Srandyf #ifdef BGE_IPMI_ASF 423767f02347Srandyf if (bgep->asf_enabled && bgep->asf_newhandshake) { 423867f02347Srandyf if (asf_mode != ASF_MODE_NONE) { 423967f02347Srandyf if ((asf_mode == ASF_MODE_INIT) || 424067f02347Srandyf (asf_mode == ASF_MODE_POST_INIT)) { 424167f02347Srandyf 424267f02347Srandyf bge_asf_post_reset_new_mode(bgep, 424367f02347Srandyf BGE_INIT_RESET); 424467f02347Srandyf } else { 424567f02347Srandyf bge_asf_post_reset_new_mode(bgep, 424667f02347Srandyf BGE_SHUTDOWN_RESET); 424767f02347Srandyf } 424867f02347Srandyf } 424967f02347Srandyf } 425067f02347Srandyf #endif 425167f02347Srandyf 425262387023Sdduvall /* 425362387023Sdduvall * Record the new state 425462387023Sdduvall */ 425562387023Sdduvall bgep->chip_resets += 1; 425662387023Sdduvall bgep->bge_chip_state = BGE_CHIP_RESET; 425700d0963fSdilpreet return (retval); 425862387023Sdduvall } 425962387023Sdduvall 426062387023Sdduvall /* 426162387023Sdduvall * bge_chip_start() -- start the chip transmitting and/or receiving, 426262387023Sdduvall * including enabling interrupts 426362387023Sdduvall */ 426400d0963fSdilpreet int bge_chip_start(bge_t *bgep, boolean_t reset_phys); 426562387023Sdduvall #pragma no_inline(bge_chip_start) 426662387023Sdduvall 42674d6eaea5Syong tan - Sun Microsystems - Beijing China void 42684d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bge_t *bgep) 42694d6eaea5Syong tan - Sun Microsystems - Beijing China { 42704d6eaea5Syong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, SEND_COALESCE_MAX_BD_REG, 42714d6eaea5Syong tan - Sun Microsystems - Beijing China bgep->chipid.tx_count_norm); 42724d6eaea5Syong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, SEND_COALESCE_TICKS_REG, 42734d6eaea5Syong tan - Sun Microsystems - Beijing China bgep->chipid.tx_ticks_norm); 42744d6eaea5Syong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, RCV_COALESCE_MAX_BD_REG, 42754d6eaea5Syong tan - Sun Microsystems - Beijing China bgep->chipid.rx_count_norm); 42764d6eaea5Syong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, RCV_COALESCE_TICKS_REG, 42774d6eaea5Syong tan - Sun Microsystems - Beijing China bgep->chipid.rx_ticks_norm); 42784d6eaea5Syong tan - Sun Microsystems - Beijing China } 42794d6eaea5Syong tan - Sun Microsystems - Beijing China 428000d0963fSdilpreet int 428162387023Sdduvall bge_chip_start(bge_t *bgep, boolean_t reset_phys) 428262387023Sdduvall { 428362387023Sdduvall uint32_t coalmode; 428462387023Sdduvall uint32_t ledctl; 428562387023Sdduvall uint32_t mtu; 428662387023Sdduvall uint32_t maxring; 4287542d98abSzh199473 uint32_t stats_mask; 428803a69b52Sml149210 uint32_t dma_wrprio; 428962387023Sdduvall uint64_t ring; 4290087a28d1SDavid Gwynne uint32_t reg; 4291dc3f9a75Syong tan - Sun Microsystems - Beijing China uint32_t regval; 4292087a28d1SDavid Gwynne uint32_t mhcr; 429300d0963fSdilpreet int retval = DDI_SUCCESS; 4294087a28d1SDavid Gwynne int i; 429562387023Sdduvall 429662387023Sdduvall BGE_TRACE(("bge_chip_start($%p)", 429762387023Sdduvall (void *)bgep)); 429862387023Sdduvall 429962387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 430062387023Sdduvall ASSERT(bgep->bge_chip_state == BGE_CHIP_RESET); 430162387023Sdduvall 4302087a28d1SDavid Gwynne /* Initialize EEE, enable MAC control of LPI */ 4303087a28d1SDavid Gwynne bge_eee_init(bgep); 4304087a28d1SDavid Gwynne 4305087a28d1SDavid Gwynne if (bgep->ape_enabled) { 4306087a28d1SDavid Gwynne /* 4307087a28d1SDavid Gwynne * Allow reads and writes to the 4308087a28d1SDavid Gwynne * APE register and memory space. 4309087a28d1SDavid Gwynne */ 4310087a28d1SDavid Gwynne regval = pci_config_get32(bgep->cfg_handle, 4311087a28d1SDavid Gwynne PCI_CONF_BGE_PCISTATE); 4312087a28d1SDavid Gwynne regval |= PCISTATE_ALLOW_APE_CTLSPC_WR | 4313087a28d1SDavid Gwynne PCISTATE_ALLOW_APE_SHMEM_WR | PCISTATE_ALLOW_APE_PSPACE_WR; 4314087a28d1SDavid Gwynne pci_config_put32(bgep->cfg_handle, 4315087a28d1SDavid Gwynne PCI_CONF_BGE_PCISTATE, regval); 4316087a28d1SDavid Gwynne } 4317087a28d1SDavid Gwynne 431862387023Sdduvall /* 431962387023Sdduvall * Taken from Broadcom document 570X-PG102-R, pp 102-116. 432062387023Sdduvall * The document specifies 95 separate steps to fully 432162387023Sdduvall * initialise the chip!!!! 432262387023Sdduvall * 432362387023Sdduvall * The reset code above has already got us as far as step 432462387023Sdduvall * 21, so we continue with ... 432562387023Sdduvall * 432662387023Sdduvall * Step 22: clear the MAC statistics block 432762387023Sdduvall * (0x0300-0x0aff in NIC-local memory) 432862387023Sdduvall */ 432962387023Sdduvall if (bgep->chipid.statistic_type == BGE_STAT_BLK) 433062387023Sdduvall bge_nic_zero(bgep, NIC_MEM_STATISTICS, 433162387023Sdduvall NIC_MEM_STATISTICS_SIZE); 433262387023Sdduvall 433362387023Sdduvall /* 433462387023Sdduvall * Step 23: clear the status block (in host memory) 433562387023Sdduvall */ 433662387023Sdduvall DMA_ZERO(bgep->status_block); 433762387023Sdduvall 433862387023Sdduvall /* 433962387023Sdduvall * Step 24: set DMA read/write control register 434062387023Sdduvall */ 434162387023Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_PDRWCR, 434262387023Sdduvall bgep->chipid.bge_dma_rwctrl); 434362387023Sdduvall 434462387023Sdduvall /* 434562387023Sdduvall * Step 25: Configure DMA endianness -- already done (16/17) 434662387023Sdduvall * Step 26: Configure Host-Based Send Rings 434762387023Sdduvall * Step 27: Indicate Host Stack Up 434862387023Sdduvall */ 434962387023Sdduvall bge_reg_set32(bgep, MODE_CONTROL_REG, 435062387023Sdduvall MODE_HOST_SEND_BDS | 435162387023Sdduvall MODE_HOST_STACK_UP); 435262387023Sdduvall 4353087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 4354087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 4355087a28d1SDavid Gwynne reg = (CHIP_ASIC_REV(bgep) == CHIP_ASIC_REV_5762) 4356087a28d1SDavid Gwynne ? RDMA_RSRV_CTRL_REG2 : RDMA_RSRV_CTRL_REG; 4357087a28d1SDavid Gwynne regval = bge_reg_get32(bgep, reg); 4358087a28d1SDavid Gwynne if ((bgep->chipid.device == DEVICE_ID_5719) || 4359087a28d1SDavid Gwynne (bgep->chipid.device == DEVICE_ID_5720) || 4360087a28d1SDavid Gwynne (CHIP_ASIC_REV(bgep) == CHIP_ASIC_REV_5762)) { 4361087a28d1SDavid Gwynne regval &= ~(RDMA_RSRV_CTRL_TXMRGN_MASK | 4362087a28d1SDavid Gwynne RDMA_RSRV_CTRL_FIFO_LWM_MASK | 4363087a28d1SDavid Gwynne RDMA_RSRV_CTRL_FIFO_HWM_MASK); 4364087a28d1SDavid Gwynne regval |= (RDMA_RSRV_CTRL_TXMRGN_320B | 4365087a28d1SDavid Gwynne RDMA_RSRV_CTRL_FIFO_LWM_1_5K | 4366087a28d1SDavid Gwynne RDMA_RSRV_CTRL_FIFO_HWM_1_5K); 4367087a28d1SDavid Gwynne } 4368087a28d1SDavid Gwynne /* Enable the DMA FIFO Overrun fix. */ 4369087a28d1SDavid Gwynne bge_reg_put32(bgep, reg, 4370087a28d1SDavid Gwynne (regval | RDMA_RSRV_CTRL_FIFO_OFLW_FIX)); 4371087a28d1SDavid Gwynne 4372087a28d1SDavid Gwynne if ((CHIP_ASIC_REV(bgep) == CHIP_ASIC_REV_5719) || 4373087a28d1SDavid Gwynne (CHIP_ASIC_REV(bgep) == CHIP_ASIC_REV_5720) || 4374087a28d1SDavid Gwynne (CHIP_ASIC_REV(bgep) == CHIP_ASIC_REV_5762)) { 4375087a28d1SDavid Gwynne reg = (CHIP_ASIC_REV(bgep) == CHIP_ASIC_REV_5762) 4376087a28d1SDavid Gwynne ? RDMA_CORR_CTRL_REG2 : RDMA_CORR_CTRL_REG; 4377087a28d1SDavid Gwynne regval = bge_reg_get32(bgep, reg); 4378087a28d1SDavid Gwynne bge_reg_put32(bgep, reg, (regval | 4379087a28d1SDavid Gwynne RDMA_CORR_CTRL_BLEN_BD_4K | 4380087a28d1SDavid Gwynne RDMA_CORR_CTRL_BLEN_LSO_4K)); 4381087a28d1SDavid Gwynne } 4382087a28d1SDavid Gwynne } 4383087a28d1SDavid Gwynne 438462387023Sdduvall /* 438562387023Sdduvall * Step 28: Configure checksum options: 43863c46fd93Szh199473 * Solaris supports the hardware default checksum options. 43873c46fd93Szh199473 * 43883c46fd93Szh199473 * Workaround for Incorrect pseudo-header checksum calculation. 438962387023Sdduvall */ 4390256e438eSzh199473 if (bgep->chipid.flags & CHIP_FLAG_PARTIAL_CSUM) 43913c46fd93Szh199473 bge_reg_set32(bgep, MODE_CONTROL_REG, 43923c46fd93Szh199473 MODE_SEND_NO_PSEUDO_HDR_CSUM); 439362387023Sdduvall 439462387023Sdduvall /* 439562387023Sdduvall * Step 29: configure Timer Prescaler. The value is always the 439662387023Sdduvall * same: the Core Clock frequency in MHz (66), minus 1, shifted 439762387023Sdduvall * into bits 7-1. Don't set bit 0, 'cos that's the RESET bit 439862387023Sdduvall * for the whole chip! 439962387023Sdduvall */ 4400dc3f9a75Syong tan - Sun Microsystems - Beijing China regval = bge_reg_get32(bgep, MISC_CONFIG_REG); 4401dc3f9a75Syong tan - Sun Microsystems - Beijing China regval = (regval & 0xffffff00) | MISC_CONFIG_DEFAULT; 4402dc3f9a75Syong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, MISC_CONFIG_REG, regval); 440362387023Sdduvall 44045a506a18Syong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { 44055a506a18Syong tan - Sun Microsystems - Beijing China drv_usecwait(40); 44065a506a18Syong tan - Sun Microsystems - Beijing China /* put PHY into ready state */ 44075a506a18Syong tan - Sun Microsystems - Beijing China bge_reg_clr32(bgep, MISC_CONFIG_REG, MISC_CONFIG_EPHY_IDDQ); 44085a506a18Syong tan - Sun Microsystems - Beijing China (void) bge_reg_get32(bgep, MISC_CONFIG_REG); /* flush */ 44095a506a18Syong tan - Sun Microsystems - Beijing China drv_usecwait(40); 44105a506a18Syong tan - Sun Microsystems - Beijing China } 44115a506a18Syong tan - Sun Microsystems - Beijing China 441262387023Sdduvall /* 441362387023Sdduvall * Steps 30-31: Configure MAC local memory pool & DMA pool registers 441462387023Sdduvall * 441562387023Sdduvall * If the mbuf_length is specified as 0, we just leave these at 441662387023Sdduvall * their hardware defaults, rather than explicitly setting them. 441762387023Sdduvall * As the Broadcom HRM,driver better not change the parameters 441862387023Sdduvall * when the chipsets is 5705/5788/5721/5751/5714 and 5715. 441962387023Sdduvall */ 442062387023Sdduvall if ((bgep->chipid.mbuf_length != 0) && 442162387023Sdduvall (DEVICE_5704_SERIES_CHIPSETS(bgep))) { 442262387023Sdduvall bge_reg_put32(bgep, MBUF_POOL_BASE_REG, 442362387023Sdduvall bgep->chipid.mbuf_base); 442462387023Sdduvall bge_reg_put32(bgep, MBUF_POOL_LENGTH_REG, 442562387023Sdduvall bgep->chipid.mbuf_length); 442662387023Sdduvall bge_reg_put32(bgep, DMAD_POOL_BASE_REG, 442762387023Sdduvall DMAD_POOL_BASE_DEFAULT); 442862387023Sdduvall bge_reg_put32(bgep, DMAD_POOL_LENGTH_REG, 442962387023Sdduvall DMAD_POOL_LENGTH_DEFAULT); 443062387023Sdduvall } 443162387023Sdduvall 443262387023Sdduvall /* 443362387023Sdduvall * Step 32: configure MAC memory pool watermarks 443462387023Sdduvall */ 443562387023Sdduvall bge_reg_put32(bgep, RDMA_MBUF_LOWAT_REG, 443662387023Sdduvall bgep->chipid.mbuf_lo_water_rdma); 443762387023Sdduvall bge_reg_put32(bgep, MAC_RX_MBUF_LOWAT_REG, 443862387023Sdduvall bgep->chipid.mbuf_lo_water_rmac); 443962387023Sdduvall bge_reg_put32(bgep, MBUF_HIWAT_REG, 444062387023Sdduvall bgep->chipid.mbuf_hi_water); 444162387023Sdduvall 444262387023Sdduvall /* 444362387023Sdduvall * Step 33: configure DMA resource watermarks 444462387023Sdduvall */ 444562387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 444662387023Sdduvall bge_reg_put32(bgep, DMAD_POOL_LOWAT_REG, 444762387023Sdduvall bge_dmad_lo_water); 444862387023Sdduvall bge_reg_put32(bgep, DMAD_POOL_HIWAT_REG, 444962387023Sdduvall bge_dmad_hi_water); 445062387023Sdduvall } 445162387023Sdduvall bge_reg_put32(bgep, LOWAT_MAX_RECV_FRAMES_REG, bge_lowat_recv_frames); 445262387023Sdduvall 445362387023Sdduvall /* 445462387023Sdduvall * Steps 34-36: enable buffer manager & internal h/w queues 445562387023Sdduvall */ 4456087a28d1SDavid Gwynne regval = STATE_MACHINE_ATTN_ENABLE_BIT; 4457087a28d1SDavid Gwynne if (bgep->chipid.device == DEVICE_ID_5719) 4458087a28d1SDavid Gwynne regval |= BUFFER_MANAGER_MODE_NO_TX_UNDERRUN; 4459087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 4460087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) 4461087a28d1SDavid Gwynne regval |= BUFFER_MANAGER_MODE_MBLOW_ATTN_ENABLE; 4462087a28d1SDavid Gwynne if (!bge_chip_enable_engine(bgep, BUFFER_MANAGER_MODE_REG, regval)) 446300d0963fSdilpreet retval = DDI_FAILURE; 4464087a28d1SDavid Gwynne 446500d0963fSdilpreet if (!bge_chip_enable_engine(bgep, FTQ_RESET_REG, 0)) 446600d0963fSdilpreet retval = DDI_FAILURE; 446762387023Sdduvall 446862387023Sdduvall /* 446962387023Sdduvall * Steps 37-39: initialise Receive Buffer (Producer) RCBs 447062387023Sdduvall */ 4471087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 4472087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 4473dc3f9a75Syong tan - Sun Microsystems - Beijing China buff_ring_t *brp = &bgep->buff[BGE_STD_BUFF_RING]; 4474dc3f9a75Syong tan - Sun Microsystems - Beijing China bge_reg_put64(bgep, STD_RCV_BD_RING_RCB_REG, 4475dc3f9a75Syong tan - Sun Microsystems - Beijing China brp->desc.cookie.dmac_laddress); 4476dc3f9a75Syong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, STD_RCV_BD_RING_RCB_REG + 8, 4477dc3f9a75Syong tan - Sun Microsystems - Beijing China (brp->desc.nslots) << 16 | brp->buf[0].size << 2); 4478dc3f9a75Syong tan - Sun Microsystems - Beijing China bge_reg_put32(bgep, STD_RCV_BD_RING_RCB_REG + 0xc, 4479dc3f9a75Syong tan - Sun Microsystems - Beijing China NIC_MEM_SHADOW_BUFF_STD_5717); 4480dc3f9a75Syong tan - Sun Microsystems - Beijing China } else 448162387023Sdduvall bge_reg_putrcb(bgep, STD_RCV_BD_RING_RCB_REG, 448262387023Sdduvall &bgep->buff[BGE_STD_BUFF_RING].hw_rcb); 4483dc3f9a75Syong tan - Sun Microsystems - Beijing China 448462387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 448562387023Sdduvall bge_reg_putrcb(bgep, JUMBO_RCV_BD_RING_RCB_REG, 448662387023Sdduvall &bgep->buff[BGE_JUMBO_BUFF_RING].hw_rcb); 448762387023Sdduvall bge_reg_putrcb(bgep, MINI_RCV_BD_RING_RCB_REG, 448862387023Sdduvall &bgep->buff[BGE_MINI_BUFF_RING].hw_rcb); 448962387023Sdduvall } 449062387023Sdduvall 449162387023Sdduvall /* 449262387023Sdduvall * Step 40: set Receive Buffer Descriptor Ring replenish thresholds 449362387023Sdduvall */ 449462387023Sdduvall bge_reg_put32(bgep, STD_RCV_BD_REPLENISH_REG, bge_replenish_std); 449562387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 449662387023Sdduvall bge_reg_put32(bgep, JUMBO_RCV_BD_REPLENISH_REG, 449762387023Sdduvall bge_replenish_jumbo); 449862387023Sdduvall bge_reg_put32(bgep, MINI_RCV_BD_REPLENISH_REG, 449962387023Sdduvall bge_replenish_mini); 450062387023Sdduvall } 450162387023Sdduvall 450262387023Sdduvall /* 450362387023Sdduvall * Steps 41-43: clear Send Ring Producer Indices and initialise 450462387023Sdduvall * Send Producer Rings (0x0100-0x01ff in NIC-local memory) 450562387023Sdduvall */ 450662387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 450762387023Sdduvall maxring = BGE_SEND_RINGS_MAX; 450862387023Sdduvall else 450962387023Sdduvall maxring = BGE_SEND_RINGS_MAX_5705; 451062387023Sdduvall for (ring = 0; ring < maxring; ++ring) { 451162387023Sdduvall bge_mbx_put(bgep, SEND_RING_HOST_INDEX_REG(ring), 0); 451262387023Sdduvall bge_mbx_put(bgep, SEND_RING_NIC_INDEX_REG(ring), 0); 451362387023Sdduvall bge_nic_putrcb(bgep, NIC_MEM_SEND_RING(ring), 451462387023Sdduvall &bgep->send[ring].hw_rcb); 451562387023Sdduvall } 451662387023Sdduvall 451762387023Sdduvall /* 451862387023Sdduvall * Steps 44-45: initialise Receive Return Rings 451962387023Sdduvall * (0x0200-0x02ff in NIC-local memory) 452062387023Sdduvall */ 452162387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 452262387023Sdduvall maxring = BGE_RECV_RINGS_MAX; 452362387023Sdduvall else 452462387023Sdduvall maxring = BGE_RECV_RINGS_MAX_5705; 452562387023Sdduvall for (ring = 0; ring < maxring; ++ring) 452662387023Sdduvall bge_nic_putrcb(bgep, NIC_MEM_RECV_RING(ring), 452762387023Sdduvall &bgep->recv[ring].hw_rcb); 452862387023Sdduvall 452962387023Sdduvall /* 453062387023Sdduvall * Step 46: initialise Receive Buffer (Producer) Ring indexes 453162387023Sdduvall */ 453262387023Sdduvall bge_mbx_put(bgep, RECV_STD_PROD_INDEX_REG, 0); 453362387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 453462387023Sdduvall bge_mbx_put(bgep, RECV_JUMBO_PROD_INDEX_REG, 0); 453562387023Sdduvall bge_mbx_put(bgep, RECV_MINI_PROD_INDEX_REG, 0); 453662387023Sdduvall } 453762387023Sdduvall /* 453862387023Sdduvall * Step 47: configure the MAC unicast address 453962387023Sdduvall * Step 48: configure the random backoff seed 454062387023Sdduvall * Step 96: set up multicast filters 454162387023Sdduvall */ 454267f02347Srandyf #ifdef BGE_IPMI_ASF 454300d0963fSdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) 454467f02347Srandyf #else 454500d0963fSdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) 454667f02347Srandyf #endif 454700d0963fSdilpreet retval = DDI_FAILURE; 454862387023Sdduvall 454962387023Sdduvall /* 455062387023Sdduvall * Step 49: configure the MTU 455162387023Sdduvall */ 455262387023Sdduvall mtu = bgep->chipid.ethmax_size+ETHERFCSL+VLAN_TAGSZ; 455362387023Sdduvall bge_reg_put32(bgep, MAC_RX_MTU_SIZE_REG, mtu); 455462387023Sdduvall 455562387023Sdduvall /* 455662387023Sdduvall * Step 50: configure the IPG et al 455762387023Sdduvall */ 455862387023Sdduvall bge_reg_put32(bgep, MAC_TX_LENGTHS_REG, MAC_TX_LENGTHS_DEFAULT); 455962387023Sdduvall 456062387023Sdduvall /* 456162387023Sdduvall * Step 51: configure the default Rx Return Ring 456262387023Sdduvall */ 456362387023Sdduvall bge_reg_put32(bgep, RCV_RULES_CONFIG_REG, RCV_RULES_CONFIG_DEFAULT); 456462387023Sdduvall 456562387023Sdduvall /* 456662387023Sdduvall * Steps 52-54: configure Receive List Placement, 456762387023Sdduvall * and enable Receive List Placement Statistics 456862387023Sdduvall */ 456962387023Sdduvall bge_reg_put32(bgep, RCV_LP_CONFIG_REG, 457062387023Sdduvall RCV_LP_CONFIG(bgep->chipid.rx_rings)); 4571087a28d1SDavid Gwynne switch (MHCR_CHIP_ASIC_REV(bgep)) { 4572542d98abSzh199473 case MHCR_CHIP_ASIC_REV_5700: 4573542d98abSzh199473 case MHCR_CHIP_ASIC_REV_5701: 4574542d98abSzh199473 case MHCR_CHIP_ASIC_REV_5703: 4575542d98abSzh199473 case MHCR_CHIP_ASIC_REV_5704: 457662387023Sdduvall bge_reg_put32(bgep, RCV_LP_STATS_ENABLE_MASK_REG, ~0); 4577542d98abSzh199473 break; 4578542d98abSzh199473 case MHCR_CHIP_ASIC_REV_5705: 4579542d98abSzh199473 break; 4580542d98abSzh199473 default: 4581542d98abSzh199473 stats_mask = bge_reg_get32(bgep, RCV_LP_STATS_ENABLE_MASK_REG); 4582542d98abSzh199473 stats_mask &= ~RCV_LP_STATS_DISABLE_MACTQ; 4583542d98abSzh199473 bge_reg_put32(bgep, RCV_LP_STATS_ENABLE_MASK_REG, stats_mask); 4584542d98abSzh199473 break; 4585542d98abSzh199473 } 458662387023Sdduvall bge_reg_set32(bgep, RCV_LP_STATS_CONTROL_REG, RCV_LP_STATS_ENABLE); 458762387023Sdduvall 458862387023Sdduvall if (bgep->chipid.rx_rings > 1) 458962387023Sdduvall bge_init_recv_rule(bgep); 459062387023Sdduvall 459162387023Sdduvall /* 459262387023Sdduvall * Steps 55-56: enable Send Data Initiator Statistics 459362387023Sdduvall */ 459462387023Sdduvall bge_reg_put32(bgep, SEND_INIT_STATS_ENABLE_MASK_REG, ~0); 459562387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 459662387023Sdduvall bge_reg_put32(bgep, SEND_INIT_STATS_CONTROL_REG, 459762387023Sdduvall SEND_INIT_STATS_ENABLE | SEND_INIT_STATS_FASTER); 459862387023Sdduvall } else { 459962387023Sdduvall bge_reg_put32(bgep, SEND_INIT_STATS_CONTROL_REG, 460062387023Sdduvall SEND_INIT_STATS_ENABLE); 460162387023Sdduvall } 460262387023Sdduvall /* 460362387023Sdduvall * Steps 57-58: stop (?) the Host Coalescing Engine 460462387023Sdduvall */ 460500d0963fSdilpreet if (!bge_chip_disable_engine(bgep, HOST_COALESCE_MODE_REG, ~0)) 460600d0963fSdilpreet retval = DDI_FAILURE; 460762387023Sdduvall 460862387023Sdduvall /* 460962387023Sdduvall * Steps 59-62: initialise Host Coalescing parameters 461062387023Sdduvall */ 46114d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bgep); 461262387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 461362387023Sdduvall bge_reg_put32(bgep, SEND_COALESCE_INT_BD_REG, 461462387023Sdduvall bge_tx_count_intr); 461562387023Sdduvall bge_reg_put32(bgep, SEND_COALESCE_INT_TICKS_REG, 461662387023Sdduvall bge_tx_ticks_intr); 461762387023Sdduvall bge_reg_put32(bgep, RCV_COALESCE_INT_BD_REG, 461862387023Sdduvall bge_rx_count_intr); 461962387023Sdduvall bge_reg_put32(bgep, RCV_COALESCE_INT_TICKS_REG, 462062387023Sdduvall bge_rx_ticks_intr); 462162387023Sdduvall } 462262387023Sdduvall 462362387023Sdduvall /* 462462387023Sdduvall * Steps 63-64: initialise status block & statistics 462562387023Sdduvall * host memory addresses 462662387023Sdduvall * The statistic block does not exist in some chipsets 462762387023Sdduvall * Step 65: initialise Statistics Coalescing Tick Counter 462862387023Sdduvall */ 462962387023Sdduvall bge_reg_put64(bgep, STATUS_BLOCK_HOST_ADDR_REG, 463062387023Sdduvall bgep->status_block.cookie.dmac_laddress); 463162387023Sdduvall 463262387023Sdduvall /* 463362387023Sdduvall * Steps 66-67: initialise status block & statistics 463462387023Sdduvall * NIC-local memory addresses 463562387023Sdduvall */ 463662387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 463762387023Sdduvall bge_reg_put64(bgep, STATISTICS_HOST_ADDR_REG, 463862387023Sdduvall bgep->statistics.cookie.dmac_laddress); 463962387023Sdduvall bge_reg_put32(bgep, STATISTICS_TICKS_REG, 464062387023Sdduvall STATISTICS_TICKS_DEFAULT); 464162387023Sdduvall bge_reg_put32(bgep, STATUS_BLOCK_BASE_ADDR_REG, 464262387023Sdduvall NIC_MEM_STATUS_BLOCK); 464362387023Sdduvall bge_reg_put32(bgep, STATISTICS_BASE_ADDR_REG, 464462387023Sdduvall NIC_MEM_STATISTICS); 464562387023Sdduvall } 464662387023Sdduvall 464762387023Sdduvall /* 464862387023Sdduvall * Steps 68-71: start the Host Coalescing Engine, the Receive BD 464962387023Sdduvall * Completion Engine, the Receive List Placement Engine, and the 465062387023Sdduvall * Receive List selector.Pay attention:0x3400 is not exist in BCM5714 465162387023Sdduvall * and BCM5715. 465262387023Sdduvall */ 4653087a28d1SDavid Gwynne 4654087a28d1SDavid Gwynne if (bgep->chipid.device == DEVICE_ID_5719) { 4655087a28d1SDavid Gwynne for (i = 0; i < BGE_NUM_RDMA_CHANNELS; i++) { 4656087a28d1SDavid Gwynne if (bge_reg_get32(bgep, (BGE_RDMA_LENGTH + (i << 2))) > 4657087a28d1SDavid Gwynne bgep->chipid.default_mtu) 4658087a28d1SDavid Gwynne break; 4659087a28d1SDavid Gwynne } 4660087a28d1SDavid Gwynne if (i < BGE_NUM_RDMA_CHANNELS) { 4661087a28d1SDavid Gwynne regval = bge_reg_get32(bgep, RDMA_CORR_CTRL_REG); 4662087a28d1SDavid Gwynne regval |= RDMA_CORR_CTRL_TX_LENGTH_WA; 4663087a28d1SDavid Gwynne bge_reg_put32(bgep, RDMA_CORR_CTRL_REG, regval); 4664087a28d1SDavid Gwynne bgep->rdma_length_bug_on_5719 = B_TRUE; 4665087a28d1SDavid Gwynne } 4666087a28d1SDavid Gwynne } 4667087a28d1SDavid Gwynne 466862387023Sdduvall if (bgep->chipid.tx_rings <= COALESCE_64_BYTE_RINGS && 466962387023Sdduvall bgep->chipid.rx_rings <= COALESCE_64_BYTE_RINGS) 467062387023Sdduvall coalmode = COALESCE_64_BYTE_STATUS; 467162387023Sdduvall else 467262387023Sdduvall coalmode = 0; 4673087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 4674087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) 4675dc3f9a75Syong tan - Sun Microsystems - Beijing China coalmode = COALESCE_CLR_TICKS_RX; 467600d0963fSdilpreet if (!bge_chip_enable_engine(bgep, HOST_COALESCE_MODE_REG, coalmode)) 467700d0963fSdilpreet retval = DDI_FAILURE; 467800d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RCV_BD_COMPLETION_MODE_REG, 467900d0963fSdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 468000d0963fSdilpreet retval = DDI_FAILURE; 468100d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RCV_LIST_PLACEMENT_MODE_REG, 0)) 468200d0963fSdilpreet retval = DDI_FAILURE; 468362387023Sdduvall 468462387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 468500d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RCV_LIST_SELECTOR_MODE_REG, 468600d0963fSdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 468700d0963fSdilpreet retval = DDI_FAILURE; 468862387023Sdduvall 468962387023Sdduvall /* 469062387023Sdduvall * Step 72: Enable MAC DMA engines 469162387023Sdduvall * Step 73: Clear & enable MAC statistics 469262387023Sdduvall */ 4693087a28d1SDavid Gwynne if (bgep->ape_enabled) { 4694087a28d1SDavid Gwynne /* XXX put32 instead of set32 ? */ 4695087a28d1SDavid Gwynne bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, 4696087a28d1SDavid Gwynne ETHERNET_MODE_APE_TX_EN | ETHERNET_MODE_APE_RX_EN); 4697087a28d1SDavid Gwynne } 469862387023Sdduvall bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, 469962387023Sdduvall ETHERNET_MODE_ENABLE_FHDE | 470062387023Sdduvall ETHERNET_MODE_ENABLE_RDE | 470162387023Sdduvall ETHERNET_MODE_ENABLE_TDE); 470262387023Sdduvall bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, 470362387023Sdduvall ETHERNET_MODE_ENABLE_TX_STATS | 470462387023Sdduvall ETHERNET_MODE_ENABLE_RX_STATS | 470562387023Sdduvall ETHERNET_MODE_CLEAR_TX_STATS | 470662387023Sdduvall ETHERNET_MODE_CLEAR_RX_STATS); 470762387023Sdduvall 4708087a28d1SDavid Gwynne drv_usecwait(140); 4709087a28d1SDavid Gwynne 4710087a28d1SDavid Gwynne if (bgep->ape_enabled) { 4711087a28d1SDavid Gwynne /* Write our heartbeat update interval to APE. */ 4712087a28d1SDavid Gwynne bge_ape_put32(bgep, BGE_APE_HOST_HEARTBEAT_INT_MS, 4713087a28d1SDavid Gwynne APE_HOST_HEARTBEAT_INT_DISABLE); 4714087a28d1SDavid Gwynne } 4715087a28d1SDavid Gwynne 471662387023Sdduvall /* 471762387023Sdduvall * Step 74: configure the MLCR (Miscellaneous Local Control 471862387023Sdduvall * Register); not required, as we set up the MLCR in step 10 471962387023Sdduvall * (part of the reset code) above. 472062387023Sdduvall * 472162387023Sdduvall * Step 75: clear Interrupt Mailbox 0 472262387023Sdduvall */ 472362387023Sdduvall bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG, 0); 472462387023Sdduvall 472562387023Sdduvall /* 472662387023Sdduvall * Steps 76-87: Gentlemen, start your engines ... 472762387023Sdduvall * 472862387023Sdduvall * Enable the DMA Completion Engine, the Write DMA Engine, 472962387023Sdduvall * the Read DMA Engine, Receive Data Completion Engine, 473062387023Sdduvall * the MBuf Cluster Free Engine, the Send Data Completion Engine, 473162387023Sdduvall * the Send BD Completion Engine, the Receive BD Initiator Engine, 473262387023Sdduvall * the Receive Data Initiator Engine, the Send Data Initiator Engine, 473362387023Sdduvall * the Send BD Initiator Engine, and the Send BD Selector Engine. 473462387023Sdduvall * 473562387023Sdduvall * Beware exhaust fumes? 473662387023Sdduvall */ 473762387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 473800d0963fSdilpreet if (!bge_chip_enable_engine(bgep, DMA_COMPLETION_MODE_REG, 0)) 473900d0963fSdilpreet retval = DDI_FAILURE; 474003a69b52Sml149210 dma_wrprio = (bge_dma_wrprio << DMA_PRIORITY_SHIFT) | 474103a69b52Sml149210 ALL_DMA_ATTN_BITS; 4742087a28d1SDavid Gwynne /* the 5723 check here covers all newer chip families (OK) */ 4743087a28d1SDavid Gwynne if ((MHCR_CHIP_ASIC_REV(bgep) == MHCR_CHIP_ASIC_REV_5755) || 4744087a28d1SDavid Gwynne (MHCR_CHIP_ASIC_REV(bgep) == MHCR_CHIP_ASIC_REV_5723) || 4745087a28d1SDavid Gwynne (MHCR_CHIP_ASIC_REV(bgep) == MHCR_CHIP_ASIC_REV_5906)) { 474603a69b52Sml149210 dma_wrprio |= DMA_STATUS_TAG_FIX_CQ12384; 474703a69b52Sml149210 } 474800d0963fSdilpreet if (!bge_chip_enable_engine(bgep, WRITE_DMA_MODE_REG, 474903a69b52Sml149210 dma_wrprio)) 475000d0963fSdilpreet retval = DDI_FAILURE; 4751087a28d1SDavid Gwynne 4752087a28d1SDavid Gwynne drv_usecwait(40); 4753087a28d1SDavid Gwynne 4754dc3f9a75Syong tan - Sun Microsystems - Beijing China if (DEVICE_5723_SERIES_CHIPSETS(bgep) || 4755087a28d1SDavid Gwynne DEVICE_5717_SERIES_CHIPSETS(bgep) || 4756087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) 4757652b4801Syong tan - Sun Microsystems - Beijing China bge_dma_rdprio = 0; 475800d0963fSdilpreet if (!bge_chip_enable_engine(bgep, READ_DMA_MODE_REG, 475900d0963fSdilpreet (bge_dma_rdprio << DMA_PRIORITY_SHIFT) | ALL_DMA_ATTN_BITS)) 476000d0963fSdilpreet retval = DDI_FAILURE; 4761087a28d1SDavid Gwynne 4762087a28d1SDavid Gwynne drv_usecwait(40); 4763087a28d1SDavid Gwynne 476400d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RCV_DATA_COMPLETION_MODE_REG, 476500d0963fSdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 476600d0963fSdilpreet retval = DDI_FAILURE; 476762387023Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 476800d0963fSdilpreet if (!bge_chip_enable_engine(bgep, 476900d0963fSdilpreet MBUF_CLUSTER_FREE_MODE_REG, 0)) 477000d0963fSdilpreet retval = DDI_FAILURE; 477100d0963fSdilpreet if (!bge_chip_enable_engine(bgep, SEND_DATA_COMPLETION_MODE_REG, 0)) 477200d0963fSdilpreet retval = DDI_FAILURE; 477300d0963fSdilpreet if (!bge_chip_enable_engine(bgep, SEND_BD_COMPLETION_MODE_REG, 477400d0963fSdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 477500d0963fSdilpreet retval = DDI_FAILURE; 477600d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RCV_BD_INITIATOR_MODE_REG, 477700d0963fSdilpreet RCV_BD_DISABLED_RING_ATTN)) 477800d0963fSdilpreet retval = DDI_FAILURE; 477900d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RCV_DATA_BD_INITIATOR_MODE_REG, 478000d0963fSdilpreet RCV_DATA_BD_ILL_RING_ATTN)) 478100d0963fSdilpreet retval = DDI_FAILURE; 478200d0963fSdilpreet if (!bge_chip_enable_engine(bgep, SEND_DATA_INITIATOR_MODE_REG, 0)) 478300d0963fSdilpreet retval = DDI_FAILURE; 478400d0963fSdilpreet if (!bge_chip_enable_engine(bgep, SEND_BD_INITIATOR_MODE_REG, 478500d0963fSdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 478600d0963fSdilpreet retval = DDI_FAILURE; 478700d0963fSdilpreet if (!bge_chip_enable_engine(bgep, SEND_BD_SELECTOR_MODE_REG, 478800d0963fSdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 478900d0963fSdilpreet retval = DDI_FAILURE; 479062387023Sdduvall 4791087a28d1SDavid Gwynne drv_usecwait(40); 4792087a28d1SDavid Gwynne 479362387023Sdduvall /* 479462387023Sdduvall * Step 88: download firmware -- doesn't apply 479562387023Sdduvall * Steps 89-90: enable Transmit & Receive MAC Engines 479662387023Sdduvall */ 4797087a28d1SDavid Gwynne regval = 0; 4798087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep)) { 4799087a28d1SDavid Gwynne regval |= TRANSMIT_MODE_MBUF_LOCKUP_FIX; 4800087a28d1SDavid Gwynne } 4801087a28d1SDavid Gwynne if (!bge_chip_enable_engine(bgep, TRANSMIT_MAC_MODE_REG, regval)) 480200d0963fSdilpreet retval = DDI_FAILURE; 4803087a28d1SDavid Gwynne 4804087a28d1SDavid Gwynne drv_usecwait(100); 4805087a28d1SDavid Gwynne 480667f02347Srandyf #ifdef BGE_IPMI_ASF 480700d0963fSdilpreet if (!bgep->asf_enabled) { 480800d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RECEIVE_MAC_MODE_REG, 480900d0963fSdilpreet RECEIVE_MODE_KEEP_VLAN_TAG)) 481000d0963fSdilpreet retval = DDI_FAILURE; 481167f02347Srandyf } else { 481200d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RECEIVE_MAC_MODE_REG, 0)) 481300d0963fSdilpreet retval = DDI_FAILURE; 481467f02347Srandyf } 481567f02347Srandyf #else 481600d0963fSdilpreet if (!bge_chip_enable_engine(bgep, RECEIVE_MAC_MODE_REG, 481700d0963fSdilpreet RECEIVE_MODE_KEEP_VLAN_TAG)) 481800d0963fSdilpreet retval = DDI_FAILURE; 481967f02347Srandyf #endif 482062387023Sdduvall 4821087a28d1SDavid Gwynne drv_usecwait(100); 4822087a28d1SDavid Gwynne 482362387023Sdduvall /* 482462387023Sdduvall * Step 91: disable auto-polling of PHY status 482562387023Sdduvall */ 482662387023Sdduvall bge_reg_put32(bgep, MI_MODE_REG, MI_MODE_DEFAULT); 482762387023Sdduvall 482862387023Sdduvall /* 482962387023Sdduvall * Step 92: configure D0 power state (not required) 483062387023Sdduvall * Step 93: initialise LED control register () 483162387023Sdduvall */ 483262387023Sdduvall ledctl = LED_CONTROL_DEFAULT; 483362387023Sdduvall switch (bgep->chipid.device) { 483462387023Sdduvall case DEVICE_ID_5700: 483562387023Sdduvall case DEVICE_ID_5700x: 483662387023Sdduvall case DEVICE_ID_5701: 483762387023Sdduvall /* 483862387023Sdduvall * Switch to 5700 (MAC) mode on these older chips 483962387023Sdduvall */ 484062387023Sdduvall ledctl &= ~LED_CONTROL_LED_MODE_MASK; 484162387023Sdduvall ledctl |= LED_CONTROL_LED_MODE_5700; 484262387023Sdduvall break; 484362387023Sdduvall 484462387023Sdduvall default: 484562387023Sdduvall break; 484662387023Sdduvall } 484762387023Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_LED_CONTROL_REG, ledctl); 484862387023Sdduvall 484962387023Sdduvall /* 485062387023Sdduvall * Step 94: activate link 485162387023Sdduvall */ 485262387023Sdduvall bge_reg_put32(bgep, MI_STATUS_REG, MI_STATUS_LINK); 485362387023Sdduvall 485462387023Sdduvall /* 485562387023Sdduvall * Step 95: set up physical layer (PHY/SerDes) 485662387023Sdduvall * restart autoneg (if required) 485762387023Sdduvall */ 485862387023Sdduvall if (reset_phys) 4859087a28d1SDavid Gwynne { 486000d0963fSdilpreet if (bge_phys_update(bgep) == DDI_FAILURE) 486100d0963fSdilpreet retval = DDI_FAILURE; 4862087a28d1SDavid Gwynne /* forcing a mac link update here */ 4863087a28d1SDavid Gwynne bge_phys_check(bgep); 4864087a28d1SDavid Gwynne bgep->link_state = (bgep->param_link_up) ? LINK_STATE_UP : 4865087a28d1SDavid Gwynne LINK_STATE_DOWN; 4866087a28d1SDavid Gwynne bge_sync_mac_modes(bgep); 4867087a28d1SDavid Gwynne mac_link_update(bgep->mh, bgep->link_state); 4868087a28d1SDavid Gwynne } 486962387023Sdduvall 487062387023Sdduvall /* 487162387023Sdduvall * Extra step (DSG): hand over all the Receive Buffers to the chip 487262387023Sdduvall */ 487362387023Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_USED; ++ring) 487462387023Sdduvall bge_mbx_put(bgep, bgep->buff[ring].chip_mbx_reg, 487562387023Sdduvall bgep->buff[ring].rf_next); 487662387023Sdduvall 487762387023Sdduvall /* 487862387023Sdduvall * MSI bits:The least significant MSI 16-bit word. 487962387023Sdduvall * ISR will be triggered different. 488062387023Sdduvall */ 488162387023Sdduvall if (bgep->intr_type == DDI_INTR_TYPE_MSI) 488262387023Sdduvall bge_reg_set32(bgep, HOST_COALESCE_MODE_REG, 0x70); 488362387023Sdduvall 488462387023Sdduvall /* 488562387023Sdduvall * Extra step (DSG): select which interrupts are enabled 488662387023Sdduvall * 488762387023Sdduvall * Program the Ethernet MAC engine to signal attention on 488862387023Sdduvall * Link Change events, then enable interrupts on MAC, DMA, 488962387023Sdduvall * and FLOW attention signals. 489062387023Sdduvall */ 489162387023Sdduvall bge_reg_set32(bgep, ETHERNET_MAC_EVENT_ENABLE_REG, 489262387023Sdduvall ETHERNET_EVENT_LINK_INT | 489362387023Sdduvall ETHERNET_STATUS_PCS_ERROR_INT); 489467f02347Srandyf #ifdef BGE_IPMI_ASF 489567f02347Srandyf if (bgep->asf_enabled) { 489667f02347Srandyf bge_reg_set32(bgep, MODE_CONTROL_REG, 489767f02347Srandyf MODE_INT_ON_FLOW_ATTN | 489867f02347Srandyf MODE_INT_ON_DMA_ATTN | 489967f02347Srandyf MODE_HOST_STACK_UP| 490067f02347Srandyf MODE_INT_ON_MAC_ATTN); 490167f02347Srandyf } else { 490267f02347Srandyf #endif 490362387023Sdduvall bge_reg_set32(bgep, MODE_CONTROL_REG, 490462387023Sdduvall MODE_INT_ON_FLOW_ATTN | 490562387023Sdduvall MODE_INT_ON_DMA_ATTN | 490662387023Sdduvall MODE_INT_ON_MAC_ATTN); 490767f02347Srandyf #ifdef BGE_IPMI_ASF 490867f02347Srandyf } 490967f02347Srandyf #endif 491062387023Sdduvall 4911087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 4912087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 4913087a28d1SDavid Gwynne bge_cfg_clr16(bgep, PCI_CONF_DEV_CTRL_5717, 4914087a28d1SDavid Gwynne DEV_CTRL_NO_SNOOP | DEV_CTRL_RELAXED); 4915087a28d1SDavid Gwynne #if 0 4916087a28d1SDavid Gwynne mhcr = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MHCR); 4917087a28d1SDavid Gwynne pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, 4918087a28d1SDavid Gwynne (mhcr | MHCR_TLP_MINOR_ERR_TOLERANCE)); 4919087a28d1SDavid Gwynne #endif 4920087a28d1SDavid Gwynne } 4921087a28d1SDavid Gwynne 492262387023Sdduvall /* 492362387023Sdduvall * Step 97: enable PCI interrupts!!! 492462387023Sdduvall */ 492562387023Sdduvall if (bgep->intr_type == DDI_INTR_TYPE_FIXED) 492662387023Sdduvall bge_cfg_clr32(bgep, PCI_CONF_BGE_MHCR, 4927dc3f9a75Syong tan - Sun Microsystems - Beijing China bgep->chipid.mask_pci_int); 492862387023Sdduvall 492962387023Sdduvall /* 493062387023Sdduvall * All done! 493162387023Sdduvall */ 493262387023Sdduvall bgep->bge_chip_state = BGE_CHIP_RUNNING; 493300d0963fSdilpreet return (retval); 493462387023Sdduvall } 493562387023Sdduvall 493662387023Sdduvall 493762387023Sdduvall /* 493862387023Sdduvall * ========== Hardware interrupt handler ========== 493962387023Sdduvall */ 494062387023Sdduvall 494162387023Sdduvall #undef BGE_DBG 494262387023Sdduvall #define BGE_DBG BGE_DBG_INT /* debug flag for this code */ 494362387023Sdduvall 494462387023Sdduvall /* 494562387023Sdduvall * Sync the status block, then atomically clear the specified bits in 494662387023Sdduvall * the <flags-and-tag> field of the status block. 494762387023Sdduvall * the <flags> word of the status block, returning the value of the 494862387023Sdduvall * <tag> and the <flags> before the bits were cleared. 494962387023Sdduvall */ 495000d0963fSdilpreet static int bge_status_sync(bge_t *bgep, uint64_t bits, uint64_t *flags); 495162387023Sdduvall #pragma inline(bge_status_sync) 495262387023Sdduvall 495300d0963fSdilpreet static int 495400d0963fSdilpreet bge_status_sync(bge_t *bgep, uint64_t bits, uint64_t *flags) 495562387023Sdduvall { 495662387023Sdduvall bge_status_t *bsp; 495700d0963fSdilpreet int retval; 495862387023Sdduvall 495962387023Sdduvall BGE_TRACE(("bge_status_sync($%p, 0x%llx)", 496062387023Sdduvall (void *)bgep, bits)); 496162387023Sdduvall 496262387023Sdduvall ASSERT(bgep->bge_guard == BGE_GUARD); 496362387023Sdduvall 496462387023Sdduvall DMA_SYNC(bgep->status_block, DDI_DMA_SYNC_FORKERNEL); 496500d0963fSdilpreet retval = bge_check_dma_handle(bgep, bgep->status_block.dma_hdl); 496600d0963fSdilpreet if (retval != DDI_FM_OK) 496700d0963fSdilpreet return (retval); 496800d0963fSdilpreet 496962387023Sdduvall bsp = DMA_VPTR(bgep->status_block); 497000d0963fSdilpreet *flags = bge_atomic_clr64(&bsp->flags_n_tag, bits); 497162387023Sdduvall 497262387023Sdduvall BGE_DEBUG(("bge_status_sync($%p, 0x%llx) returning 0x%llx", 497300d0963fSdilpreet (void *)bgep, bits, *flags)); 497462387023Sdduvall 497500d0963fSdilpreet return (retval); 497662387023Sdduvall } 497762387023Sdduvall 4978e7801d59Ssowmini void bge_wake_factotum(bge_t *bgep); 497962387023Sdduvall #pragma inline(bge_wake_factotum) 498062387023Sdduvall 4981e7801d59Ssowmini void 498262387023Sdduvall bge_wake_factotum(bge_t *bgep) 498362387023Sdduvall { 498462387023Sdduvall mutex_enter(bgep->softintrlock); 498562387023Sdduvall if (bgep->factotum_flag == 0) { 498662387023Sdduvall bgep->factotum_flag = 1; 498762387023Sdduvall ddi_trigger_softintr(bgep->factotum_id); 498862387023Sdduvall } 498962387023Sdduvall mutex_exit(bgep->softintrlock); 499062387023Sdduvall } 499162387023Sdduvall 4992087a28d1SDavid Gwynne static void 4993087a28d1SDavid Gwynne bge_intr_error_handler(bge_t *bgep) 4994087a28d1SDavid Gwynne { 4995087a28d1SDavid Gwynne uint32_t flow; 4996087a28d1SDavid Gwynne uint32_t rdma; 4997087a28d1SDavid Gwynne uint32_t wdma; 4998087a28d1SDavid Gwynne uint32_t tmac; 4999087a28d1SDavid Gwynne uint32_t rmac; 5000087a28d1SDavid Gwynne uint32_t rxrs; 5001087a28d1SDavid Gwynne uint32_t emac; 5002087a28d1SDavid Gwynne uint32_t msis; 5003087a28d1SDavid Gwynne uint32_t txrs = 0; 5004087a28d1SDavid Gwynne 5005087a28d1SDavid Gwynne ASSERT(mutex_owned(bgep->genlock)); 5006087a28d1SDavid Gwynne 5007087a28d1SDavid Gwynne /* 5008087a28d1SDavid Gwynne * Read all the registers that show the possible 5009087a28d1SDavid Gwynne * reasons for the ERROR bit to be asserted 5010087a28d1SDavid Gwynne */ 5011087a28d1SDavid Gwynne flow = bge_reg_get32(bgep, FLOW_ATTN_REG); 5012087a28d1SDavid Gwynne rdma = bge_reg_get32(bgep, READ_DMA_STATUS_REG); 5013087a28d1SDavid Gwynne wdma = bge_reg_get32(bgep, WRITE_DMA_STATUS_REG); 5014087a28d1SDavid Gwynne tmac = bge_reg_get32(bgep, TRANSMIT_MAC_STATUS_REG); 5015087a28d1SDavid Gwynne rmac = bge_reg_get32(bgep, RECEIVE_MAC_STATUS_REG); 5016087a28d1SDavid Gwynne rxrs = bge_reg_get32(bgep, RX_RISC_STATE_REG); 5017087a28d1SDavid Gwynne emac = bge_reg_get32(bgep, ETHERNET_MAC_STATUS_REG); 5018087a28d1SDavid Gwynne msis = bge_reg_get32(bgep, MSI_STATUS_REG); 5019087a28d1SDavid Gwynne if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 5020087a28d1SDavid Gwynne txrs = bge_reg_get32(bgep, TX_RISC_STATE_REG); 5021087a28d1SDavid Gwynne 5022087a28d1SDavid Gwynne BGE_DEBUG(("factotum($%p) flow 0x%x rdma 0x%x wdma 0x%x emac 0x%x msis 0x%x", 5023087a28d1SDavid Gwynne (void *)bgep, flow, rdma, wdma, emac, msis)); 5024087a28d1SDavid Gwynne BGE_DEBUG(("factotum($%p) tmac 0x%x rmac 0x%x rxrs 0x%08x txrs 0x%08x", 5025087a28d1SDavid Gwynne (void *)bgep, tmac, rmac, rxrs, txrs)); 5026087a28d1SDavid Gwynne 5027087a28d1SDavid Gwynne /* 5028087a28d1SDavid Gwynne * For now, just clear all the errors ... 5029087a28d1SDavid Gwynne */ 5030087a28d1SDavid Gwynne if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 5031087a28d1SDavid Gwynne bge_reg_put32(bgep, TX_RISC_STATE_REG, ~0); 5032087a28d1SDavid Gwynne bge_reg_put32(bgep, RX_RISC_STATE_REG, ~0); 5033087a28d1SDavid Gwynne bge_reg_put32(bgep, RECEIVE_MAC_STATUS_REG, ~0); 5034087a28d1SDavid Gwynne bge_reg_put32(bgep, WRITE_DMA_STATUS_REG, ~0); 5035087a28d1SDavid Gwynne bge_reg_put32(bgep, READ_DMA_STATUS_REG, ~0); 5036087a28d1SDavid Gwynne bge_reg_put32(bgep, FLOW_ATTN_REG, ~0); 5037087a28d1SDavid Gwynne } 5038087a28d1SDavid Gwynne 503962387023Sdduvall /* 504062387023Sdduvall * bge_intr() -- handle chip interrupts 504162387023Sdduvall */ 504262387023Sdduvall uint_t bge_intr(caddr_t arg1, caddr_t arg2); 504362387023Sdduvall #pragma no_inline(bge_intr) 504462387023Sdduvall 504562387023Sdduvall uint_t 504662387023Sdduvall bge_intr(caddr_t arg1, caddr_t arg2) 504762387023Sdduvall { 50484a06b59fSyt223700 bge_t *bgep = (void *)arg1; /* private device info */ 504962387023Sdduvall bge_status_t *bsp; 505062387023Sdduvall uint64_t flags; 50515952d588Szh199473 uint32_t regval; 505262387023Sdduvall uint_t result; 5053a4de4ba2Sml149210 int retval, loop_cnt = 0; 505462387023Sdduvall 505562387023Sdduvall BGE_TRACE(("bge_intr($%p) ($%p)", arg1, arg2)); 505662387023Sdduvall 505762387023Sdduvall /* 505862387023Sdduvall * GLD v2 checks that s/w setup is complete before passing 505962387023Sdduvall * interrupts to this routine, thus eliminating the old 506062387023Sdduvall * (and well-known) race condition around ddi_add_intr() 506162387023Sdduvall */ 506262387023Sdduvall ASSERT(bgep->progress & PROGRESS_HWINT); 506362387023Sdduvall 50645952d588Szh199473 result = DDI_INTR_UNCLAIMED; 50655952d588Szh199473 mutex_enter(bgep->genlock); 50665952d588Szh199473 50675952d588Szh199473 if (bgep->intr_type == DDI_INTR_TYPE_FIXED) { 506862387023Sdduvall /* 506962387023Sdduvall * Check whether chip's says it's asserting #INTA; 507062387023Sdduvall * if not, don't process or claim the interrupt. 507162387023Sdduvall * 507262387023Sdduvall * Note that the PCI signal is active low, so the 507362387023Sdduvall * bit is *zero* when the interrupt is asserted. 507462387023Sdduvall */ 50755952d588Szh199473 regval = bge_reg_get32(bgep, MISC_LOCAL_CONTROL_REG); 5076087a28d1SDavid Gwynne if (!(DEVICE_5717_SERIES_CHIPSETS(bgep) || 5077087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) && 5078dc3f9a75Syong tan - Sun Microsystems - Beijing China (regval & MLCR_INTA_STATE)) { 50795952d588Szh199473 if (bge_check_acc_handle(bgep, bgep->io_handle) 50805952d588Szh199473 != DDI_FM_OK) 50815952d588Szh199473 goto chip_stop; 50825952d588Szh199473 mutex_exit(bgep->genlock); 50835952d588Szh199473 return (result); 50845952d588Szh199473 } 508562387023Sdduvall 508662387023Sdduvall /* 508762387023Sdduvall * Block further PCI interrupts ... 508862387023Sdduvall */ 50891b5c96f3Sly149593 bge_reg_set32(bgep, PCI_CONF_BGE_MHCR, 5090dc3f9a75Syong tan - Sun Microsystems - Beijing China bgep->chipid.mask_pci_int); 50915952d588Szh199473 50925952d588Szh199473 } else { 50935952d588Szh199473 /* 50945952d588Szh199473 * Check MSI status 50955952d588Szh199473 */ 50965952d588Szh199473 regval = bge_reg_get32(bgep, MSI_STATUS_REG); 50975952d588Szh199473 if (regval & MSI_ERROR_ATTENTION) { 50985952d588Szh199473 BGE_REPORT((bgep, "msi error attention," 50995952d588Szh199473 " status=0x%x", regval)); 51005952d588Szh199473 bge_reg_put32(bgep, MSI_STATUS_REG, regval); 510100d0963fSdilpreet } 51025952d588Szh199473 } 51035952d588Szh199473 51045952d588Szh199473 result = DDI_INTR_CLAIMED; 51055952d588Szh199473 51065952d588Szh199473 BGE_DEBUG(("bge_intr($%p) ($%p) regval 0x%08x", arg1, arg2, regval)); 510762387023Sdduvall 510862387023Sdduvall /* 510962387023Sdduvall * Sync the status block and grab the flags-n-tag from it. 511062387023Sdduvall * We count the number of interrupts where there doesn't 511162387023Sdduvall * seem to have been a DMA update of the status block; if 511262387023Sdduvall * it *has* been updated, the counter will be cleared in 511362387023Sdduvall * the while() loop below ... 511462387023Sdduvall */ 511562387023Sdduvall bgep->missed_dmas += 1; 511662387023Sdduvall bsp = DMA_VPTR(bgep->status_block); 5117a4de4ba2Sml149210 for (loop_cnt = 0; loop_cnt < bge_intr_max_loop; loop_cnt++) { 511800d0963fSdilpreet if (bgep->bge_chip_state != BGE_CHIP_RUNNING) { 511900d0963fSdilpreet /* 512000d0963fSdilpreet * bge_chip_stop() may have freed dma area etc 512100d0963fSdilpreet * while we were in this interrupt handler - 512200d0963fSdilpreet * better not call bge_status_sync() 512300d0963fSdilpreet */ 512400d0963fSdilpreet (void) bge_check_acc_handle(bgep, 512500d0963fSdilpreet bgep->io_handle); 512600d0963fSdilpreet mutex_exit(bgep->genlock); 512700d0963fSdilpreet return (DDI_INTR_CLAIMED); 512800d0963fSdilpreet } 5129087a28d1SDavid Gwynne 5130087a28d1SDavid Gwynne retval = bge_status_sync(bgep, STATUS_FLAG_UPDATED | 5131087a28d1SDavid Gwynne STATUS_FLAG_LINK_CHANGED | STATUS_FLAG_ERROR, &flags); 513200d0963fSdilpreet if (retval != DDI_FM_OK) { 513300d0963fSdilpreet bgep->bge_dma_error = B_TRUE; 513400d0963fSdilpreet goto chip_stop; 513500d0963fSdilpreet } 513662387023Sdduvall 513700d0963fSdilpreet if (!(flags & STATUS_FLAG_UPDATED)) 513800d0963fSdilpreet break; 513900d0963fSdilpreet 514062387023Sdduvall /* 514162387023Sdduvall * Tell the chip that we're processing the interrupt 514262387023Sdduvall */ 514362387023Sdduvall bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG, 514462387023Sdduvall INTERRUPT_MBOX_DISABLE(flags)); 514500d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != 514600d0963fSdilpreet DDI_FM_OK) 514700d0963fSdilpreet goto chip_stop; 514862387023Sdduvall 5149087a28d1SDavid Gwynne if (flags & STATUS_FLAG_LINK_CHANGED) { 5150087a28d1SDavid Gwynne BGE_DEBUG(("bge_intr($%p) ($%p) link event", arg1, arg2)); 5151087a28d1SDavid Gwynne if (bge_phys_check(bgep)) { 5152087a28d1SDavid Gwynne bgep->link_state = bgep->param_link_up ? 5153087a28d1SDavid Gwynne LINK_STATE_UP : LINK_STATE_DOWN; 5154087a28d1SDavid Gwynne bge_sync_mac_modes(bgep); 5155087a28d1SDavid Gwynne mac_link_update(bgep->mh, bgep->link_state); 5156087a28d1SDavid Gwynne } 5157087a28d1SDavid Gwynne 5158087a28d1SDavid Gwynne if (bge_check_acc_handle(bgep, bgep->io_handle) != 5159087a28d1SDavid Gwynne DDI_FM_OK) 5160087a28d1SDavid Gwynne goto chip_stop; 5161087a28d1SDavid Gwynne } 5162087a28d1SDavid Gwynne 5163087a28d1SDavid Gwynne if (flags & STATUS_FLAG_ERROR) { 5164087a28d1SDavid Gwynne bge_intr_error_handler(bgep); 5165087a28d1SDavid Gwynne 5166087a28d1SDavid Gwynne if (bge_check_acc_handle(bgep, bgep->io_handle) != 5167087a28d1SDavid Gwynne DDI_FM_OK) 5168087a28d1SDavid Gwynne goto chip_stop; 5169087a28d1SDavid Gwynne } 5170087a28d1SDavid Gwynne 517162387023Sdduvall /* 517262387023Sdduvall * Drop the mutex while we: 517362387023Sdduvall * Receive any newly-arrived packets 517462387023Sdduvall * Recycle any newly-finished send buffers 517562387023Sdduvall */ 517600d0963fSdilpreet bgep->bge_intr_running = B_TRUE; 517762387023Sdduvall mutex_exit(bgep->genlock); 517862387023Sdduvall bge_receive(bgep, bsp); 51792adae974Syong tan - Sun Microsystems - Beijing China (void) bge_recycle(bgep, bsp); 518062387023Sdduvall mutex_enter(bgep->genlock); 518100d0963fSdilpreet bgep->bge_intr_running = B_FALSE; 518262387023Sdduvall 518362387023Sdduvall /* 518462387023Sdduvall * Tell the chip we've finished processing, and 518562387023Sdduvall * give it the tag that we got from the status 518662387023Sdduvall * block earlier, so that it knows just how far 518762387023Sdduvall * we've gone. If it's got more for us to do, 518862387023Sdduvall * it will now update the status block and try 518962387023Sdduvall * to assert an interrupt (but we've got the 519062387023Sdduvall * #INTA blocked at present). If we see the 519162387023Sdduvall * update, we'll loop around to do some more. 519262387023Sdduvall * Eventually we'll get out of here ... 519362387023Sdduvall */ 519462387023Sdduvall bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG, 519562387023Sdduvall INTERRUPT_MBOX_ENABLE(flags)); 5196dca582a1Sgh162552 if (bgep->chipid.pci_type == BGE_PCI_E) 5197dca582a1Sgh162552 (void) bge_mbx_get(bgep, INTERRUPT_MBOX_0_REG); 519862387023Sdduvall bgep->missed_dmas = 0; 519962387023Sdduvall } 520062387023Sdduvall 520162387023Sdduvall if (bgep->missed_dmas) { 520262387023Sdduvall /* 520362387023Sdduvall * Probably due to the internal status tag not 520462387023Sdduvall * being reset. Force a status block update now; 520562387023Sdduvall * this should ensure that we get an update and 520662387023Sdduvall * a new interrupt. After that, we should be in 520762387023Sdduvall * sync again ... 520862387023Sdduvall */ 520962387023Sdduvall BGE_REPORT((bgep, "interrupt: flags 0x%llx - " 521062387023Sdduvall "not updated?", flags)); 52115952d588Szh199473 bgep->missed_updates++; 521262387023Sdduvall bge_reg_set32(bgep, HOST_COALESCE_MODE_REG, 521362387023Sdduvall COALESCE_NOW); 521462387023Sdduvall 521562387023Sdduvall if (bgep->missed_dmas >= bge_dma_miss_limit) { 521662387023Sdduvall /* 521762387023Sdduvall * If this happens multiple times in a row, 521862387023Sdduvall * it means DMA is just not working. Maybe 521962387023Sdduvall * the chip's failed, or maybe there's a 522062387023Sdduvall * problem on the PCI bus or in the host-PCI 522162387023Sdduvall * bridge (Tomatillo). 522262387023Sdduvall * 522362387023Sdduvall * At all events, we want to stop further 522462387023Sdduvall * interrupts and let the recovery code take 522562387023Sdduvall * over to see whether anything can be done 522662387023Sdduvall * about it ... 522762387023Sdduvall */ 522800d0963fSdilpreet bge_fm_ereport(bgep, 522900d0963fSdilpreet DDI_FM_DEVICE_BADINT_LIMIT); 523000d0963fSdilpreet goto chip_stop; 523100d0963fSdilpreet } 523200d0963fSdilpreet } 523300d0963fSdilpreet 523400d0963fSdilpreet /* 523500d0963fSdilpreet * Reenable assertion of #INTA, unless there's a DMA fault 523600d0963fSdilpreet */ 523700d0963fSdilpreet if (bgep->intr_type == DDI_INTR_TYPE_FIXED) { 52381b5c96f3Sly149593 bge_reg_clr32(bgep, PCI_CONF_BGE_MHCR, 5239dc3f9a75Syong tan - Sun Microsystems - Beijing China bgep->chipid.mask_pci_int); 52405952d588Szh199473 if (bge_check_acc_handle(bgep, bgep->cfg_handle) != 52415952d588Szh199473 DDI_FM_OK) 524200d0963fSdilpreet goto chip_stop; 524300d0963fSdilpreet } 524400d0963fSdilpreet 524500d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 524600d0963fSdilpreet goto chip_stop; 524700d0963fSdilpreet 524800d0963fSdilpreet mutex_exit(bgep->genlock); 524900d0963fSdilpreet return (result); 525000d0963fSdilpreet 525100d0963fSdilpreet chip_stop: 5252087a28d1SDavid Gwynne 525367f02347Srandyf #ifdef BGE_IPMI_ASF 525400d0963fSdilpreet if (bgep->asf_enabled && bgep->asf_status == ASF_STAT_RUN) { 525567f02347Srandyf /* 525667f02347Srandyf * We must stop ASF heart beat before 525767f02347Srandyf * bge_chip_stop(), otherwise some 525867f02347Srandyf * computers (ex. IBM HS20 blade 525967f02347Srandyf * server) may crash. 526067f02347Srandyf */ 526167f02347Srandyf bge_asf_update_status(bgep); 526267f02347Srandyf bge_asf_stop_timer(bgep); 526367f02347Srandyf bgep->asf_status = ASF_STAT_STOP; 526467f02347Srandyf 526500d0963fSdilpreet bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 526600d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 526767f02347Srandyf } 526867f02347Srandyf #endif 526962387023Sdduvall bge_chip_stop(bgep, B_TRUE); 527000d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 527162387023Sdduvall mutex_exit(bgep->genlock); 527262387023Sdduvall return (result); 527362387023Sdduvall } 527462387023Sdduvall 527562387023Sdduvall /* 527662387023Sdduvall * ========== Factotum, implemented as a softint handler ========== 527762387023Sdduvall */ 527862387023Sdduvall 527962387023Sdduvall #undef BGE_DBG 528062387023Sdduvall #define BGE_DBG BGE_DBG_FACT /* debug flag for this code */ 528162387023Sdduvall 528262387023Sdduvall /* 528362387023Sdduvall * Factotum routine to check for Tx stall, using the 'watchdog' counter 528462387023Sdduvall */ 528562387023Sdduvall static boolean_t bge_factotum_stall_check(bge_t *bgep); 528662387023Sdduvall #pragma no_inline(bge_factotum_stall_check) 528762387023Sdduvall 528862387023Sdduvall static boolean_t 528962387023Sdduvall bge_factotum_stall_check(bge_t *bgep) 529062387023Sdduvall { 529162387023Sdduvall uint32_t dogval; 52922adae974Syong tan - Sun Microsystems - Beijing China bge_status_t *bsp; 52932adae974Syong tan - Sun Microsystems - Beijing China uint64_t now = gethrtime(); 52942adae974Syong tan - Sun Microsystems - Beijing China 52952adae974Syong tan - Sun Microsystems - Beijing China if ((now - bgep->timestamp) < BGE_CYCLIC_PERIOD) 52962adae974Syong tan - Sun Microsystems - Beijing China return (B_FALSE); 52972adae974Syong tan - Sun Microsystems - Beijing China 52982adae974Syong tan - Sun Microsystems - Beijing China bgep->timestamp = now; 529962387023Sdduvall 530062387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 530162387023Sdduvall 530262387023Sdduvall /* 530362387023Sdduvall * Specific check for Tx stall ... 530462387023Sdduvall * 530562387023Sdduvall * The 'watchdog' counter is incremented whenever a packet 530662387023Sdduvall * is queued, reset to 1 when some (but not all) buffers 530762387023Sdduvall * are reclaimed, reset to 0 (disabled) when all buffers 530862387023Sdduvall * are reclaimed, and shifted left here. If it exceeds the 530962387023Sdduvall * threshold value, the chip is assumed to have stalled and 531062387023Sdduvall * is put into the ERROR state. The factotum will then reset 531162387023Sdduvall * it on the next pass. 531262387023Sdduvall * 531362387023Sdduvall * All of which should ensure that we don't get into a state 531462387023Sdduvall * where packets are left pending indefinitely! 531562387023Sdduvall */ 531662387023Sdduvall dogval = bge_atomic_shl32(&bgep->watchdog, 1); 53172adae974Syong tan - Sun Microsystems - Beijing China bsp = DMA_VPTR(bgep->status_block); 53182adae974Syong tan - Sun Microsystems - Beijing China if (dogval < bge_watchdog_count || bge_recycle(bgep, bsp)) 531962387023Sdduvall return (B_FALSE); 532062387023Sdduvall 5321a4de4ba2Sml149210 #if !defined(BGE_NETCONSOLE) 532262387023Sdduvall BGE_REPORT((bgep, "Tx stall detected, watchdog code 0x%x", dogval)); 5323a4de4ba2Sml149210 #endif 532400d0963fSdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_STALL); 532562387023Sdduvall return (B_TRUE); 532662387023Sdduvall } 532762387023Sdduvall 532862387023Sdduvall /* 532962387023Sdduvall * The factotum is woken up when there's something to do that we'd rather 533062387023Sdduvall * not do from inside a hardware interrupt handler or high-level cyclic. 5331087a28d1SDavid Gwynne * Its main task is to reset & restart the chip after an error. 533262387023Sdduvall */ 533362387023Sdduvall uint_t bge_chip_factotum(caddr_t arg); 533462387023Sdduvall #pragma no_inline(bge_chip_factotum) 533562387023Sdduvall 533662387023Sdduvall uint_t 533762387023Sdduvall bge_chip_factotum(caddr_t arg) 533862387023Sdduvall { 533962387023Sdduvall bge_t *bgep; 534062387023Sdduvall uint_t result; 534162387023Sdduvall boolean_t error; 534200d0963fSdilpreet int dma_state; 534362387023Sdduvall 53444a06b59fSyt223700 bgep = (void *)arg; 534562387023Sdduvall 534662387023Sdduvall BGE_TRACE(("bge_chip_factotum($%p)", (void *)bgep)); 534762387023Sdduvall 534862387023Sdduvall mutex_enter(bgep->softintrlock); 534962387023Sdduvall if (bgep->factotum_flag == 0) { 535062387023Sdduvall mutex_exit(bgep->softintrlock); 535162387023Sdduvall return (DDI_INTR_UNCLAIMED); 535262387023Sdduvall } 535354868785Sly149593 bgep->factotum_flag = 0; 535462387023Sdduvall mutex_exit(bgep->softintrlock); 535562387023Sdduvall 535662387023Sdduvall result = DDI_INTR_CLAIMED; 535762387023Sdduvall error = B_FALSE; 535862387023Sdduvall 535962387023Sdduvall mutex_enter(bgep->genlock); 536062387023Sdduvall switch (bgep->bge_chip_state) { 536162387023Sdduvall default: 536262387023Sdduvall break; 536362387023Sdduvall 536462387023Sdduvall case BGE_CHIP_RUNNING: 5365087a28d1SDavid Gwynne 5366087a28d1SDavid Gwynne if (bgep->chipid.device == DEVICE_ID_5700) { 5367087a28d1SDavid Gwynne if (bge_phys_check(bgep)) { 5368087a28d1SDavid Gwynne bgep->link_state = (bgep->param_link_up) ? 5369087a28d1SDavid Gwynne LINK_STATE_UP : LINK_STATE_DOWN; 5370087a28d1SDavid Gwynne bge_sync_mac_modes(bgep); 5371087a28d1SDavid Gwynne mac_link_update(bgep->mh, bgep->link_state); 5372087a28d1SDavid Gwynne } 5373087a28d1SDavid Gwynne } 5374087a28d1SDavid Gwynne 537562387023Sdduvall error = bge_factotum_stall_check(bgep); 537600d0963fSdilpreet if (dma_state != DDI_FM_OK) { 537700d0963fSdilpreet bgep->bge_dma_error = B_TRUE; 537800d0963fSdilpreet error = B_TRUE; 537900d0963fSdilpreet } 538000d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 538100d0963fSdilpreet error = B_TRUE; 538200d0963fSdilpreet if (error) 538300d0963fSdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 538462387023Sdduvall break; 538562387023Sdduvall 538662387023Sdduvall case BGE_CHIP_ERROR: 538762387023Sdduvall error = B_TRUE; 538862387023Sdduvall break; 538962387023Sdduvall 539062387023Sdduvall case BGE_CHIP_FAULT: 539162387023Sdduvall /* 539262387023Sdduvall * Fault detected, time to reset ... 539362387023Sdduvall */ 539462387023Sdduvall if (bge_autorecover) { 539500d0963fSdilpreet if (!(bgep->progress & PROGRESS_BUFS)) { 539667f02347Srandyf /* 539700d0963fSdilpreet * if we can't allocate the ring buffers, 539800d0963fSdilpreet * try later 539967f02347Srandyf */ 540000d0963fSdilpreet if (bge_alloc_bufs(bgep) != DDI_SUCCESS) { 540100d0963fSdilpreet mutex_exit(bgep->genlock); 540200d0963fSdilpreet return (result); 540300d0963fSdilpreet } 540400d0963fSdilpreet bgep->progress |= PROGRESS_BUFS; 540500d0963fSdilpreet } 540600d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 540700d0963fSdilpreet bge_init_rings(bgep); 540800d0963fSdilpreet bge_intr_enable(bgep); 540900d0963fSdilpreet bgep->progress |= PROGRESS_INTR; 541000d0963fSdilpreet } 541100d0963fSdilpreet if (!(bgep->progress & PROGRESS_KSTATS)) { 541200d0963fSdilpreet bge_init_kstats(bgep, 541300d0963fSdilpreet ddi_get_instance(bgep->devinfo)); 541400d0963fSdilpreet bgep->progress |= PROGRESS_KSTATS; 541500d0963fSdilpreet } 541600d0963fSdilpreet 541700d0963fSdilpreet BGE_REPORT((bgep, "automatic recovery activated")); 541800d0963fSdilpreet 541900d0963fSdilpreet if (bge_restart(bgep, B_FALSE) != DDI_SUCCESS) { 542000d0963fSdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 542100d0963fSdilpreet error = B_TRUE; 542200d0963fSdilpreet } 542300d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != 542400d0963fSdilpreet DDI_FM_OK) { 542500d0963fSdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 542600d0963fSdilpreet error = B_TRUE; 542700d0963fSdilpreet } 542800d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != 542900d0963fSdilpreet DDI_FM_OK) { 543000d0963fSdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 543100d0963fSdilpreet error = B_TRUE; 543200d0963fSdilpreet } 543300d0963fSdilpreet if (error == B_FALSE) { 543400d0963fSdilpreet #ifdef BGE_IPMI_ASF 543500d0963fSdilpreet if (bgep->asf_enabled && 543600d0963fSdilpreet bgep->asf_status != ASF_STAT_RUN) { 543767f02347Srandyf bgep->asf_timeout_id = timeout( 543800d0963fSdilpreet bge_asf_heartbeat, (void *)bgep, 543967f02347Srandyf drv_usectohz( 544067f02347Srandyf BGE_ASF_HEARTBEAT_INTERVAL)); 544167f02347Srandyf bgep->asf_status = ASF_STAT_RUN; 544267f02347Srandyf } 544367f02347Srandyf #endif 5444e7801d59Ssowmini if (!bgep->manual_reset) { 544500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 544600d0963fSdilpreet DDI_SERVICE_RESTORED); 544700d0963fSdilpreet } 544862387023Sdduvall } 5449e7801d59Ssowmini } 545062387023Sdduvall break; 545162387023Sdduvall } 545262387023Sdduvall 545362387023Sdduvall /* 545462387023Sdduvall * If an error is detected, stop the chip now, marking it as 545562387023Sdduvall * faulty, so that it will be reset next time through ... 545600d0963fSdilpreet * 545700d0963fSdilpreet * Note that if intr_running is set, then bge_intr() has dropped 545800d0963fSdilpreet * genlock to call bge_receive/bge_recycle. Can't stop the chip at 545900d0963fSdilpreet * this point so have to wait until the next time the factotum runs. 546062387023Sdduvall */ 546100d0963fSdilpreet if (error && !bgep->bge_intr_running) { 546267f02347Srandyf #ifdef BGE_IPMI_ASF 546367f02347Srandyf if (bgep->asf_enabled && (bgep->asf_status == ASF_STAT_RUN)) { 546467f02347Srandyf /* 546567f02347Srandyf * We must stop ASF heart beat before bge_chip_stop(), 546667f02347Srandyf * otherwise some computers (ex. IBM HS20 blade server) 546767f02347Srandyf * may crash. 546867f02347Srandyf */ 546967f02347Srandyf bge_asf_update_status(bgep); 547067f02347Srandyf bge_asf_stop_timer(bgep); 547167f02347Srandyf bgep->asf_status = ASF_STAT_STOP; 547267f02347Srandyf 547367f02347Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 547400d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 547567f02347Srandyf } 547667f02347Srandyf #endif 547762387023Sdduvall bge_chip_stop(bgep, B_TRUE); 547800d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 547967f02347Srandyf } 548062387023Sdduvall mutex_exit(bgep->genlock); 548162387023Sdduvall 548262387023Sdduvall return (result); 548362387023Sdduvall } 548462387023Sdduvall 548562387023Sdduvall /* 548662387023Sdduvall * High-level cyclic handler 548762387023Sdduvall * 548862387023Sdduvall * This routine schedules a (low-level) softint callback to the 548962387023Sdduvall * factotum, and prods the chip to update the status block (which 549062387023Sdduvall * will cause a hardware interrupt when complete). 549162387023Sdduvall */ 549262387023Sdduvall void bge_chip_cyclic(void *arg); 549362387023Sdduvall #pragma no_inline(bge_chip_cyclic) 549462387023Sdduvall 549562387023Sdduvall void 549662387023Sdduvall bge_chip_cyclic(void *arg) 549762387023Sdduvall { 549862387023Sdduvall bge_t *bgep; 5499087a28d1SDavid Gwynne uint32_t regval; 550062387023Sdduvall 550162387023Sdduvall bgep = arg; 550262387023Sdduvall 550362387023Sdduvall switch (bgep->bge_chip_state) { 550462387023Sdduvall default: 550562387023Sdduvall return; 550662387023Sdduvall 550762387023Sdduvall case BGE_CHIP_RUNNING: 5508087a28d1SDavid Gwynne 5509087a28d1SDavid Gwynne /* XXX I really don't like this forced interrupt... */ 551062387023Sdduvall bge_reg_set32(bgep, HOST_COALESCE_MODE_REG, COALESCE_NOW); 551100d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 551200d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 551300d0963fSdilpreet DDI_SERVICE_UNAFFECTED); 5514dca582a1Sgh162552 551562387023Sdduvall break; 551662387023Sdduvall 551762387023Sdduvall case BGE_CHIP_FAULT: 551862387023Sdduvall case BGE_CHIP_ERROR: 5519087a28d1SDavid Gwynne 552062387023Sdduvall break; 552162387023Sdduvall } 552262387023Sdduvall 5523087a28d1SDavid Gwynne mutex_enter(bgep->genlock); 5524087a28d1SDavid Gwynne 5525087a28d1SDavid Gwynne if (bgep->eee_lpi_wait && !--bgep->eee_lpi_wait) { 5526087a28d1SDavid Gwynne BGE_DEBUG(("eee cyclic, lpi enabled")); 5527087a28d1SDavid Gwynne bge_eee_enable(bgep); 5528087a28d1SDavid Gwynne } 5529087a28d1SDavid Gwynne 5530087a28d1SDavid Gwynne if (bgep->rdma_length_bug_on_5719) { 5531087a28d1SDavid Gwynne if ((bge_reg_get32(bgep, STAT_IFHCOUT_UPKGS_REG) + 5532087a28d1SDavid Gwynne bge_reg_get32(bgep, STAT_IFHCOUT_MPKGS_REG) + 5533087a28d1SDavid Gwynne bge_reg_get32(bgep, STAT_IFHCOUT_BPKGS_REG)) > 5534087a28d1SDavid Gwynne BGE_NUM_RDMA_CHANNELS) { 5535087a28d1SDavid Gwynne regval = bge_reg_get32(bgep, RDMA_CORR_CTRL_REG); 5536087a28d1SDavid Gwynne regval &= ~RDMA_CORR_CTRL_TX_LENGTH_WA; 5537087a28d1SDavid Gwynne bge_reg_put32(bgep, RDMA_CORR_CTRL_REG, regval); 5538087a28d1SDavid Gwynne bgep->rdma_length_bug_on_5719 = B_FALSE; 5539087a28d1SDavid Gwynne } 5540087a28d1SDavid Gwynne } 5541087a28d1SDavid Gwynne 5542087a28d1SDavid Gwynne mutex_exit(bgep->genlock); 5543087a28d1SDavid Gwynne 554462387023Sdduvall bge_wake_factotum(bgep); 5545087a28d1SDavid Gwynne 554662387023Sdduvall } 554762387023Sdduvall 554862387023Sdduvall 554962387023Sdduvall /* 555062387023Sdduvall * ========== Ioctl subfunctions ========== 555162387023Sdduvall */ 555262387023Sdduvall 555362387023Sdduvall #undef BGE_DBG 555462387023Sdduvall #define BGE_DBG BGE_DBG_PPIO /* debug flag for this code */ 555562387023Sdduvall 555662387023Sdduvall #if BGE_DEBUGGING || BGE_DO_PPIO 555762387023Sdduvall 555862387023Sdduvall static void bge_chip_peek_cfg(bge_t *bgep, bge_peekpoke_t *ppd); 555962387023Sdduvall #pragma no_inline(bge_chip_peek_cfg) 556062387023Sdduvall 556162387023Sdduvall static void 556262387023Sdduvall bge_chip_peek_cfg(bge_t *bgep, bge_peekpoke_t *ppd) 556362387023Sdduvall { 556462387023Sdduvall uint64_t regval; 556562387023Sdduvall uint64_t regno; 556662387023Sdduvall 556762387023Sdduvall BGE_TRACE(("bge_chip_peek_cfg($%p, $%p)", 556862387023Sdduvall (void *)bgep, (void *)ppd)); 556962387023Sdduvall 557062387023Sdduvall regno = ppd->pp_acc_offset; 557162387023Sdduvall 557262387023Sdduvall switch (ppd->pp_acc_size) { 557362387023Sdduvall case 1: 557462387023Sdduvall regval = pci_config_get8(bgep->cfg_handle, regno); 557562387023Sdduvall break; 557662387023Sdduvall 557762387023Sdduvall case 2: 557862387023Sdduvall regval = pci_config_get16(bgep->cfg_handle, regno); 557962387023Sdduvall break; 558062387023Sdduvall 558162387023Sdduvall case 4: 558262387023Sdduvall regval = pci_config_get32(bgep->cfg_handle, regno); 558362387023Sdduvall break; 558462387023Sdduvall 558562387023Sdduvall case 8: 558662387023Sdduvall regval = pci_config_get64(bgep->cfg_handle, regno); 558762387023Sdduvall break; 558862387023Sdduvall } 558962387023Sdduvall 559062387023Sdduvall ppd->pp_acc_data = regval; 559162387023Sdduvall } 559262387023Sdduvall 559362387023Sdduvall static void bge_chip_poke_cfg(bge_t *bgep, bge_peekpoke_t *ppd); 559462387023Sdduvall #pragma no_inline(bge_chip_poke_cfg) 559562387023Sdduvall 559662387023Sdduvall static void 559762387023Sdduvall bge_chip_poke_cfg(bge_t *bgep, bge_peekpoke_t *ppd) 559862387023Sdduvall { 559962387023Sdduvall uint64_t regval; 560062387023Sdduvall uint64_t regno; 560162387023Sdduvall 560262387023Sdduvall BGE_TRACE(("bge_chip_poke_cfg($%p, $%p)", 560362387023Sdduvall (void *)bgep, (void *)ppd)); 560462387023Sdduvall 560562387023Sdduvall regno = ppd->pp_acc_offset; 560662387023Sdduvall regval = ppd->pp_acc_data; 560762387023Sdduvall 560862387023Sdduvall switch (ppd->pp_acc_size) { 560962387023Sdduvall case 1: 561062387023Sdduvall pci_config_put8(bgep->cfg_handle, regno, regval); 561162387023Sdduvall break; 561262387023Sdduvall 561362387023Sdduvall case 2: 561462387023Sdduvall pci_config_put16(bgep->cfg_handle, regno, regval); 561562387023Sdduvall break; 561662387023Sdduvall 561762387023Sdduvall case 4: 561862387023Sdduvall pci_config_put32(bgep->cfg_handle, regno, regval); 561962387023Sdduvall break; 562062387023Sdduvall 562162387023Sdduvall case 8: 562262387023Sdduvall pci_config_put64(bgep->cfg_handle, regno, regval); 562362387023Sdduvall break; 562462387023Sdduvall } 562562387023Sdduvall } 562662387023Sdduvall 562762387023Sdduvall static void bge_chip_peek_reg(bge_t *bgep, bge_peekpoke_t *ppd); 562862387023Sdduvall #pragma no_inline(bge_chip_peek_reg) 562962387023Sdduvall 563062387023Sdduvall static void 563162387023Sdduvall bge_chip_peek_reg(bge_t *bgep, bge_peekpoke_t *ppd) 563262387023Sdduvall { 563362387023Sdduvall uint64_t regval; 563462387023Sdduvall void *regaddr; 563562387023Sdduvall 563662387023Sdduvall BGE_TRACE(("bge_chip_peek_reg($%p, $%p)", 563762387023Sdduvall (void *)bgep, (void *)ppd)); 563862387023Sdduvall 563962387023Sdduvall regaddr = PIO_ADDR(bgep, ppd->pp_acc_offset); 564062387023Sdduvall 564162387023Sdduvall switch (ppd->pp_acc_size) { 564262387023Sdduvall case 1: 564362387023Sdduvall regval = ddi_get8(bgep->io_handle, regaddr); 564462387023Sdduvall break; 564562387023Sdduvall 564662387023Sdduvall case 2: 564762387023Sdduvall regval = ddi_get16(bgep->io_handle, regaddr); 564862387023Sdduvall break; 564962387023Sdduvall 565062387023Sdduvall case 4: 565162387023Sdduvall regval = ddi_get32(bgep->io_handle, regaddr); 565262387023Sdduvall break; 565362387023Sdduvall 565462387023Sdduvall case 8: 565562387023Sdduvall regval = ddi_get64(bgep->io_handle, regaddr); 565662387023Sdduvall break; 565762387023Sdduvall } 565862387023Sdduvall 565962387023Sdduvall ppd->pp_acc_data = regval; 566062387023Sdduvall } 566162387023Sdduvall 566262387023Sdduvall static void bge_chip_poke_reg(bge_t *bgep, bge_peekpoke_t *ppd); 566362387023Sdduvall #pragma no_inline(bge_chip_peek_reg) 566462387023Sdduvall 566562387023Sdduvall static void 566662387023Sdduvall bge_chip_poke_reg(bge_t *bgep, bge_peekpoke_t *ppd) 566762387023Sdduvall { 566862387023Sdduvall uint64_t regval; 566962387023Sdduvall void *regaddr; 567062387023Sdduvall 567162387023Sdduvall BGE_TRACE(("bge_chip_poke_reg($%p, $%p)", 567262387023Sdduvall (void *)bgep, (void *)ppd)); 567362387023Sdduvall 567462387023Sdduvall regaddr = PIO_ADDR(bgep, ppd->pp_acc_offset); 567562387023Sdduvall regval = ppd->pp_acc_data; 567662387023Sdduvall 567762387023Sdduvall switch (ppd->pp_acc_size) { 567862387023Sdduvall case 1: 567962387023Sdduvall ddi_put8(bgep->io_handle, regaddr, regval); 568062387023Sdduvall break; 568162387023Sdduvall 568262387023Sdduvall case 2: 568362387023Sdduvall ddi_put16(bgep->io_handle, regaddr, regval); 568462387023Sdduvall break; 568562387023Sdduvall 568662387023Sdduvall case 4: 568762387023Sdduvall ddi_put32(bgep->io_handle, regaddr, regval); 568862387023Sdduvall break; 568962387023Sdduvall 569062387023Sdduvall case 8: 569162387023Sdduvall ddi_put64(bgep->io_handle, regaddr, regval); 569262387023Sdduvall break; 569362387023Sdduvall } 569462387023Sdduvall BGE_PCICHK(bgep); 569562387023Sdduvall } 569662387023Sdduvall 569762387023Sdduvall static void bge_chip_peek_nic(bge_t *bgep, bge_peekpoke_t *ppd); 569862387023Sdduvall #pragma no_inline(bge_chip_peek_nic) 569962387023Sdduvall 570062387023Sdduvall static void 570162387023Sdduvall bge_chip_peek_nic(bge_t *bgep, bge_peekpoke_t *ppd) 570262387023Sdduvall { 570362387023Sdduvall uint64_t regoff; 570462387023Sdduvall uint64_t regval; 570562387023Sdduvall void *regaddr; 570662387023Sdduvall 570762387023Sdduvall BGE_TRACE(("bge_chip_peek_nic($%p, $%p)", 570862387023Sdduvall (void *)bgep, (void *)ppd)); 570962387023Sdduvall 571062387023Sdduvall regoff = ppd->pp_acc_offset; 571162387023Sdduvall bge_nic_setwin(bgep, regoff & ~MWBAR_GRANULE_MASK); 571262387023Sdduvall regoff &= MWBAR_GRANULE_MASK; 571362387023Sdduvall regoff += NIC_MEM_WINDOW_OFFSET; 571462387023Sdduvall regaddr = PIO_ADDR(bgep, regoff); 571562387023Sdduvall 571662387023Sdduvall switch (ppd->pp_acc_size) { 571762387023Sdduvall case 1: 571862387023Sdduvall regval = ddi_get8(bgep->io_handle, regaddr); 571962387023Sdduvall break; 572062387023Sdduvall 572162387023Sdduvall case 2: 572262387023Sdduvall regval = ddi_get16(bgep->io_handle, regaddr); 572362387023Sdduvall break; 572462387023Sdduvall 572562387023Sdduvall case 4: 572662387023Sdduvall regval = ddi_get32(bgep->io_handle, regaddr); 572762387023Sdduvall break; 572862387023Sdduvall 572962387023Sdduvall case 8: 573062387023Sdduvall regval = ddi_get64(bgep->io_handle, regaddr); 573162387023Sdduvall break; 573262387023Sdduvall } 573362387023Sdduvall 573462387023Sdduvall ppd->pp_acc_data = regval; 573562387023Sdduvall } 573662387023Sdduvall 573762387023Sdduvall static void bge_chip_poke_nic(bge_t *bgep, bge_peekpoke_t *ppd); 573862387023Sdduvall #pragma no_inline(bge_chip_poke_nic) 573962387023Sdduvall 574062387023Sdduvall static void 574162387023Sdduvall bge_chip_poke_nic(bge_t *bgep, bge_peekpoke_t *ppd) 574262387023Sdduvall { 574362387023Sdduvall uint64_t regoff; 574462387023Sdduvall uint64_t regval; 574562387023Sdduvall void *regaddr; 574662387023Sdduvall 574762387023Sdduvall BGE_TRACE(("bge_chip_poke_nic($%p, $%p)", 574862387023Sdduvall (void *)bgep, (void *)ppd)); 574962387023Sdduvall 575062387023Sdduvall regoff = ppd->pp_acc_offset; 575162387023Sdduvall bge_nic_setwin(bgep, regoff & ~MWBAR_GRANULE_MASK); 575262387023Sdduvall regoff &= MWBAR_GRANULE_MASK; 575362387023Sdduvall regoff += NIC_MEM_WINDOW_OFFSET; 575462387023Sdduvall regaddr = PIO_ADDR(bgep, regoff); 575562387023Sdduvall regval = ppd->pp_acc_data; 575662387023Sdduvall 575762387023Sdduvall switch (ppd->pp_acc_size) { 575862387023Sdduvall case 1: 575962387023Sdduvall ddi_put8(bgep->io_handle, regaddr, regval); 576062387023Sdduvall break; 576162387023Sdduvall 576262387023Sdduvall case 2: 576362387023Sdduvall ddi_put16(bgep->io_handle, regaddr, regval); 576462387023Sdduvall break; 576562387023Sdduvall 576662387023Sdduvall case 4: 576762387023Sdduvall ddi_put32(bgep->io_handle, regaddr, regval); 576862387023Sdduvall break; 576962387023Sdduvall 577062387023Sdduvall case 8: 577162387023Sdduvall ddi_put64(bgep->io_handle, regaddr, regval); 577262387023Sdduvall break; 577362387023Sdduvall } 577462387023Sdduvall BGE_PCICHK(bgep); 577562387023Sdduvall } 577662387023Sdduvall 577762387023Sdduvall static void bge_chip_peek_mii(bge_t *bgep, bge_peekpoke_t *ppd); 577862387023Sdduvall #pragma no_inline(bge_chip_peek_mii) 577962387023Sdduvall 578062387023Sdduvall static void 578162387023Sdduvall bge_chip_peek_mii(bge_t *bgep, bge_peekpoke_t *ppd) 578262387023Sdduvall { 578362387023Sdduvall BGE_TRACE(("bge_chip_peek_mii($%p, $%p)", 578462387023Sdduvall (void *)bgep, (void *)ppd)); 578562387023Sdduvall 578662387023Sdduvall ppd->pp_acc_data = bge_mii_get16(bgep, ppd->pp_acc_offset/2); 578762387023Sdduvall } 578862387023Sdduvall 578962387023Sdduvall static void bge_chip_poke_mii(bge_t *bgep, bge_peekpoke_t *ppd); 579062387023Sdduvall #pragma no_inline(bge_chip_poke_mii) 579162387023Sdduvall 579262387023Sdduvall static void 579362387023Sdduvall bge_chip_poke_mii(bge_t *bgep, bge_peekpoke_t *ppd) 579462387023Sdduvall { 579562387023Sdduvall BGE_TRACE(("bge_chip_poke_mii($%p, $%p)", 579662387023Sdduvall (void *)bgep, (void *)ppd)); 579762387023Sdduvall 579862387023Sdduvall bge_mii_put16(bgep, ppd->pp_acc_offset/2, ppd->pp_acc_data); 579962387023Sdduvall } 580062387023Sdduvall 580162387023Sdduvall #if BGE_SEE_IO32 580262387023Sdduvall 580362387023Sdduvall static void bge_chip_peek_seeprom(bge_t *bgep, bge_peekpoke_t *ppd); 580462387023Sdduvall #pragma no_inline(bge_chip_peek_seeprom) 580562387023Sdduvall 580662387023Sdduvall static void 580762387023Sdduvall bge_chip_peek_seeprom(bge_t *bgep, bge_peekpoke_t *ppd) 580862387023Sdduvall { 580962387023Sdduvall uint32_t data; 581062387023Sdduvall int err; 581162387023Sdduvall 581262387023Sdduvall BGE_TRACE(("bge_chip_peek_seeprom($%p, $%p)", 581362387023Sdduvall (void *)bgep, (void *)ppd)); 581462387023Sdduvall 581562387023Sdduvall err = bge_nvmem_rw32(bgep, BGE_SEE_READ, ppd->pp_acc_offset, &data); 581662387023Sdduvall ppd->pp_acc_data = err ? ~0ull : data; 581762387023Sdduvall } 581862387023Sdduvall 581962387023Sdduvall static void bge_chip_poke_seeprom(bge_t *bgep, bge_peekpoke_t *ppd); 582062387023Sdduvall #pragma no_inline(bge_chip_poke_seeprom) 582162387023Sdduvall 582262387023Sdduvall static void 582362387023Sdduvall bge_chip_poke_seeprom(bge_t *bgep, bge_peekpoke_t *ppd) 582462387023Sdduvall { 582562387023Sdduvall uint32_t data; 582662387023Sdduvall 582762387023Sdduvall BGE_TRACE(("bge_chip_poke_seeprom($%p, $%p)", 582862387023Sdduvall (void *)bgep, (void *)ppd)); 582962387023Sdduvall 583062387023Sdduvall data = ppd->pp_acc_data; 583162387023Sdduvall (void) bge_nvmem_rw32(bgep, BGE_SEE_WRITE, ppd->pp_acc_offset, &data); 583262387023Sdduvall } 583362387023Sdduvall #endif /* BGE_SEE_IO32 */ 583462387023Sdduvall 583562387023Sdduvall #if BGE_FLASH_IO32 583662387023Sdduvall 583762387023Sdduvall static void bge_chip_peek_flash(bge_t *bgep, bge_peekpoke_t *ppd); 583862387023Sdduvall #pragma no_inline(bge_chip_peek_flash) 583962387023Sdduvall 584062387023Sdduvall static void 584162387023Sdduvall bge_chip_peek_flash(bge_t *bgep, bge_peekpoke_t *ppd) 584262387023Sdduvall { 584362387023Sdduvall uint32_t data; 584462387023Sdduvall int err; 584562387023Sdduvall 584662387023Sdduvall BGE_TRACE(("bge_chip_peek_flash($%p, $%p)", 584762387023Sdduvall (void *)bgep, (void *)ppd)); 584862387023Sdduvall 584962387023Sdduvall err = bge_nvmem_rw32(bgep, BGE_FLASH_READ, ppd->pp_acc_offset, &data); 585062387023Sdduvall ppd->pp_acc_data = err ? ~0ull : data; 585162387023Sdduvall } 585262387023Sdduvall 585362387023Sdduvall static void bge_chip_poke_flash(bge_t *bgep, bge_peekpoke_t *ppd); 585462387023Sdduvall #pragma no_inline(bge_chip_poke_flash) 585562387023Sdduvall 585662387023Sdduvall static void 585762387023Sdduvall bge_chip_poke_flash(bge_t *bgep, bge_peekpoke_t *ppd) 585862387023Sdduvall { 585962387023Sdduvall uint32_t data; 586062387023Sdduvall 586162387023Sdduvall BGE_TRACE(("bge_chip_poke_flash($%p, $%p)", 586262387023Sdduvall (void *)bgep, (void *)ppd)); 586362387023Sdduvall 586462387023Sdduvall data = ppd->pp_acc_data; 586562387023Sdduvall (void) bge_nvmem_rw32(bgep, BGE_FLASH_WRITE, 586662387023Sdduvall ppd->pp_acc_offset, &data); 586762387023Sdduvall } 586862387023Sdduvall #endif /* BGE_FLASH_IO32 */ 586962387023Sdduvall 587062387023Sdduvall static void bge_chip_peek_mem(bge_t *bgep, bge_peekpoke_t *ppd); 587162387023Sdduvall #pragma no_inline(bge_chip_peek_mem) 587262387023Sdduvall 587362387023Sdduvall static void 587462387023Sdduvall bge_chip_peek_mem(bge_t *bgep, bge_peekpoke_t *ppd) 587562387023Sdduvall { 587662387023Sdduvall uint64_t regval; 587762387023Sdduvall void *vaddr; 587862387023Sdduvall 587962387023Sdduvall BGE_TRACE(("bge_chip_peek_bge($%p, $%p)", 588062387023Sdduvall (void *)bgep, (void *)ppd)); 588162387023Sdduvall 588262387023Sdduvall vaddr = (void *)(uintptr_t)ppd->pp_acc_offset; 588362387023Sdduvall 588462387023Sdduvall switch (ppd->pp_acc_size) { 588562387023Sdduvall case 1: 588662387023Sdduvall regval = *(uint8_t *)vaddr; 588762387023Sdduvall break; 588862387023Sdduvall 588962387023Sdduvall case 2: 589062387023Sdduvall regval = *(uint16_t *)vaddr; 589162387023Sdduvall break; 589262387023Sdduvall 589362387023Sdduvall case 4: 589462387023Sdduvall regval = *(uint32_t *)vaddr; 589562387023Sdduvall break; 589662387023Sdduvall 589762387023Sdduvall case 8: 589862387023Sdduvall regval = *(uint64_t *)vaddr; 589962387023Sdduvall break; 590062387023Sdduvall } 590162387023Sdduvall 590262387023Sdduvall BGE_DEBUG(("bge_chip_peek_mem($%p, $%p) peeked 0x%llx from $%p", 590362387023Sdduvall (void *)bgep, (void *)ppd, regval, vaddr)); 590462387023Sdduvall 590562387023Sdduvall ppd->pp_acc_data = regval; 590662387023Sdduvall } 590762387023Sdduvall 590862387023Sdduvall static void bge_chip_poke_mem(bge_t *bgep, bge_peekpoke_t *ppd); 590962387023Sdduvall #pragma no_inline(bge_chip_poke_mem) 591062387023Sdduvall 591162387023Sdduvall static void 591262387023Sdduvall bge_chip_poke_mem(bge_t *bgep, bge_peekpoke_t *ppd) 591362387023Sdduvall { 591462387023Sdduvall uint64_t regval; 591562387023Sdduvall void *vaddr; 591662387023Sdduvall 591762387023Sdduvall BGE_TRACE(("bge_chip_poke_mem($%p, $%p)", 591862387023Sdduvall (void *)bgep, (void *)ppd)); 591962387023Sdduvall 592062387023Sdduvall vaddr = (void *)(uintptr_t)ppd->pp_acc_offset; 592162387023Sdduvall regval = ppd->pp_acc_data; 592262387023Sdduvall 592362387023Sdduvall BGE_DEBUG(("bge_chip_poke_mem($%p, $%p) poking 0x%llx at $%p", 592462387023Sdduvall (void *)bgep, (void *)ppd, regval, vaddr)); 592562387023Sdduvall 592662387023Sdduvall switch (ppd->pp_acc_size) { 592762387023Sdduvall case 1: 592862387023Sdduvall *(uint8_t *)vaddr = (uint8_t)regval; 592962387023Sdduvall break; 593062387023Sdduvall 593162387023Sdduvall case 2: 593262387023Sdduvall *(uint16_t *)vaddr = (uint16_t)regval; 593362387023Sdduvall break; 593462387023Sdduvall 593562387023Sdduvall case 4: 593662387023Sdduvall *(uint32_t *)vaddr = (uint32_t)regval; 593762387023Sdduvall break; 593862387023Sdduvall 593962387023Sdduvall case 8: 594062387023Sdduvall *(uint64_t *)vaddr = (uint64_t)regval; 594162387023Sdduvall break; 594262387023Sdduvall } 594362387023Sdduvall } 594462387023Sdduvall 594562387023Sdduvall static enum ioc_reply bge_pp_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 594662387023Sdduvall struct iocblk *iocp); 594762387023Sdduvall #pragma no_inline(bge_pp_ioctl) 594862387023Sdduvall 594962387023Sdduvall static enum ioc_reply 595062387023Sdduvall bge_pp_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 595162387023Sdduvall { 595262387023Sdduvall void (*ppfn)(bge_t *bgep, bge_peekpoke_t *ppd); 595362387023Sdduvall bge_peekpoke_t *ppd; 595462387023Sdduvall dma_area_t *areap; 595562387023Sdduvall uint64_t sizemask; 595662387023Sdduvall uint64_t mem_va; 595762387023Sdduvall uint64_t maxoff; 595862387023Sdduvall boolean_t peek; 595962387023Sdduvall 596062387023Sdduvall switch (cmd) { 596162387023Sdduvall default: 596262387023Sdduvall /* NOTREACHED */ 596362387023Sdduvall bge_error(bgep, "bge_pp_ioctl: invalid cmd 0x%x", cmd); 596462387023Sdduvall return (IOC_INVAL); 596562387023Sdduvall 596662387023Sdduvall case BGE_PEEK: 596762387023Sdduvall peek = B_TRUE; 596862387023Sdduvall break; 596962387023Sdduvall 597062387023Sdduvall case BGE_POKE: 597162387023Sdduvall peek = B_FALSE; 597262387023Sdduvall break; 597362387023Sdduvall } 597462387023Sdduvall 597562387023Sdduvall /* 597662387023Sdduvall * Validate format of ioctl 597762387023Sdduvall */ 597862387023Sdduvall if (iocp->ioc_count != sizeof (bge_peekpoke_t)) 597962387023Sdduvall return (IOC_INVAL); 598062387023Sdduvall if (mp->b_cont == NULL) 598162387023Sdduvall return (IOC_INVAL); 59824a06b59fSyt223700 ppd = (void *)mp->b_cont->b_rptr; 598362387023Sdduvall 598462387023Sdduvall /* 598562387023Sdduvall * Validate request parameters 598662387023Sdduvall */ 598762387023Sdduvall switch (ppd->pp_acc_space) { 598862387023Sdduvall default: 598962387023Sdduvall return (IOC_INVAL); 599062387023Sdduvall 599162387023Sdduvall case BGE_PP_SPACE_CFG: 599262387023Sdduvall /* 599362387023Sdduvall * Config space 599462387023Sdduvall */ 599562387023Sdduvall sizemask = 8|4|2|1; 599662387023Sdduvall mem_va = 0; 599762387023Sdduvall maxoff = PCI_CONF_HDR_SIZE; 599862387023Sdduvall ppfn = peek ? bge_chip_peek_cfg : bge_chip_poke_cfg; 599962387023Sdduvall break; 600062387023Sdduvall 600162387023Sdduvall case BGE_PP_SPACE_REG: 600262387023Sdduvall /* 600362387023Sdduvall * Memory-mapped I/O space 600462387023Sdduvall */ 600562387023Sdduvall sizemask = 8|4|2|1; 600662387023Sdduvall mem_va = 0; 600762387023Sdduvall maxoff = RIAAR_REGISTER_MAX; 600862387023Sdduvall ppfn = peek ? bge_chip_peek_reg : bge_chip_poke_reg; 600962387023Sdduvall break; 601062387023Sdduvall 601162387023Sdduvall case BGE_PP_SPACE_NIC: 601262387023Sdduvall /* 601362387023Sdduvall * NIC on-chip memory 601462387023Sdduvall */ 601562387023Sdduvall sizemask = 8|4|2|1; 601662387023Sdduvall mem_va = 0; 601762387023Sdduvall maxoff = MWBAR_ONCHIP_MAX; 601862387023Sdduvall ppfn = peek ? bge_chip_peek_nic : bge_chip_poke_nic; 601962387023Sdduvall break; 602062387023Sdduvall 602162387023Sdduvall case BGE_PP_SPACE_MII: 602262387023Sdduvall /* 602362387023Sdduvall * PHY's MII registers 602462387023Sdduvall * NB: all PHY registers are two bytes, but the 602562387023Sdduvall * addresses increment in ones (word addressing). 602662387023Sdduvall * So we scale the address here, then undo the 602762387023Sdduvall * transformation inside the peek/poke functions. 602862387023Sdduvall */ 602962387023Sdduvall ppd->pp_acc_offset *= 2; 603062387023Sdduvall sizemask = 2; 603162387023Sdduvall mem_va = 0; 603262387023Sdduvall maxoff = (MII_MAXREG+1)*2; 603362387023Sdduvall ppfn = peek ? bge_chip_peek_mii : bge_chip_poke_mii; 603462387023Sdduvall break; 603562387023Sdduvall 603662387023Sdduvall #if BGE_SEE_IO32 603762387023Sdduvall case BGE_PP_SPACE_SEEPROM: 603862387023Sdduvall /* 603962387023Sdduvall * Attached SEEPROM(s), if any. 604062387023Sdduvall * NB: we use the high-order bits of the 'address' as 604162387023Sdduvall * a device select to accommodate multiple SEEPROMS, 604262387023Sdduvall * If each one is the maximum size (64kbytes), this 604362387023Sdduvall * makes them appear contiguous. Otherwise, there may 604462387023Sdduvall * be holes in the mapping. ENxS doesn't have any 604562387023Sdduvall * SEEPROMs anyway ... 604662387023Sdduvall */ 604762387023Sdduvall sizemask = 4; 604862387023Sdduvall mem_va = 0; 604962387023Sdduvall maxoff = SEEPROM_DEV_AND_ADDR_MASK; 605062387023Sdduvall ppfn = peek ? bge_chip_peek_seeprom : bge_chip_poke_seeprom; 605162387023Sdduvall break; 605262387023Sdduvall #endif /* BGE_SEE_IO32 */ 605362387023Sdduvall 605462387023Sdduvall #if BGE_FLASH_IO32 605562387023Sdduvall case BGE_PP_SPACE_FLASH: 605662387023Sdduvall /* 605762387023Sdduvall * Attached Flash device (if any); a maximum of one device 605862387023Sdduvall * is currently supported. But it can be up to 1MB (unlike 605962387023Sdduvall * the 64k limit on SEEPROMs) so why would you need more ;-) 606062387023Sdduvall */ 606162387023Sdduvall sizemask = 4; 606262387023Sdduvall mem_va = 0; 606362387023Sdduvall maxoff = NVM_FLASH_ADDR_MASK; 606462387023Sdduvall ppfn = peek ? bge_chip_peek_flash : bge_chip_poke_flash; 606562387023Sdduvall break; 606662387023Sdduvall #endif /* BGE_FLASH_IO32 */ 606762387023Sdduvall 606862387023Sdduvall case BGE_PP_SPACE_BGE: 606962387023Sdduvall /* 607062387023Sdduvall * BGE data structure! 607162387023Sdduvall */ 607262387023Sdduvall sizemask = 8|4|2|1; 607362387023Sdduvall mem_va = (uintptr_t)bgep; 607462387023Sdduvall maxoff = sizeof (*bgep); 607562387023Sdduvall ppfn = peek ? bge_chip_peek_mem : bge_chip_poke_mem; 607662387023Sdduvall break; 607762387023Sdduvall 607862387023Sdduvall case BGE_PP_SPACE_STATUS: 607962387023Sdduvall case BGE_PP_SPACE_STATISTICS: 608062387023Sdduvall case BGE_PP_SPACE_TXDESC: 608162387023Sdduvall case BGE_PP_SPACE_TXBUFF: 608262387023Sdduvall case BGE_PP_SPACE_RXDESC: 608362387023Sdduvall case BGE_PP_SPACE_RXBUFF: 608462387023Sdduvall /* 608562387023Sdduvall * Various DMA_AREAs 608662387023Sdduvall */ 608762387023Sdduvall switch (ppd->pp_acc_space) { 608862387023Sdduvall case BGE_PP_SPACE_TXDESC: 608962387023Sdduvall areap = &bgep->tx_desc; 609062387023Sdduvall break; 609162387023Sdduvall case BGE_PP_SPACE_TXBUFF: 609262387023Sdduvall areap = &bgep->tx_buff[0]; 609362387023Sdduvall break; 609462387023Sdduvall case BGE_PP_SPACE_RXDESC: 609562387023Sdduvall areap = &bgep->rx_desc[0]; 609662387023Sdduvall break; 609762387023Sdduvall case BGE_PP_SPACE_RXBUFF: 609862387023Sdduvall areap = &bgep->rx_buff[0]; 609962387023Sdduvall break; 610062387023Sdduvall case BGE_PP_SPACE_STATUS: 610162387023Sdduvall areap = &bgep->status_block; 610262387023Sdduvall break; 610362387023Sdduvall case BGE_PP_SPACE_STATISTICS: 610462387023Sdduvall if (bgep->chipid.statistic_type == BGE_STAT_BLK) 610562387023Sdduvall areap = &bgep->statistics; 610662387023Sdduvall break; 610762387023Sdduvall } 610862387023Sdduvall 610962387023Sdduvall sizemask = 8|4|2|1; 611062387023Sdduvall mem_va = (uintptr_t)areap->mem_va; 611162387023Sdduvall maxoff = areap->alength; 611262387023Sdduvall ppfn = peek ? bge_chip_peek_mem : bge_chip_poke_mem; 611362387023Sdduvall break; 611462387023Sdduvall } 611562387023Sdduvall 611662387023Sdduvall switch (ppd->pp_acc_size) { 611762387023Sdduvall default: 611862387023Sdduvall return (IOC_INVAL); 611962387023Sdduvall 612062387023Sdduvall case 8: 612162387023Sdduvall case 4: 612262387023Sdduvall case 2: 612362387023Sdduvall case 1: 612462387023Sdduvall if ((ppd->pp_acc_size & sizemask) == 0) 612562387023Sdduvall return (IOC_INVAL); 612662387023Sdduvall break; 612762387023Sdduvall } 612862387023Sdduvall 612962387023Sdduvall if ((ppd->pp_acc_offset % ppd->pp_acc_size) != 0) 613062387023Sdduvall return (IOC_INVAL); 613162387023Sdduvall 613262387023Sdduvall if (ppd->pp_acc_offset >= maxoff) 613362387023Sdduvall return (IOC_INVAL); 613462387023Sdduvall 613562387023Sdduvall if (ppd->pp_acc_offset+ppd->pp_acc_size > maxoff) 613662387023Sdduvall return (IOC_INVAL); 613762387023Sdduvall 613862387023Sdduvall /* 613962387023Sdduvall * All OK - go do it! 614062387023Sdduvall */ 614162387023Sdduvall ppd->pp_acc_offset += mem_va; 614262387023Sdduvall (*ppfn)(bgep, ppd); 614362387023Sdduvall return (peek ? IOC_REPLY : IOC_ACK); 614462387023Sdduvall } 614562387023Sdduvall 614662387023Sdduvall static enum ioc_reply bge_diag_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 614762387023Sdduvall struct iocblk *iocp); 614862387023Sdduvall #pragma no_inline(bge_diag_ioctl) 614962387023Sdduvall 615062387023Sdduvall static enum ioc_reply 615162387023Sdduvall bge_diag_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 615262387023Sdduvall { 615362387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 615462387023Sdduvall 615562387023Sdduvall switch (cmd) { 615662387023Sdduvall default: 615762387023Sdduvall /* NOTREACHED */ 615862387023Sdduvall bge_error(bgep, "bge_diag_ioctl: invalid cmd 0x%x", cmd); 615962387023Sdduvall return (IOC_INVAL); 616062387023Sdduvall 616162387023Sdduvall case BGE_DIAG: 616262387023Sdduvall /* 616362387023Sdduvall * Currently a no-op 616462387023Sdduvall */ 616562387023Sdduvall return (IOC_ACK); 616662387023Sdduvall 616762387023Sdduvall case BGE_PEEK: 616862387023Sdduvall case BGE_POKE: 616962387023Sdduvall return (bge_pp_ioctl(bgep, cmd, mp, iocp)); 617062387023Sdduvall 617162387023Sdduvall case BGE_PHY_RESET: 617262387023Sdduvall return (IOC_RESTART_ACK); 617362387023Sdduvall 617462387023Sdduvall case BGE_SOFT_RESET: 617562387023Sdduvall case BGE_HARD_RESET: 617662387023Sdduvall /* 617762387023Sdduvall * Reset and reinitialise the 570x hardware 617862387023Sdduvall */ 6179a4de4ba2Sml149210 bgep->bge_chip_state = BGE_CHIP_FAULT; 6180a4de4ba2Sml149210 ddi_trigger_softintr(bgep->factotum_id); 618100d0963fSdilpreet (void) bge_restart(bgep, cmd == BGE_HARD_RESET); 618262387023Sdduvall return (IOC_ACK); 618362387023Sdduvall } 618462387023Sdduvall 618562387023Sdduvall /* NOTREACHED */ 618662387023Sdduvall } 618762387023Sdduvall 618862387023Sdduvall #endif /* BGE_DEBUGGING || BGE_DO_PPIO */ 618962387023Sdduvall 619062387023Sdduvall static enum ioc_reply bge_mii_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 619162387023Sdduvall struct iocblk *iocp); 619262387023Sdduvall #pragma no_inline(bge_mii_ioctl) 619362387023Sdduvall 619462387023Sdduvall static enum ioc_reply 619562387023Sdduvall bge_mii_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 619662387023Sdduvall { 619762387023Sdduvall struct bge_mii_rw *miirwp; 619862387023Sdduvall 619962387023Sdduvall /* 620062387023Sdduvall * Validate format of ioctl 620162387023Sdduvall */ 620262387023Sdduvall if (iocp->ioc_count != sizeof (struct bge_mii_rw)) 620362387023Sdduvall return (IOC_INVAL); 620462387023Sdduvall if (mp->b_cont == NULL) 620562387023Sdduvall return (IOC_INVAL); 62064a06b59fSyt223700 miirwp = (void *)mp->b_cont->b_rptr; 620762387023Sdduvall 620862387023Sdduvall /* 620962387023Sdduvall * Validate request parameters ... 621062387023Sdduvall */ 621162387023Sdduvall if (miirwp->mii_reg > MII_MAXREG) 621262387023Sdduvall return (IOC_INVAL); 621362387023Sdduvall 621462387023Sdduvall switch (cmd) { 621562387023Sdduvall default: 621662387023Sdduvall /* NOTREACHED */ 621762387023Sdduvall bge_error(bgep, "bge_mii_ioctl: invalid cmd 0x%x", cmd); 621862387023Sdduvall return (IOC_INVAL); 621962387023Sdduvall 622062387023Sdduvall case BGE_MII_READ: 622162387023Sdduvall miirwp->mii_data = bge_mii_get16(bgep, miirwp->mii_reg); 622262387023Sdduvall return (IOC_REPLY); 622362387023Sdduvall 622462387023Sdduvall case BGE_MII_WRITE: 622562387023Sdduvall bge_mii_put16(bgep, miirwp->mii_reg, miirwp->mii_data); 622662387023Sdduvall return (IOC_ACK); 622762387023Sdduvall } 622862387023Sdduvall 622962387023Sdduvall /* NOTREACHED */ 623062387023Sdduvall } 623162387023Sdduvall 623262387023Sdduvall #if BGE_SEE_IO32 623362387023Sdduvall 623462387023Sdduvall static enum ioc_reply bge_see_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 623562387023Sdduvall struct iocblk *iocp); 623662387023Sdduvall #pragma no_inline(bge_see_ioctl) 623762387023Sdduvall 623862387023Sdduvall static enum ioc_reply 623962387023Sdduvall bge_see_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 624062387023Sdduvall { 624162387023Sdduvall struct bge_see_rw *seerwp; 624262387023Sdduvall 624362387023Sdduvall /* 624462387023Sdduvall * Validate format of ioctl 624562387023Sdduvall */ 624662387023Sdduvall if (iocp->ioc_count != sizeof (struct bge_see_rw)) 624762387023Sdduvall return (IOC_INVAL); 624862387023Sdduvall if (mp->b_cont == NULL) 624962387023Sdduvall return (IOC_INVAL); 62504a06b59fSyt223700 seerwp = (void *)mp->b_cont->b_rptr; 625162387023Sdduvall 625262387023Sdduvall /* 625362387023Sdduvall * Validate request parameters ... 625462387023Sdduvall */ 625562387023Sdduvall if (seerwp->see_addr & ~SEEPROM_DEV_AND_ADDR_MASK) 625662387023Sdduvall return (IOC_INVAL); 625762387023Sdduvall 625862387023Sdduvall switch (cmd) { 625962387023Sdduvall default: 626062387023Sdduvall /* NOTREACHED */ 626162387023Sdduvall bge_error(bgep, "bge_see_ioctl: invalid cmd 0x%x", cmd); 626262387023Sdduvall return (IOC_INVAL); 626362387023Sdduvall 626462387023Sdduvall case BGE_SEE_READ: 626562387023Sdduvall case BGE_SEE_WRITE: 626662387023Sdduvall iocp->ioc_error = bge_nvmem_rw32(bgep, cmd, 626762387023Sdduvall seerwp->see_addr, &seerwp->see_data); 626862387023Sdduvall return (IOC_REPLY); 626962387023Sdduvall } 627062387023Sdduvall 627162387023Sdduvall /* NOTREACHED */ 627262387023Sdduvall } 627362387023Sdduvall 627462387023Sdduvall #endif /* BGE_SEE_IO32 */ 627562387023Sdduvall 627662387023Sdduvall #if BGE_FLASH_IO32 627762387023Sdduvall 627862387023Sdduvall static enum ioc_reply bge_flash_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 627962387023Sdduvall struct iocblk *iocp); 628062387023Sdduvall #pragma no_inline(bge_flash_ioctl) 628162387023Sdduvall 628262387023Sdduvall static enum ioc_reply 628362387023Sdduvall bge_flash_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 628462387023Sdduvall { 628562387023Sdduvall struct bge_flash_rw *flashrwp; 628662387023Sdduvall 628762387023Sdduvall /* 628862387023Sdduvall * Validate format of ioctl 628962387023Sdduvall */ 629062387023Sdduvall if (iocp->ioc_count != sizeof (struct bge_flash_rw)) 629162387023Sdduvall return (IOC_INVAL); 629262387023Sdduvall if (mp->b_cont == NULL) 629362387023Sdduvall return (IOC_INVAL); 62944a06b59fSyt223700 flashrwp = (void *)mp->b_cont->b_rptr; 629562387023Sdduvall 629662387023Sdduvall /* 629762387023Sdduvall * Validate request parameters ... 629862387023Sdduvall */ 629962387023Sdduvall if (flashrwp->flash_addr & ~NVM_FLASH_ADDR_MASK) 630062387023Sdduvall return (IOC_INVAL); 630162387023Sdduvall 630262387023Sdduvall switch (cmd) { 630362387023Sdduvall default: 630462387023Sdduvall /* NOTREACHED */ 630562387023Sdduvall bge_error(bgep, "bge_flash_ioctl: invalid cmd 0x%x", cmd); 630662387023Sdduvall return (IOC_INVAL); 630762387023Sdduvall 630862387023Sdduvall case BGE_FLASH_READ: 630962387023Sdduvall case BGE_FLASH_WRITE: 631062387023Sdduvall iocp->ioc_error = bge_nvmem_rw32(bgep, cmd, 631162387023Sdduvall flashrwp->flash_addr, &flashrwp->flash_data); 631262387023Sdduvall return (IOC_REPLY); 631362387023Sdduvall } 631462387023Sdduvall 631562387023Sdduvall /* NOTREACHED */ 631662387023Sdduvall } 631762387023Sdduvall 631862387023Sdduvall #endif /* BGE_FLASH_IO32 */ 631962387023Sdduvall 632062387023Sdduvall enum ioc_reply bge_chip_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, 632162387023Sdduvall struct iocblk *iocp); 632262387023Sdduvall #pragma no_inline(bge_chip_ioctl) 632362387023Sdduvall 632462387023Sdduvall enum ioc_reply 632562387023Sdduvall bge_chip_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 632662387023Sdduvall { 632762387023Sdduvall int cmd; 632862387023Sdduvall 632962387023Sdduvall BGE_TRACE(("bge_chip_ioctl($%p, $%p, $%p, $%p)", 633062387023Sdduvall (void *)bgep, (void *)wq, (void *)mp, (void *)iocp)); 633162387023Sdduvall 633262387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 633362387023Sdduvall 633462387023Sdduvall cmd = iocp->ioc_cmd; 633562387023Sdduvall switch (cmd) { 633662387023Sdduvall default: 633762387023Sdduvall /* NOTREACHED */ 633862387023Sdduvall bge_error(bgep, "bge_chip_ioctl: invalid cmd 0x%x", cmd); 633962387023Sdduvall return (IOC_INVAL); 634062387023Sdduvall 634162387023Sdduvall case BGE_DIAG: 634262387023Sdduvall case BGE_PEEK: 634362387023Sdduvall case BGE_POKE: 634462387023Sdduvall case BGE_PHY_RESET: 634562387023Sdduvall case BGE_SOFT_RESET: 634662387023Sdduvall case BGE_HARD_RESET: 634762387023Sdduvall #if BGE_DEBUGGING || BGE_DO_PPIO 634862387023Sdduvall return (bge_diag_ioctl(bgep, cmd, mp, iocp)); 634962387023Sdduvall #else 635062387023Sdduvall return (IOC_INVAL); 635162387023Sdduvall #endif /* BGE_DEBUGGING || BGE_DO_PPIO */ 635262387023Sdduvall 635362387023Sdduvall case BGE_MII_READ: 635462387023Sdduvall case BGE_MII_WRITE: 635562387023Sdduvall return (bge_mii_ioctl(bgep, cmd, mp, iocp)); 635662387023Sdduvall 635762387023Sdduvall #if BGE_SEE_IO32 635862387023Sdduvall case BGE_SEE_READ: 635962387023Sdduvall case BGE_SEE_WRITE: 636062387023Sdduvall return (bge_see_ioctl(bgep, cmd, mp, iocp)); 636162387023Sdduvall #endif /* BGE_SEE_IO32 */ 636262387023Sdduvall 636362387023Sdduvall #if BGE_FLASH_IO32 636462387023Sdduvall case BGE_FLASH_READ: 636562387023Sdduvall case BGE_FLASH_WRITE: 636662387023Sdduvall return (bge_flash_ioctl(bgep, cmd, mp, iocp)); 636762387023Sdduvall #endif /* BGE_FLASH_IO32 */ 636862387023Sdduvall } 636962387023Sdduvall 637062387023Sdduvall /* NOTREACHED */ 637162387023Sdduvall } 637262387023Sdduvall 6373da14cebeSEric Cheng /* ARGSUSED */ 637462387023Sdduvall void 6375da14cebeSEric Cheng bge_chip_blank(void *arg, time_t ticks, uint_t count, int flag) 637662387023Sdduvall { 6377da14cebeSEric Cheng recv_ring_t *rrp = arg; 6378da14cebeSEric Cheng bge_t *bgep = rrp->bgep; 637962387023Sdduvall 638000d0963fSdilpreet mutex_enter(bgep->genlock); 6381da14cebeSEric Cheng rrp->poll_flag = flag; 6382da14cebeSEric Cheng #ifdef NOT_YET 6383da14cebeSEric Cheng /* 6384da14cebeSEric Cheng * XXX-Sunay: Since most broadcom cards support only one 6385da14cebeSEric Cheng * interrupt but multiple rx rings, we can't disable the 6386da14cebeSEric Cheng * physical interrupt. This need to be done via capability 6387da14cebeSEric Cheng * negotiation depending on the NIC. 6388da14cebeSEric Cheng */ 638962387023Sdduvall bge_reg_put32(bgep, RCV_COALESCE_TICKS_REG, ticks); 639062387023Sdduvall bge_reg_put32(bgep, RCV_COALESCE_MAX_BD_REG, count); 6391da14cebeSEric Cheng #endif 639200d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 639300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 639400d0963fSdilpreet mutex_exit(bgep->genlock); 639562387023Sdduvall } 639667f02347Srandyf 639767f02347Srandyf #ifdef BGE_IPMI_ASF 639867f02347Srandyf 639967f02347Srandyf uint32_t 640067f02347Srandyf bge_nic_read32(bge_t *bgep, bge_regno_t addr) 640167f02347Srandyf { 640267f02347Srandyf uint32_t data; 640367f02347Srandyf 6404a4de4ba2Sml149210 #ifndef __sparc 640567f02347Srandyf if (!bgep->asf_wordswapped) { 640667f02347Srandyf /* a workaround word swap error */ 640767f02347Srandyf if (addr & 4) 640867f02347Srandyf addr = addr - 4; 640967f02347Srandyf else 641067f02347Srandyf addr = addr + 4; 641167f02347Srandyf } 6412dc3f9a75Syong tan - Sun Microsystems - Beijing China #else 6413087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 6414087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 6415dc3f9a75Syong tan - Sun Microsystems - Beijing China addr = LE_32(addr); 6416087a28d1SDavid Gwynne } 6417a4de4ba2Sml149210 #endif 641867f02347Srandyf 641967f02347Srandyf pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, addr); 642067f02347Srandyf data = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MWDAR); 642167f02347Srandyf pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, 0); 642267f02347Srandyf 6423a4de4ba2Sml149210 data = LE_32(data); 6424dc3f9a75Syong tan - Sun Microsystems - Beijing China 6425dc3f9a75Syong tan - Sun Microsystems - Beijing China BGE_DEBUG(("bge_nic_read32($%p, 0x%x) => 0x%x", 6426dc3f9a75Syong tan - Sun Microsystems - Beijing China (void *)bgep, addr, data)); 6427dc3f9a75Syong tan - Sun Microsystems - Beijing China 642867f02347Srandyf return (data); 642967f02347Srandyf } 643067f02347Srandyf 643167f02347Srandyf void 643267f02347Srandyf bge_asf_update_status(bge_t *bgep) 643367f02347Srandyf { 643467f02347Srandyf uint32_t event; 643567f02347Srandyf 643667f02347Srandyf bge_nic_put32(bgep, BGE_CMD_MAILBOX, BGE_CMD_NICDRV_ALIVE); 643767f02347Srandyf bge_nic_put32(bgep, BGE_CMD_LENGTH_MAILBOX, 4); 643867f02347Srandyf bge_nic_put32(bgep, BGE_CMD_DATA_MAILBOX, 3); 643967f02347Srandyf 644067f02347Srandyf event = bge_reg_get32(bgep, RX_RISC_EVENT_REG); 644167f02347Srandyf bge_reg_put32(bgep, RX_RISC_EVENT_REG, event | RRER_ASF_EVENT); 644267f02347Srandyf } 644367f02347Srandyf 644467f02347Srandyf 644567f02347Srandyf /* 644667f02347Srandyf * The driver is supposed to notify ASF that the OS is still running 644767f02347Srandyf * every three seconds, otherwise the management server may attempt 644867f02347Srandyf * to reboot the machine. If it hasn't actually failed, this is 6449256e438eSzh199473 * not a desirable result. However, this isn't running as a real-time 645067f02347Srandyf * thread, and even if it were, it might not be able to generate the 645167f02347Srandyf * heartbeat in a timely manner due to system load. As it isn't a 645267f02347Srandyf * significant strain on the machine, we will set the interval to half 645367f02347Srandyf * of the required value. 645467f02347Srandyf */ 645567f02347Srandyf void 645600d0963fSdilpreet bge_asf_heartbeat(void *arg) 645767f02347Srandyf { 645800d0963fSdilpreet bge_t *bgep = (bge_t *)arg; 645900d0963fSdilpreet 646000d0963fSdilpreet mutex_enter(bgep->genlock); 646167f02347Srandyf bge_asf_update_status((bge_t *)bgep); 646200d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 646300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 646400d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 646500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 646600d0963fSdilpreet mutex_exit(bgep->genlock); 646767f02347Srandyf ((bge_t *)bgep)->asf_timeout_id = timeout(bge_asf_heartbeat, bgep, 646867f02347Srandyf drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 646967f02347Srandyf } 647067f02347Srandyf 647167f02347Srandyf 647267f02347Srandyf void 647367f02347Srandyf bge_asf_stop_timer(bge_t *bgep) 647467f02347Srandyf { 647567f02347Srandyf timeout_id_t tmp_id = 0; 647667f02347Srandyf 647767f02347Srandyf while ((bgep->asf_timeout_id != 0) && 647867f02347Srandyf (tmp_id != bgep->asf_timeout_id)) { 647967f02347Srandyf tmp_id = bgep->asf_timeout_id; 648067f02347Srandyf (void) untimeout(tmp_id); 648167f02347Srandyf } 648267f02347Srandyf bgep->asf_timeout_id = 0; 648367f02347Srandyf } 648467f02347Srandyf 648567f02347Srandyf 648667f02347Srandyf 648767f02347Srandyf /* 6488256e438eSzh199473 * This function should be placed at the earliest position of bge_attach(). 648967f02347Srandyf */ 649067f02347Srandyf void 649167f02347Srandyf bge_asf_get_config(bge_t *bgep) 649267f02347Srandyf { 649367f02347Srandyf uint32_t nicsig; 649467f02347Srandyf uint32_t niccfg; 649567f02347Srandyf 6496a4de4ba2Sml149210 bgep->asf_enabled = B_FALSE; 6497*76a3936eSHans Rosenfeld 6498*76a3936eSHans Rosenfeld /* No ASF if APE present. */ 6499*76a3936eSHans Rosenfeld if (bgep->ape_enabled) 6500*76a3936eSHans Rosenfeld return; 6501*76a3936eSHans Rosenfeld 650267f02347Srandyf nicsig = bge_nic_read32(bgep, BGE_NIC_DATA_SIG_ADDR); 650367f02347Srandyf if (nicsig == BGE_NIC_DATA_SIG) { 650467f02347Srandyf niccfg = bge_nic_read32(bgep, BGE_NIC_DATA_NIC_CFG_ADDR); 650567f02347Srandyf if (niccfg & BGE_NIC_CFG_ENABLE_ASF) 650667f02347Srandyf /* 650767f02347Srandyf * Here, we don't consider BAXTER, because BGE haven't 650867f02347Srandyf * supported BAXTER (that is 5752). Also, as I know, 650967f02347Srandyf * BAXTER doesn't support ASF feature. 651067f02347Srandyf */ 651167f02347Srandyf bgep->asf_enabled = B_TRUE; 651267f02347Srandyf else 651367f02347Srandyf bgep->asf_enabled = B_FALSE; 651467f02347Srandyf } else 651567f02347Srandyf bgep->asf_enabled = B_FALSE; 651667f02347Srandyf } 651767f02347Srandyf 651867f02347Srandyf 651967f02347Srandyf void 652067f02347Srandyf bge_asf_pre_reset_operations(bge_t *bgep, uint32_t mode) 652167f02347Srandyf { 652267f02347Srandyf uint32_t tries; 652367f02347Srandyf uint32_t event; 652467f02347Srandyf 652567f02347Srandyf ASSERT(bgep->asf_enabled); 652667f02347Srandyf 652767f02347Srandyf /* Issues "pause firmware" command and wait for ACK */ 652867f02347Srandyf bge_nic_put32(bgep, BGE_CMD_MAILBOX, BGE_CMD_NICDRV_PAUSE_FW); 652967f02347Srandyf event = bge_reg_get32(bgep, RX_RISC_EVENT_REG); 653067f02347Srandyf bge_reg_put32(bgep, RX_RISC_EVENT_REG, event | RRER_ASF_EVENT); 653167f02347Srandyf 653267f02347Srandyf event = bge_reg_get32(bgep, RX_RISC_EVENT_REG); 653367f02347Srandyf tries = 0; 653467f02347Srandyf while ((event & RRER_ASF_EVENT) && (tries < 100)) { 653567f02347Srandyf drv_usecwait(1); 653667f02347Srandyf tries ++; 653767f02347Srandyf event = bge_reg_get32(bgep, RX_RISC_EVENT_REG); 653867f02347Srandyf } 653967f02347Srandyf 654067f02347Srandyf bge_nic_put32(bgep, BGE_FIRMWARE_MAILBOX, 654167f02347Srandyf BGE_MAGIC_NUM_FIRMWARE_INIT_DONE); 654267f02347Srandyf 654367f02347Srandyf if (bgep->asf_newhandshake) { 654467f02347Srandyf switch (mode) { 654567f02347Srandyf case BGE_INIT_RESET: 654667f02347Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 654767f02347Srandyf BGE_DRV_STATE_START); 654867f02347Srandyf break; 654967f02347Srandyf case BGE_SHUTDOWN_RESET: 655067f02347Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 655167f02347Srandyf BGE_DRV_STATE_UNLOAD); 655267f02347Srandyf break; 655367f02347Srandyf case BGE_SUSPEND_RESET: 655467f02347Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 655567f02347Srandyf BGE_DRV_STATE_SUSPEND); 655667f02347Srandyf break; 655767f02347Srandyf default: 655867f02347Srandyf break; 655967f02347Srandyf } 656067f02347Srandyf } 6561087a28d1SDavid Gwynne 6562087a28d1SDavid Gwynne if (mode == BGE_INIT_RESET || 6563087a28d1SDavid Gwynne mode == BGE_SUSPEND_RESET) 6564087a28d1SDavid Gwynne bge_ape_driver_state_change(bgep, mode); 656567f02347Srandyf } 656667f02347Srandyf 656767f02347Srandyf 656867f02347Srandyf void 656967f02347Srandyf bge_asf_post_reset_old_mode(bge_t *bgep, uint32_t mode) 657067f02347Srandyf { 657167f02347Srandyf switch (mode) { 657267f02347Srandyf case BGE_INIT_RESET: 657367f02347Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 657467f02347Srandyf BGE_DRV_STATE_START); 657567f02347Srandyf break; 657667f02347Srandyf case BGE_SHUTDOWN_RESET: 657767f02347Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 657867f02347Srandyf BGE_DRV_STATE_UNLOAD); 657967f02347Srandyf break; 658067f02347Srandyf case BGE_SUSPEND_RESET: 658167f02347Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 658267f02347Srandyf BGE_DRV_STATE_SUSPEND); 658367f02347Srandyf break; 658467f02347Srandyf default: 658567f02347Srandyf break; 658667f02347Srandyf } 658767f02347Srandyf } 658867f02347Srandyf 658967f02347Srandyf 659067f02347Srandyf void 659167f02347Srandyf bge_asf_post_reset_new_mode(bge_t *bgep, uint32_t mode) 659267f02347Srandyf { 659367f02347Srandyf switch (mode) { 659467f02347Srandyf case BGE_INIT_RESET: 659567f02347Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 659667f02347Srandyf BGE_DRV_STATE_START_DONE); 659767f02347Srandyf break; 659867f02347Srandyf case BGE_SHUTDOWN_RESET: 659967f02347Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 660067f02347Srandyf BGE_DRV_STATE_UNLOAD_DONE); 660167f02347Srandyf break; 660267f02347Srandyf default: 660367f02347Srandyf break; 660467f02347Srandyf } 6605087a28d1SDavid Gwynne 6606087a28d1SDavid Gwynne if (mode == BGE_SHUTDOWN_RESET) 6607087a28d1SDavid Gwynne bge_ape_driver_state_change(bgep, mode); 660867f02347Srandyf } 660967f02347Srandyf 661067f02347Srandyf #endif /* BGE_IPMI_ASF */ 6611