11369Sdduvall /* 21369Sdduvall * CDDL HEADER START 31369Sdduvall * 41369Sdduvall * The contents of this file are subject to the terms of the 51369Sdduvall * Common Development and Distribution License (the "License"). 61369Sdduvall * You may not use this file except in compliance with the License. 71369Sdduvall * 81369Sdduvall * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91369Sdduvall * or http://www.opensolaris.org/os/licensing. 101369Sdduvall * See the License for the specific language governing permissions 111369Sdduvall * and limitations under the License. 121369Sdduvall * 131369Sdduvall * When distributing Covered Code, include this CDDL HEADER in each 141369Sdduvall * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151369Sdduvall * If applicable, add the following below this CDDL HEADER, with the 161369Sdduvall * fields enclosed by brackets "[]" replaced with your own identifying 171369Sdduvall * information: Portions Copyright [yyyy] [name of copyright owner] 181369Sdduvall * 191369Sdduvall * CDDL HEADER END 201369Sdduvall */ 211369Sdduvall 221369Sdduvall /* 235903Ssowmini * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241369Sdduvall * Use is subject to license terms. 251369Sdduvall */ 261369Sdduvall 272675Szh199473 #include "bge_impl.h" 281369Sdduvall 291369Sdduvall #define PIO_ADDR(bgep, offset) ((void *)((caddr_t)(bgep)->io_regs+(offset))) 301369Sdduvall 311369Sdduvall /* 321369Sdduvall * Future features ... ? 331369Sdduvall */ 342135Szh199473 #define BGE_CFG_IO8 1 /* 8/16-bit cfg space BIS/BIC */ 353918Sml149210 #define BGE_IND_IO32 1 /* indirect access code */ 361369Sdduvall #define BGE_SEE_IO32 1 /* SEEPROM access code */ 371369Sdduvall #define BGE_FLASH_IO32 1 /* FLASH access code */ 381369Sdduvall 391369Sdduvall /* 401369Sdduvall * BGE MSI tunable: 411369Sdduvall * 421369Sdduvall * By default MSI is enabled on all supported platforms but it is disabled 431369Sdduvall * for some Broadcom chips due to known MSI hardware issues. Currently MSI 441369Sdduvall * is enabled only for 5714C A2 and 5715C A2 broadcom chips. 451369Sdduvall */ 461369Sdduvall boolean_t bge_enable_msi = B_TRUE; 471369Sdduvall 481369Sdduvall /* 493907Szh199473 * PCI-X/PCI-E relaxed ordering tunable for OS/Nexus driver 503907Szh199473 */ 513907Szh199473 boolean_t bge_relaxed_ordering = B_TRUE; 523907Szh199473 533907Szh199473 /* 541369Sdduvall * Property names 551369Sdduvall */ 561369Sdduvall static char knownids_propname[] = "bge-known-subsystems"; 571369Sdduvall 581369Sdduvall /* 591369Sdduvall * Patchable globals: 601369Sdduvall * 611369Sdduvall * bge_autorecover 621369Sdduvall * Enables/disables automatic recovery after fault detection 631369Sdduvall * 641369Sdduvall * bge_mlcr_default 651369Sdduvall * Value to program into the MLCR; controls the chip's GPIO pins 661369Sdduvall * 671369Sdduvall * bge_dma_{rd,wr}prio 681369Sdduvall * Relative priorities of DMA reads & DMA writes respectively. 691369Sdduvall * These may each be patched to any value 0-3. Equal values 701369Sdduvall * will give "fair" (round-robin) arbitration for PCI access. 711369Sdduvall * Unequal values will give one or the other function priority. 721369Sdduvall * 731369Sdduvall * bge_dma_rwctrl 741369Sdduvall * Value to put in the Read/Write DMA control register. See 751369Sdduvall * the Broadcom PRM for things you can fiddle with in this 761369Sdduvall * register ... 771369Sdduvall * 781369Sdduvall * bge_{tx,rx}_{count,ticks}_{norm,intr} 791369Sdduvall * Send/receive interrupt coalescing parameters. Counts are 801369Sdduvall * #s of descriptors, ticks are in microseconds. *norm* values 811369Sdduvall * apply between status updates/interrupts; the *intr* values 821369Sdduvall * refer to the 'during-interrupt' versions - see the PRM. 831369Sdduvall * 841369Sdduvall * NOTE: these values have been determined by measurement. They 851369Sdduvall * differ significantly from the values recommended in the PRM. 861369Sdduvall */ 871369Sdduvall static uint32_t bge_autorecover = 1; 881369Sdduvall static uint32_t bge_mlcr_default_5714 = MLCR_DEFAULT_5714; 891369Sdduvall 901369Sdduvall static uint32_t bge_dma_rdprio = 1; 911369Sdduvall static uint32_t bge_dma_wrprio = 0; 921369Sdduvall static uint32_t bge_dma_rwctrl = PDRWCR_VAR_DEFAULT; 931369Sdduvall static uint32_t bge_dma_rwctrl_5721 = PDRWCR_VAR_5721; 941369Sdduvall static uint32_t bge_dma_rwctrl_5714 = PDRWCR_VAR_5714; 951369Sdduvall static uint32_t bge_dma_rwctrl_5715 = PDRWCR_VAR_5715; 961369Sdduvall 971369Sdduvall uint32_t bge_rx_ticks_norm = 128; 981369Sdduvall uint32_t bge_tx_ticks_norm = 2048; /* 8 for FJ2+ !?!? */ 991369Sdduvall uint32_t bge_rx_count_norm = 8; 1001369Sdduvall uint32_t bge_tx_count_norm = 128; 1011369Sdduvall 1021369Sdduvall static uint32_t bge_rx_ticks_intr = 128; 1031369Sdduvall static uint32_t bge_tx_ticks_intr = 0; /* 8 for FJ2+ !?!? */ 1041369Sdduvall static uint32_t bge_rx_count_intr = 2; 1051369Sdduvall static uint32_t bge_tx_count_intr = 0; 1061369Sdduvall 1071369Sdduvall /* 1081369Sdduvall * Memory pool configuration parameters. 1091369Sdduvall * 1101369Sdduvall * These are generally specific to each member of the chip family, since 1111369Sdduvall * each one may have a different memory size/configuration. 1121369Sdduvall * 1131369Sdduvall * Setting the mbuf pool length for a specific type of chip to 0 inhibits 1141369Sdduvall * the driver from programming the various registers; instead they are left 1151369Sdduvall * at their hardware defaults. This is the preferred option for later chips 1161369Sdduvall * (5705+), whereas the older chips *required* these registers to be set, 1171369Sdduvall * since the h/w default was 0 ;-( 1181369Sdduvall */ 1191369Sdduvall static uint32_t bge_mbuf_pool_base = MBUF_POOL_BASE_DEFAULT; 1201369Sdduvall static uint32_t bge_mbuf_pool_base_5704 = MBUF_POOL_BASE_5704; 1211369Sdduvall static uint32_t bge_mbuf_pool_base_5705 = MBUF_POOL_BASE_5705; 1221369Sdduvall static uint32_t bge_mbuf_pool_base_5721 = MBUF_POOL_BASE_5721; 1231369Sdduvall static uint32_t bge_mbuf_pool_len = MBUF_POOL_LENGTH_DEFAULT; 1241369Sdduvall static uint32_t bge_mbuf_pool_len_5704 = MBUF_POOL_LENGTH_5704; 1251369Sdduvall static uint32_t bge_mbuf_pool_len_5705 = 0; /* use h/w default */ 1261369Sdduvall static uint32_t bge_mbuf_pool_len_5721 = 0; 1271369Sdduvall 1281369Sdduvall /* 1291369Sdduvall * Various high and low water marks, thresholds, etc ... 1301369Sdduvall * 1311369Sdduvall * Note: these are taken from revision 7 of the PRM, and some are different 1321369Sdduvall * from both the values in earlier PRMs *and* those determined experimentally 1331369Sdduvall * and used in earlier versions of this driver ... 1341369Sdduvall */ 1351369Sdduvall static uint32_t bge_mbuf_hi_water = MBUF_HIWAT_DEFAULT; 1361369Sdduvall static uint32_t bge_mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_DEFAULT; 1371369Sdduvall static uint32_t bge_mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_DEFAULT; 1381369Sdduvall 1391369Sdduvall static uint32_t bge_dmad_lo_water = DMAD_POOL_LOWAT_DEFAULT; 1401369Sdduvall static uint32_t bge_dmad_hi_water = DMAD_POOL_HIWAT_DEFAULT; 1411369Sdduvall static uint32_t bge_lowat_recv_frames = LOWAT_MAX_RECV_FRAMES_DEFAULT; 1421369Sdduvall 1431369Sdduvall static uint32_t bge_replenish_std = STD_RCV_BD_REPLENISH_DEFAULT; 1441369Sdduvall static uint32_t bge_replenish_mini = MINI_RCV_BD_REPLENISH_DEFAULT; 1451369Sdduvall static uint32_t bge_replenish_jumbo = JUMBO_RCV_BD_REPLENISH_DEFAULT; 1461369Sdduvall 1471369Sdduvall static uint32_t bge_watchdog_count = 1 << 16; 1481369Sdduvall static uint16_t bge_dma_miss_limit = 20; 1491369Sdduvall 1501369Sdduvall static uint32_t bge_stop_start_on_sync = 0; 1511369Sdduvall 1521369Sdduvall boolean_t bge_jumbo_enable = B_TRUE; 1531369Sdduvall 1541369Sdduvall /* 1553918Sml149210 * bge_intr_max_loop controls the maximum loop number within bge_intr. 1563918Sml149210 * When loading NIC with heavy network traffic, it is useful. 1573918Sml149210 * Increasing this value could have positive effect to throughput, 1583918Sml149210 * but it might also increase ticks of a bge ISR stick on CPU, which might 1593918Sml149210 * lead to bad UI interactive experience. So tune this with caution. 1603918Sml149210 */ 1613918Sml149210 static int bge_intr_max_loop = 1; 1623918Sml149210 1633918Sml149210 /* 1641369Sdduvall * ========== Low-level chip & ring buffer manipulation ========== 1651369Sdduvall */ 1661369Sdduvall 1671369Sdduvall #define BGE_DBG BGE_DBG_REGS /* debug flag for this code */ 1681369Sdduvall 1691369Sdduvall 1701369Sdduvall /* 1711369Sdduvall * Config space read-modify-write routines 1721369Sdduvall */ 1731369Sdduvall 1741369Sdduvall #if BGE_CFG_IO8 1751369Sdduvall 1761369Sdduvall static void bge_cfg_clr16(bge_t *bgep, bge_regno_t regno, uint16_t bits); 1771369Sdduvall #pragma inline(bge_cfg_clr16) 1781369Sdduvall 1791369Sdduvall static void 1801369Sdduvall bge_cfg_clr16(bge_t *bgep, bge_regno_t regno, uint16_t bits) 1811369Sdduvall { 1821369Sdduvall uint16_t regval; 1831369Sdduvall 1841369Sdduvall BGE_TRACE(("bge_cfg_clr16($%p, 0x%lx, 0x%x)", 1854588Sml149210 (void *)bgep, regno, bits)); 1861369Sdduvall 1871369Sdduvall regval = pci_config_get16(bgep->cfg_handle, regno); 1881369Sdduvall 1891369Sdduvall BGE_DEBUG(("bge_cfg_clr16($%p, 0x%lx, 0x%x): 0x%x => 0x%x", 1904588Sml149210 (void *)bgep, regno, bits, regval, regval & ~bits)); 1911369Sdduvall 1921369Sdduvall regval &= ~bits; 1931369Sdduvall pci_config_put16(bgep->cfg_handle, regno, regval); 1941369Sdduvall } 1951369Sdduvall 1961369Sdduvall #endif /* BGE_CFG_IO8 */ 1971369Sdduvall 1981369Sdduvall static void bge_cfg_clr32(bge_t *bgep, bge_regno_t regno, uint32_t bits); 1991369Sdduvall #pragma inline(bge_cfg_clr32) 2001369Sdduvall 2011369Sdduvall static void 2021369Sdduvall bge_cfg_clr32(bge_t *bgep, bge_regno_t regno, uint32_t bits) 2031369Sdduvall { 2041369Sdduvall uint32_t regval; 2051369Sdduvall 2061369Sdduvall BGE_TRACE(("bge_cfg_clr32($%p, 0x%lx, 0x%x)", 2074588Sml149210 (void *)bgep, regno, bits)); 2081369Sdduvall 2091369Sdduvall regval = pci_config_get32(bgep->cfg_handle, regno); 2101369Sdduvall 2111369Sdduvall BGE_DEBUG(("bge_cfg_clr32($%p, 0x%lx, 0x%x): 0x%x => 0x%x", 2124588Sml149210 (void *)bgep, regno, bits, regval, regval & ~bits)); 2131369Sdduvall 2141369Sdduvall regval &= ~bits; 2151369Sdduvall pci_config_put32(bgep->cfg_handle, regno, regval); 2161369Sdduvall } 2171369Sdduvall 2181369Sdduvall #if BGE_IND_IO32 2191369Sdduvall 2201369Sdduvall /* 2211369Sdduvall * Indirect access to registers & RISC scratchpads, using config space 2221369Sdduvall * accesses only. 2231369Sdduvall * 2241369Sdduvall * This isn't currently used, but someday we might want to use it for 2251369Sdduvall * restoring the Subsystem Device/Vendor registers (which aren't directly 2261369Sdduvall * writable in Config Space), or for downloading firmware into the RISCs 2271369Sdduvall * 2281369Sdduvall * In any case there are endian issues to be resolved before this code is 2291369Sdduvall * enabled; the bizarre way that bytes get twisted by this chip AND by 2301369Sdduvall * the PCI bridge in SPARC systems mean that we shouldn't enable it until 2311369Sdduvall * it's been thoroughly tested for all access sizes on all supported 2321369Sdduvall * architectures (SPARC *and* x86!). 2331369Sdduvall */ 2343918Sml149210 uint32_t bge_ind_get32(bge_t *bgep, bge_regno_t regno); 2351369Sdduvall #pragma inline(bge_ind_get32) 2361369Sdduvall 2373918Sml149210 uint32_t 2381369Sdduvall bge_ind_get32(bge_t *bgep, bge_regno_t regno) 2391369Sdduvall { 2401369Sdduvall uint32_t val; 2411369Sdduvall 2421369Sdduvall BGE_TRACE(("bge_ind_get32($%p, 0x%lx)", (void *)bgep, regno)); 2431369Sdduvall 2441369Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_RIAAR, regno); 2451369Sdduvall val = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_RIADR); 2461369Sdduvall 2471369Sdduvall BGE_DEBUG(("bge_ind_get32($%p, 0x%lx) => 0x%x", 2484588Sml149210 (void *)bgep, regno, val)); 2491369Sdduvall 2503918Sml149210 val = LE_32(val); 2513918Sml149210 2521369Sdduvall return (val); 2531369Sdduvall } 2541369Sdduvall 2553918Sml149210 void bge_ind_put32(bge_t *bgep, bge_regno_t regno, uint32_t val); 2561369Sdduvall #pragma inline(bge_ind_put32) 2571369Sdduvall 2583918Sml149210 void 2591369Sdduvall bge_ind_put32(bge_t *bgep, bge_regno_t regno, uint32_t val) 2601369Sdduvall { 2611369Sdduvall BGE_TRACE(("bge_ind_put32($%p, 0x%lx, 0x%x)", 2624588Sml149210 (void *)bgep, regno, val)); 2631369Sdduvall 2643918Sml149210 val = LE_32(val); 2651369Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_RIAAR, regno); 2661369Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_RIADR, val); 2671369Sdduvall } 2681369Sdduvall 2691369Sdduvall #endif /* BGE_IND_IO32 */ 2701369Sdduvall 2711369Sdduvall #if BGE_DEBUGGING 2721369Sdduvall 2731369Sdduvall static void bge_pci_check(bge_t *bgep); 2741369Sdduvall #pragma no_inline(bge_pci_check) 2751369Sdduvall 2761369Sdduvall static void 2771369Sdduvall bge_pci_check(bge_t *bgep) 2781369Sdduvall { 2791369Sdduvall uint16_t pcistatus; 2801369Sdduvall 2811369Sdduvall pcistatus = pci_config_get16(bgep->cfg_handle, PCI_CONF_STAT); 2821369Sdduvall if ((pcistatus & (PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB)) != 0) 2831369Sdduvall BGE_DEBUG(("bge_pci_check($%p): PCI status 0x%x", 2844588Sml149210 (void *)bgep, pcistatus)); 2851369Sdduvall } 2861369Sdduvall 2871369Sdduvall #endif /* BGE_DEBUGGING */ 2881369Sdduvall 2891369Sdduvall /* 2901369Sdduvall * Perform first-stage chip (re-)initialisation, using only config-space 2911369Sdduvall * accesses: 2921369Sdduvall * 2931369Sdduvall * + Read the vendor/device/revision/subsystem/cache-line-size registers, 2941369Sdduvall * returning the data in the structure pointed to by <idp>. 2951369Sdduvall * + Configure the target-mode endianness (swap) options. 2961369Sdduvall * + Disable interrupts and enable Memory Space accesses. 2971369Sdduvall * + Enable or disable Bus Mastering according to the <enable_dma> flag. 2981369Sdduvall * 2991369Sdduvall * This sequence is adapted from Broadcom document 570X-PG102-R, 3001369Sdduvall * page 102, steps 1-3, 6-8 and 11-13. The omitted parts of the sequence 3011369Sdduvall * are 4 and 5 (Reset Core and wait) which are handled elsewhere. 3021369Sdduvall * 3031369Sdduvall * This function MUST be called before any non-config-space accesses 3041369Sdduvall * are made; on this first call <enable_dma> is B_FALSE, and it 3051369Sdduvall * effectively performs steps 3-1(!) of the initialisation sequence 3061369Sdduvall * (the rest are not required but should be harmless). 3071369Sdduvall * 3082135Szh199473 * It MUST also be called after a chip reset, as this disables 3091369Sdduvall * Memory Space cycles! In this case, <enable_dma> is B_TRUE, and 3101369Sdduvall * it is effectively performing steps 6-8. 3111369Sdduvall */ 3121369Sdduvall void bge_chip_cfg_init(bge_t *bgep, chip_id_t *cidp, boolean_t enable_dma); 3131369Sdduvall #pragma no_inline(bge_chip_cfg_init) 3141369Sdduvall 3151369Sdduvall void 3161369Sdduvall bge_chip_cfg_init(bge_t *bgep, chip_id_t *cidp, boolean_t enable_dma) 3171369Sdduvall { 3181369Sdduvall ddi_acc_handle_t handle; 3191369Sdduvall uint16_t command; 3201369Sdduvall uint32_t mhcr; 3211369Sdduvall uint16_t value16; 3221369Sdduvall int i; 3231369Sdduvall 3241369Sdduvall BGE_TRACE(("bge_chip_cfg_init($%p, $%p, %d)", 3254588Sml149210 (void *)bgep, (void *)cidp, enable_dma)); 3261369Sdduvall 3271369Sdduvall /* 3281369Sdduvall * Step 3: save PCI cache line size and subsystem vendor ID 3291369Sdduvall * 3301369Sdduvall * Read all the config-space registers that characterise the 3311369Sdduvall * chip, specifically vendor/device/revision/subsystem vendor 3321369Sdduvall * and subsystem device id. We expect (but don't check) that 3331369Sdduvall * (vendor == VENDOR_ID_BROADCOM) && (device == DEVICE_ID_5704) 3341369Sdduvall * 3352135Szh199473 * Also save all bus-transaction related registers (cache-line 3361369Sdduvall * size, bus-grant/latency parameters, etc). Some of these are 3371369Sdduvall * cleared by reset, so we'll have to restore them later. This 3381369Sdduvall * comes from the Broadcom document 570X-PG102-R ... 3391369Sdduvall * 3401369Sdduvall * Note: Broadcom document 570X-PG102-R seems to be in error 3411369Sdduvall * here w.r.t. the offsets of the Subsystem Vendor ID and 3421369Sdduvall * Subsystem (Device) ID registers, which are the opposite way 3431369Sdduvall * round according to the PCI standard. For good measure, we 3441369Sdduvall * save/restore both anyway. 3451369Sdduvall */ 3461369Sdduvall handle = bgep->cfg_handle; 3471369Sdduvall 3481369Sdduvall mhcr = pci_config_get32(handle, PCI_CONF_BGE_MHCR); 3491369Sdduvall cidp->asic_rev = mhcr & MHCR_CHIP_REV_MASK; 3501369Sdduvall cidp->businfo = pci_config_get32(handle, PCI_CONF_BGE_PCISTATE); 3511369Sdduvall cidp->command = pci_config_get16(handle, PCI_CONF_COMM); 3521369Sdduvall 3531369Sdduvall cidp->vendor = pci_config_get16(handle, PCI_CONF_VENID); 3541369Sdduvall cidp->device = pci_config_get16(handle, PCI_CONF_DEVID); 3551369Sdduvall cidp->subven = pci_config_get16(handle, PCI_CONF_SUBVENID); 3561369Sdduvall cidp->subdev = pci_config_get16(handle, PCI_CONF_SUBSYSID); 3571369Sdduvall cidp->revision = pci_config_get8(handle, PCI_CONF_REVID); 3581369Sdduvall cidp->clsize = pci_config_get8(handle, PCI_CONF_CACHE_LINESZ); 3591369Sdduvall cidp->latency = pci_config_get8(handle, PCI_CONF_LATENCY_TIMER); 3601369Sdduvall 3611369Sdduvall BGE_DEBUG(("bge_chip_cfg_init: %s bus is %s and %s; #INTA is %s", 3624588Sml149210 cidp->businfo & PCISTATE_BUS_IS_PCI ? "PCI" : "PCI-X", 3634588Sml149210 cidp->businfo & PCISTATE_BUS_IS_FAST ? "fast" : "slow", 3644588Sml149210 cidp->businfo & PCISTATE_BUS_IS_32_BIT ? "narrow" : "wide", 3654588Sml149210 cidp->businfo & PCISTATE_INTA_STATE ? "high" : "low")); 3661369Sdduvall BGE_DEBUG(("bge_chip_cfg_init: vendor 0x%x device 0x%x revision 0x%x", 3674588Sml149210 cidp->vendor, cidp->device, cidp->revision)); 3681369Sdduvall BGE_DEBUG(("bge_chip_cfg_init: subven 0x%x subdev 0x%x asic_rev 0x%x", 3694588Sml149210 cidp->subven, cidp->subdev, cidp->asic_rev)); 3701369Sdduvall BGE_DEBUG(("bge_chip_cfg_init: clsize %d latency %d command 0x%x", 3714588Sml149210 cidp->clsize, cidp->latency, cidp->command)); 3721369Sdduvall 3731369Sdduvall /* 3741369Sdduvall * Step 2 (also step 6): disable and clear interrupts. 3751369Sdduvall * Steps 11-13: configure PIO endianness options, and enable 3761369Sdduvall * indirect register access. We'll also select any other 3772135Szh199473 * options controlled by the MHCR (e.g. tagged status, mask 3781369Sdduvall * interrupt mode) at this stage ... 3791369Sdduvall * 3801369Sdduvall * Note: internally, the chip is 64-bit and BIG-endian, but 3811369Sdduvall * since it talks to the host over a (LITTLE-endian) PCI bus, 3821369Sdduvall * it normally swaps bytes around at the PCI interface. 3831369Sdduvall * However, the PCI host bridge on SPARC systems normally 3841369Sdduvall * swaps the byte lanes around too, since SPARCs are also 3851369Sdduvall * BIG-endian. So it turns out that on SPARC, the right 3861369Sdduvall * option is to tell the chip to swap (and the host bridge 3871369Sdduvall * will swap back again), whereas on x86 we ask the chip 3881369Sdduvall * NOT to swap, so the natural little-endianness of the 3891369Sdduvall * PCI bus is assumed. Then the only thing that doesn't 3901369Sdduvall * automatically work right is access to an 8-byte register 3911369Sdduvall * by a little-endian host; but we don't want to set the 3921369Sdduvall * MHCR_ENABLE_REGISTER_WORD_SWAP bit because then 4-byte 3931369Sdduvall * accesses don't go where expected ;-( So we live with 3941369Sdduvall * that, and perform word-swaps in software in the few cases 3951369Sdduvall * where a chip register is defined as an 8-byte value -- 3961369Sdduvall * see the code below for details ... 3971369Sdduvall * 3981369Sdduvall * Note: the meaning of the 'MASK_INTERRUPT_MODE' bit isn't 3991369Sdduvall * very clear in the register description in the PRM, but 4001369Sdduvall * Broadcom document 570X-PG104-R page 248 explains a little 4011369Sdduvall * more (under "Broadcom Mask Mode"). The bit changes the way 4021369Sdduvall * the MASK_PCI_INT_OUTPUT bit works: with MASK_INTERRUPT_MODE 4031369Sdduvall * clear, the chip interprets MASK_PCI_INT_OUTPUT in the same 4041369Sdduvall * way as the 5700 did, which isn't very convenient. Setting 4051369Sdduvall * the MASK_INTERRUPT_MODE bit makes the MASK_PCI_INT_OUTPUT 4061369Sdduvall * bit do just what its name says -- MASK the PCI #INTA output 4071369Sdduvall * (i.e. deassert the signal at the pin) leaving all internal 4081369Sdduvall * state unchanged. This is much more convenient for our 4091369Sdduvall * interrupt handler, so we set MASK_INTERRUPT_MODE here. 4101369Sdduvall * 4111369Sdduvall * Note: the inconvenient semantics of the interrupt mailbox 4121369Sdduvall * (nonzero disables and acknowledges/clears the interrupt, 4131369Sdduvall * zero enables AND CLEARS it) would make race conditions 4141369Sdduvall * likely in the interrupt handler: 4151369Sdduvall * 4161369Sdduvall * (1) acknowledge & disable interrupts 4171369Sdduvall * (2) while (more to do) 4181369Sdduvall * process packets 4191369Sdduvall * (3) enable interrupts -- also clears pending 4201369Sdduvall * 4211369Sdduvall * If the chip received more packets and internally generated 4221369Sdduvall * an interrupt between the check at (2) and the mbox write 4231369Sdduvall * at (3), this interrupt would be lost :-( 4241369Sdduvall * 4251369Sdduvall * The best way to avoid this is to use TAGGED STATUS mode, 4261369Sdduvall * where the chip includes a unique tag in each status block 4271369Sdduvall * update, and the host, when re-enabling interrupts, passes 4281369Sdduvall * the last tag it saw back to the chip; then the chip can 4291369Sdduvall * see whether the host is truly up to date, and regenerate 4301369Sdduvall * its interrupt if not. 4311369Sdduvall */ 4321369Sdduvall mhcr = MHCR_ENABLE_INDIRECT_ACCESS | 4334588Sml149210 MHCR_ENABLE_TAGGED_STATUS_MODE | 4344588Sml149210 MHCR_MASK_INTERRUPT_MODE | 4354588Sml149210 MHCR_CLEAR_INTERRUPT_INTA; 4361369Sdduvall 4371369Sdduvall if (bgep->intr_type == DDI_INTR_TYPE_FIXED) 4381369Sdduvall mhcr |= MHCR_MASK_PCI_INT_OUTPUT; 4391369Sdduvall 4401369Sdduvall #ifdef _BIG_ENDIAN 4411369Sdduvall mhcr |= MHCR_ENABLE_ENDIAN_WORD_SWAP | MHCR_ENABLE_ENDIAN_BYTE_SWAP; 4421369Sdduvall #endif /* _BIG_ENDIAN */ 4431369Sdduvall 4441369Sdduvall pci_config_put32(handle, PCI_CONF_BGE_MHCR, mhcr); 4451369Sdduvall 4461408Srandyf #ifdef BGE_IPMI_ASF 4471408Srandyf bgep->asf_wordswapped = B_FALSE; 4481408Srandyf #endif 4491369Sdduvall /* 4501369Sdduvall * Step 1 (also step 7): Enable PCI Memory Space accesses 4511369Sdduvall * Disable Memory Write/Invalidate 4521369Sdduvall * Enable or disable Bus Mastering 4531369Sdduvall * 4541369Sdduvall * Note that all other bits are taken from the original value saved 4551369Sdduvall * the first time through here, rather than from the current register 4561369Sdduvall * value, 'cos that will have been cleared by a soft RESET since. 4571369Sdduvall * In this way we preserve the OBP/nexus-parent's preferred settings 4581369Sdduvall * of the parity-error and system-error enable bits across multiple 4591369Sdduvall * chip RESETs. 4601369Sdduvall */ 4611369Sdduvall command = bgep->chipid.command | PCI_COMM_MAE; 4621369Sdduvall command &= ~(PCI_COMM_ME|PCI_COMM_MEMWR_INVAL); 4631369Sdduvall if (enable_dma) 4641369Sdduvall command |= PCI_COMM_ME; 4651369Sdduvall /* 4661369Sdduvall * on BCM5714 revision A0, false parity error gets generated 4672135Szh199473 * due to a logic bug. Provide a workaround by disabling parity 4681369Sdduvall * error. 4691369Sdduvall */ 4701369Sdduvall if (((cidp->device == DEVICE_ID_5714C) || 4711369Sdduvall (cidp->device == DEVICE_ID_5714S)) && 4721369Sdduvall (cidp->revision == REVISION_ID_5714_A0)) { 4731369Sdduvall command &= ~PCI_COMM_PARITY_DETECT; 4741369Sdduvall } 4751369Sdduvall pci_config_put16(handle, PCI_CONF_COMM, command); 4761369Sdduvall 4771369Sdduvall /* 4781369Sdduvall * On some PCI-E device, there were instances when 4791369Sdduvall * the device was still link training. 4801369Sdduvall */ 4811369Sdduvall if (bgep->chipid.pci_type == BGE_PCI_E) { 4821369Sdduvall i = 0; 4831369Sdduvall value16 = pci_config_get16(handle, PCI_CONF_COMM); 4841369Sdduvall while ((value16 != command) && (i < 100)) { 4851369Sdduvall drv_usecwait(200); 4861369Sdduvall value16 = pci_config_get16(handle, PCI_CONF_COMM); 4871369Sdduvall ++i; 4881369Sdduvall } 4891369Sdduvall } 4901369Sdduvall 4911369Sdduvall /* 4921369Sdduvall * Clear any remaining error status bits 4931369Sdduvall */ 4941369Sdduvall pci_config_put16(handle, PCI_CONF_STAT, ~0); 4951369Sdduvall 4961369Sdduvall /* 4972073Svivek * Do following if and only if the device is NOT BCM5714C OR 4982073Svivek * BCM5715C 4991369Sdduvall */ 5002073Svivek if (!((cidp->device == DEVICE_ID_5714C) || 5014588Sml149210 (cidp->device == DEVICE_ID_5715C))) { 5022073Svivek /* 5032073Svivek * Make sure these indirect-access registers are sane 5042073Svivek * rather than random after power-up or reset 5052073Svivek */ 5062073Svivek pci_config_put32(handle, PCI_CONF_BGE_RIAAR, 0); 5072073Svivek pci_config_put32(handle, PCI_CONF_BGE_MWBAR, 0); 5082073Svivek } 5092135Szh199473 /* 5102135Szh199473 * Step 8: Disable PCI-X/PCI-E Relaxed Ordering 5112135Szh199473 */ 5122135Szh199473 bge_cfg_clr16(bgep, PCIX_CONF_COMM, PCIX_COMM_RELAXED); 5132135Szh199473 5142135Szh199473 if (cidp->pci_type == BGE_PCI_E) 5152135Szh199473 bge_cfg_clr16(bgep, PCI_CONF_DEV_CTRL, 5164588Sml149210 DEV_CTRL_NO_SNOOP | DEV_CTRL_RELAXED); 5171369Sdduvall } 5181369Sdduvall 5191369Sdduvall #ifdef __amd64 5201369Sdduvall /* 5211369Sdduvall * Distinguish CPU types 5221369Sdduvall * 5231369Sdduvall * These use to distinguish AMD64 or Intel EM64T of CPU running mode. 5241369Sdduvall * If CPU runs on Intel EM64T mode,the 64bit operation cannot works fine 5251369Sdduvall * for PCI-Express based network interface card. This is the work-around 5261369Sdduvall * for those nics. 5271369Sdduvall */ 5281369Sdduvall static boolean_t bge_get_em64t_type(void); 5291369Sdduvall #pragma inline(bge_get_em64t_type) 5301369Sdduvall 5311369Sdduvall static boolean_t 5321369Sdduvall bge_get_em64t_type(void) 5331369Sdduvall { 5341369Sdduvall 5351369Sdduvall return (x86_vendor == X86_VENDOR_Intel); 5361369Sdduvall } 5371369Sdduvall #endif 5381369Sdduvall 5391369Sdduvall /* 5401369Sdduvall * Operating register get/set access routines 5411369Sdduvall */ 5421369Sdduvall 5431369Sdduvall uint32_t bge_reg_get32(bge_t *bgep, bge_regno_t regno); 5441369Sdduvall #pragma inline(bge_reg_get32) 5451369Sdduvall 5461369Sdduvall uint32_t 5471369Sdduvall bge_reg_get32(bge_t *bgep, bge_regno_t regno) 5481369Sdduvall { 5491369Sdduvall BGE_TRACE(("bge_reg_get32($%p, 0x%lx)", 5504588Sml149210 (void *)bgep, regno)); 5511369Sdduvall 5521369Sdduvall return (ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno))); 5531369Sdduvall } 5541369Sdduvall 5551369Sdduvall void bge_reg_put32(bge_t *bgep, bge_regno_t regno, uint32_t data); 5561369Sdduvall #pragma inline(bge_reg_put32) 5571369Sdduvall 5581369Sdduvall void 5591369Sdduvall bge_reg_put32(bge_t *bgep, bge_regno_t regno, uint32_t data) 5601369Sdduvall { 5611369Sdduvall BGE_TRACE(("bge_reg_put32($%p, 0x%lx, 0x%x)", 5624588Sml149210 (void *)bgep, regno, data)); 5631369Sdduvall 5641369Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, regno), data); 5651369Sdduvall BGE_PCICHK(bgep); 5661369Sdduvall } 5671369Sdduvall 5681369Sdduvall void bge_reg_set32(bge_t *bgep, bge_regno_t regno, uint32_t bits); 5691369Sdduvall #pragma inline(bge_reg_set32) 5701369Sdduvall 5711369Sdduvall void 5721369Sdduvall bge_reg_set32(bge_t *bgep, bge_regno_t regno, uint32_t bits) 5731369Sdduvall { 5741369Sdduvall uint32_t regval; 5751369Sdduvall 5761369Sdduvall BGE_TRACE(("bge_reg_set32($%p, 0x%lx, 0x%x)", 5774588Sml149210 (void *)bgep, regno, bits)); 5781369Sdduvall 5791369Sdduvall regval = bge_reg_get32(bgep, regno); 5801369Sdduvall regval |= bits; 5811369Sdduvall bge_reg_put32(bgep, regno, regval); 5821369Sdduvall } 5831369Sdduvall 5841369Sdduvall void bge_reg_clr32(bge_t *bgep, bge_regno_t regno, uint32_t bits); 5851369Sdduvall #pragma inline(bge_reg_clr32) 5861369Sdduvall 5871369Sdduvall void 5881369Sdduvall bge_reg_clr32(bge_t *bgep, bge_regno_t regno, uint32_t bits) 5891369Sdduvall { 5901369Sdduvall uint32_t regval; 5911369Sdduvall 5921369Sdduvall BGE_TRACE(("bge_reg_clr32($%p, 0x%lx, 0x%x)", 5934588Sml149210 (void *)bgep, regno, bits)); 5941369Sdduvall 5951369Sdduvall regval = bge_reg_get32(bgep, regno); 5961369Sdduvall regval &= ~bits; 5971369Sdduvall bge_reg_put32(bgep, regno, regval); 5981369Sdduvall } 5991369Sdduvall 6001369Sdduvall static uint64_t bge_reg_get64(bge_t *bgep, bge_regno_t regno); 6011369Sdduvall #pragma inline(bge_reg_get64) 6021369Sdduvall 6031369Sdduvall static uint64_t 6041369Sdduvall bge_reg_get64(bge_t *bgep, bge_regno_t regno) 6051369Sdduvall { 6061369Sdduvall uint64_t regval; 6071369Sdduvall 6081369Sdduvall #ifdef __amd64 6091369Sdduvall if (bge_get_em64t_type()) { 6101369Sdduvall regval = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno + 4)); 6111369Sdduvall regval <<= 32; 6121369Sdduvall regval |= ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno)); 6131369Sdduvall } else { 6141369Sdduvall regval = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, regno)); 6151369Sdduvall } 6161369Sdduvall #else 6171369Sdduvall regval = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, regno)); 6181369Sdduvall #endif 6191369Sdduvall 6201369Sdduvall #ifdef _LITTLE_ENDIAN 6211369Sdduvall regval = (regval >> 32) | (regval << 32); 6221369Sdduvall #endif /* _LITTLE_ENDIAN */ 6231369Sdduvall 6241369Sdduvall BGE_TRACE(("bge_reg_get64($%p, 0x%lx) = 0x%016llx", 6254588Sml149210 (void *)bgep, regno, regval)); 6261369Sdduvall 6271369Sdduvall return (regval); 6281369Sdduvall } 6291369Sdduvall 6301369Sdduvall static void bge_reg_put64(bge_t *bgep, bge_regno_t regno, uint64_t data); 6311369Sdduvall #pragma inline(bge_reg_put64) 6321369Sdduvall 6331369Sdduvall static void 6341369Sdduvall bge_reg_put64(bge_t *bgep, bge_regno_t regno, uint64_t data) 6351369Sdduvall { 6361369Sdduvall BGE_TRACE(("bge_reg_put64($%p, 0x%lx, 0x%016llx)", 6374588Sml149210 (void *)bgep, regno, data)); 6381369Sdduvall 6391369Sdduvall #ifdef _LITTLE_ENDIAN 6401369Sdduvall data = ((data >> 32) | (data << 32)); 6411369Sdduvall #endif /* _LITTLE_ENDIAN */ 6421369Sdduvall 6431369Sdduvall #ifdef __amd64 6441369Sdduvall if (bge_get_em64t_type()) { 6451369Sdduvall ddi_put32(bgep->io_handle, 6464588Sml149210 PIO_ADDR(bgep, regno), (uint32_t)data); 6471369Sdduvall BGE_PCICHK(bgep); 6481369Sdduvall ddi_put32(bgep->io_handle, 6494588Sml149210 PIO_ADDR(bgep, regno + 4), (uint32_t)(data >> 32)); 6501369Sdduvall 6511369Sdduvall } else { 6521369Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, regno), data); 6531369Sdduvall } 6541369Sdduvall #else 6551369Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, regno), data); 6561369Sdduvall #endif 6571369Sdduvall 6581369Sdduvall BGE_PCICHK(bgep); 6591369Sdduvall } 6601369Sdduvall 6611369Sdduvall /* 6621369Sdduvall * The DDI doesn't provide get/put functions for 128 bit data 6631369Sdduvall * so we put RCBs out as two 64-bit chunks instead. 6641369Sdduvall */ 6651369Sdduvall static void bge_reg_putrcb(bge_t *bgep, bge_regno_t addr, bge_rcb_t *rcbp); 6661369Sdduvall #pragma inline(bge_reg_putrcb) 6671369Sdduvall 6681369Sdduvall static void 6691369Sdduvall bge_reg_putrcb(bge_t *bgep, bge_regno_t addr, bge_rcb_t *rcbp) 6701369Sdduvall { 6711369Sdduvall uint64_t *p; 6721369Sdduvall 6731369Sdduvall BGE_TRACE(("bge_reg_putrcb($%p, 0x%lx, 0x%016llx:%04x:%04x:%08x)", 6744588Sml149210 (void *)bgep, addr, rcbp->host_ring_addr, 6754588Sml149210 rcbp->max_len, rcbp->flags, rcbp->nic_ring_addr)); 6761369Sdduvall 6771369Sdduvall ASSERT((addr % sizeof (*rcbp)) == 0); 6781369Sdduvall 6791369Sdduvall p = (void *)rcbp; 6801369Sdduvall bge_reg_put64(bgep, addr, *p++); 6811369Sdduvall bge_reg_put64(bgep, addr+8, *p); 6821369Sdduvall } 6831369Sdduvall 6841369Sdduvall void bge_mbx_put(bge_t *bgep, bge_regno_t regno, uint64_t data); 6851369Sdduvall #pragma inline(bge_mbx_put) 6861369Sdduvall 6871369Sdduvall void 6881369Sdduvall bge_mbx_put(bge_t *bgep, bge_regno_t regno, uint64_t data) 6891369Sdduvall { 690*7678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 691*7678SYong.Tan@Sun.COM regno += INTERRUPT_LP_MBOX_0_REG - INTERRUPT_MBOX_0_REG + 4; 692*7678SYong.Tan@Sun.COM 6931369Sdduvall BGE_TRACE(("bge_mbx_put($%p, 0x%lx, 0x%016llx)", 6944588Sml149210 (void *)bgep, regno, data)); 6951369Sdduvall 6961369Sdduvall /* 6971369Sdduvall * Mailbox registers are nominally 64 bits on the 5701, but 6981369Sdduvall * the MSW isn't used. On the 5703, they're only 32 bits 6991369Sdduvall * anyway. So here we just write the lower(!) 32 bits - 7001369Sdduvall * remembering that the chip is big-endian, even though the 7011369Sdduvall * PCI bus is little-endian ... 7021369Sdduvall */ 7031369Sdduvall #ifdef _BIG_ENDIAN 7041369Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, regno+4), (uint32_t)data); 7051369Sdduvall #else 7061369Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, regno), (uint32_t)data); 7071369Sdduvall #endif /* _BIG_ENDIAN */ 7081369Sdduvall BGE_PCICHK(bgep); 7091369Sdduvall } 7101369Sdduvall 7116546Sgh162552 uint32_t bge_mbx_get(bge_t *bgep, bge_regno_t regno); 7126546Sgh162552 #pragma inline(bge_mbx_get) 7136546Sgh162552 7146546Sgh162552 uint32_t 7156546Sgh162552 bge_mbx_get(bge_t *bgep, bge_regno_t regno) 7166546Sgh162552 { 7176546Sgh162552 uint32_t val32; 7186546Sgh162552 719*7678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 720*7678SYong.Tan@Sun.COM regno += INTERRUPT_LP_MBOX_0_REG - INTERRUPT_MBOX_0_REG + 4; 721*7678SYong.Tan@Sun.COM 7226546Sgh162552 BGE_TRACE(("bge_mbx_get($%p, 0x%lx)", 7236546Sgh162552 (void *)bgep, regno)); 7246546Sgh162552 7256546Sgh162552 #ifdef _BIG_ENDIAN 7266546Sgh162552 val32 = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno+4)); 7276546Sgh162552 #else 7286546Sgh162552 val32 = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, regno)); 7296546Sgh162552 #endif /* _BIG_ENDIAN */ 7306546Sgh162552 BGE_PCICHK(bgep); 7316546Sgh162552 7326546Sgh162552 return (val32); 7336546Sgh162552 } 7346546Sgh162552 7356546Sgh162552 7361369Sdduvall #if BGE_DEBUGGING 7371369Sdduvall 7381369Sdduvall void bge_led_mark(bge_t *bgep); 7391369Sdduvall #pragma no_inline(bge_led_mark) 7401369Sdduvall 7411369Sdduvall void 7421369Sdduvall bge_led_mark(bge_t *bgep) 7431369Sdduvall { 7441369Sdduvall uint32_t led_ctrl = LED_CONTROL_OVERRIDE_LINK | 7454588Sml149210 LED_CONTROL_1000MBPS_LED | 7464588Sml149210 LED_CONTROL_100MBPS_LED | 7474588Sml149210 LED_CONTROL_10MBPS_LED; 7481369Sdduvall 7491369Sdduvall /* 7501369Sdduvall * Blink all three LINK LEDs on simultaneously, then all off, 7511369Sdduvall * then restore to automatic hardware control. This is used 7521369Sdduvall * in laboratory testing to trigger a logic analyser or scope. 7531369Sdduvall */ 7541369Sdduvall bge_reg_set32(bgep, ETHERNET_MAC_LED_CONTROL_REG, led_ctrl); 7551369Sdduvall led_ctrl ^= LED_CONTROL_OVERRIDE_LINK; 7561369Sdduvall bge_reg_clr32(bgep, ETHERNET_MAC_LED_CONTROL_REG, led_ctrl); 7571369Sdduvall led_ctrl = LED_CONTROL_OVERRIDE_LINK; 7581369Sdduvall bge_reg_clr32(bgep, ETHERNET_MAC_LED_CONTROL_REG, led_ctrl); 7591369Sdduvall } 7601369Sdduvall 7611369Sdduvall #endif /* BGE_DEBUGGING */ 7621369Sdduvall 7631369Sdduvall /* 7641369Sdduvall * NIC on-chip memory access routines 7651369Sdduvall * 7661369Sdduvall * Only 32K of NIC memory is visible at a time, controlled by the 7671369Sdduvall * Memory Window Base Address Register (in PCI config space). Once 7681369Sdduvall * this is set, the 32K region of NIC-local memory that it refers 7691369Sdduvall * to can be directly addressed in the upper 32K of the 64K of PCI 7701369Sdduvall * memory space used for the device. 7711369Sdduvall */ 7721369Sdduvall 7731369Sdduvall static void bge_nic_setwin(bge_t *bgep, bge_regno_t base); 7741369Sdduvall #pragma inline(bge_nic_setwin) 7751369Sdduvall 7761369Sdduvall static void 7771369Sdduvall bge_nic_setwin(bge_t *bgep, bge_regno_t base) 7781369Sdduvall { 7792073Svivek chip_id_t *cidp; 7802073Svivek 7811369Sdduvall BGE_TRACE(("bge_nic_setwin($%p, 0x%lx)", 7824588Sml149210 (void *)bgep, base)); 7831369Sdduvall 7841369Sdduvall ASSERT((base & MWBAR_GRANULE_MASK) == 0); 7852073Svivek 7862073Svivek /* 7872073Svivek * Don't do repeated zero data writes, 7882073Svivek * if the device is BCM5714C/15C. 7892073Svivek */ 7902073Svivek cidp = &bgep->chipid; 7912073Svivek if ((cidp->device == DEVICE_ID_5714C) || 7924588Sml149210 (cidp->device == DEVICE_ID_5715C)) { 7932073Svivek if (bgep->lastWriteZeroData && (base == (bge_regno_t)0)) 7942073Svivek return; 7952073Svivek /* Adjust lastWriteZeroData */ 7962073Svivek bgep->lastWriteZeroData = ((base == (bge_regno_t)0) ? 7974588Sml149210 B_TRUE : B_FALSE); 7982073Svivek } 7991369Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, base); 8001369Sdduvall } 8011369Sdduvall 8021369Sdduvall static uint32_t bge_nic_get32(bge_t *bgep, bge_regno_t addr); 8031369Sdduvall #pragma inline(bge_nic_get32) 8041369Sdduvall 8051369Sdduvall static uint32_t 8061369Sdduvall bge_nic_get32(bge_t *bgep, bge_regno_t addr) 8071369Sdduvall { 8081369Sdduvall uint32_t data; 8091369Sdduvall 8103918Sml149210 #if defined(BGE_IPMI_ASF) && !defined(__sparc) 8111408Srandyf if (bgep->asf_enabled && !bgep->asf_wordswapped) { 8121408Srandyf /* workaround for word swap error */ 8131408Srandyf if (addr & 4) 8141408Srandyf addr = addr - 4; 8151408Srandyf else 8161408Srandyf addr = addr + 4; 8171408Srandyf } 8181408Srandyf #endif 8191408Srandyf 8203918Sml149210 #ifdef __sparc 8213918Sml149210 data = bge_nic_read32(bgep, addr); 8223918Sml149210 #else 8231369Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 8241369Sdduvall addr &= MWBAR_GRANULE_MASK; 8251369Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 8261369Sdduvall 8271369Sdduvall data = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, addr)); 8283918Sml149210 #endif 8291369Sdduvall 8301369Sdduvall BGE_TRACE(("bge_nic_get32($%p, 0x%lx) = 0x%08x", 8314588Sml149210 (void *)bgep, addr, data)); 8321369Sdduvall 8331369Sdduvall return (data); 8341369Sdduvall } 8351369Sdduvall 8361408Srandyf void bge_nic_put32(bge_t *bgep, bge_regno_t addr, uint32_t data); 8371408Srandyf #pragma inline(bge_nic_put32) 8381408Srandyf 8391408Srandyf void 8401369Sdduvall bge_nic_put32(bge_t *bgep, bge_regno_t addr, uint32_t data) 8411369Sdduvall { 8421369Sdduvall BGE_TRACE(("bge_nic_put32($%p, 0x%lx, 0x%08x)", 8434588Sml149210 (void *)bgep, addr, data)); 8441369Sdduvall 8453918Sml149210 #if defined(BGE_IPMI_ASF) && !defined(__sparc) 8461408Srandyf if (bgep->asf_enabled && !bgep->asf_wordswapped) { 8471408Srandyf /* workaround for word swap error */ 8481408Srandyf if (addr & 4) 8491408Srandyf addr = addr - 4; 8501408Srandyf else 8511408Srandyf addr = addr + 4; 8521408Srandyf } 8531408Srandyf #endif 8541408Srandyf 8553918Sml149210 #ifdef __sparc 8563918Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, addr); 8573918Sml149210 data = LE_32(data); 8583918Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWDAR, data); 8593918Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, 0); 8603918Sml149210 #else 8611369Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 8621369Sdduvall addr &= MWBAR_GRANULE_MASK; 8631369Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 8641369Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr), data); 8651369Sdduvall BGE_PCICHK(bgep); 8663918Sml149210 #endif 8671369Sdduvall } 8681369Sdduvall 8691369Sdduvall static uint64_t bge_nic_get64(bge_t *bgep, bge_regno_t addr); 8701369Sdduvall #pragma inline(bge_nic_get64) 8711369Sdduvall 8721369Sdduvall static uint64_t 8731369Sdduvall bge_nic_get64(bge_t *bgep, bge_regno_t addr) 8741369Sdduvall { 8751369Sdduvall uint64_t data; 8761369Sdduvall 8771369Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 8781369Sdduvall addr &= MWBAR_GRANULE_MASK; 8791369Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 8801369Sdduvall 8811369Sdduvall #ifdef __amd64 8821369Sdduvall if (bge_get_em64t_type()) { 8831369Sdduvall data = ddi_get32(bgep->io_handle, PIO_ADDR(bgep, addr)); 8841369Sdduvall data <<= 32; 8851369Sdduvall data |= ddi_get32(bgep->io_handle, 8864588Sml149210 PIO_ADDR(bgep, addr + 4)); 8871369Sdduvall } else { 8881369Sdduvall data = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, addr)); 8891369Sdduvall } 8901369Sdduvall #else 8911369Sdduvall data = ddi_get64(bgep->io_handle, PIO_ADDR(bgep, addr)); 8921369Sdduvall #endif 8931369Sdduvall 8941369Sdduvall BGE_TRACE(("bge_nic_get64($%p, 0x%lx) = 0x%016llx", 8954588Sml149210 (void *)bgep, addr, data)); 8961369Sdduvall 8971369Sdduvall return (data); 8981369Sdduvall } 8991369Sdduvall 9001369Sdduvall static void bge_nic_put64(bge_t *bgep, bge_regno_t addr, uint64_t data); 9011369Sdduvall #pragma inline(bge_nic_put64) 9021369Sdduvall 9031369Sdduvall static void 9041369Sdduvall bge_nic_put64(bge_t *bgep, bge_regno_t addr, uint64_t data) 9051369Sdduvall { 9061369Sdduvall BGE_TRACE(("bge_nic_put64($%p, 0x%lx, 0x%016llx)", 9074588Sml149210 (void *)bgep, addr, data)); 9081369Sdduvall 9091369Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 9101369Sdduvall addr &= MWBAR_GRANULE_MASK; 9111369Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 9121369Sdduvall 9131369Sdduvall #ifdef __amd64 9141369Sdduvall if (bge_get_em64t_type()) { 9151369Sdduvall ddi_put32(bgep->io_handle, 9164588Sml149210 PIO_ADDR(bgep, addr), (uint32_t)data); 9171369Sdduvall BGE_PCICHK(bgep); 9181369Sdduvall ddi_put32(bgep->io_handle, 9194588Sml149210 PIO_ADDR(bgep, addr + 4), (uint32_t)(data >> 32)); 9201369Sdduvall } else { 9211369Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), data); 9221369Sdduvall } 9231369Sdduvall #else 9241369Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), data); 9251369Sdduvall #endif 9261369Sdduvall 9271369Sdduvall BGE_PCICHK(bgep); 9281369Sdduvall } 9291369Sdduvall 9301369Sdduvall /* 9311369Sdduvall * The DDI doesn't provide get/put functions for 128 bit data 9321369Sdduvall * so we put RCBs out as two 64-bit chunks instead. 9331369Sdduvall */ 9341369Sdduvall static void bge_nic_putrcb(bge_t *bgep, bge_regno_t addr, bge_rcb_t *rcbp); 9351369Sdduvall #pragma inline(bge_nic_putrcb) 9361369Sdduvall 9371369Sdduvall static void 9381369Sdduvall bge_nic_putrcb(bge_t *bgep, bge_regno_t addr, bge_rcb_t *rcbp) 9391369Sdduvall { 9401369Sdduvall uint64_t *p; 9411369Sdduvall 9421369Sdduvall BGE_TRACE(("bge_nic_putrcb($%p, 0x%lx, 0x%016llx:%04x:%04x:%08x)", 9434588Sml149210 (void *)bgep, addr, rcbp->host_ring_addr, 9444588Sml149210 rcbp->max_len, rcbp->flags, rcbp->nic_ring_addr)); 9451369Sdduvall 9461369Sdduvall ASSERT((addr % sizeof (*rcbp)) == 0); 9471369Sdduvall 9481369Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 9491369Sdduvall addr &= MWBAR_GRANULE_MASK; 9501369Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 9511369Sdduvall 9521369Sdduvall p = (void *)rcbp; 9531369Sdduvall #ifdef __amd64 9541369Sdduvall if (bge_get_em64t_type()) { 9551369Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr), 9564588Sml149210 (uint32_t)(*p)); 9571369Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr + 4), 9584588Sml149210 (uint32_t)(*p >> 32)); 9591369Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr + 8), 9604588Sml149210 (uint32_t)(*(p + 1))); 9611369Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, addr + 12), 9624588Sml149210 (uint32_t)(*p >> 32)); 9631369Sdduvall 9641369Sdduvall } else { 9651369Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), *p++); 9661369Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr+8), *p); 9671369Sdduvall } 9681369Sdduvall #else 9691369Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr), *p++); 9701369Sdduvall ddi_put64(bgep->io_handle, PIO_ADDR(bgep, addr + 8), *p); 9711369Sdduvall #endif 9721369Sdduvall 9731369Sdduvall BGE_PCICHK(bgep); 9741369Sdduvall } 9751369Sdduvall 9761369Sdduvall static void bge_nic_zero(bge_t *bgep, bge_regno_t addr, uint32_t nbytes); 9771369Sdduvall #pragma inline(bge_nic_zero) 9781369Sdduvall 9791369Sdduvall static void 9801369Sdduvall bge_nic_zero(bge_t *bgep, bge_regno_t addr, uint32_t nbytes) 9811369Sdduvall { 9821369Sdduvall BGE_TRACE(("bge_nic_zero($%p, 0x%lx, 0x%x)", 9834588Sml149210 (void *)bgep, addr, nbytes)); 9841369Sdduvall 9851369Sdduvall ASSERT((addr & ~MWBAR_GRANULE_MASK) == 9864588Sml149210 ((addr+nbytes) & ~MWBAR_GRANULE_MASK)); 9871369Sdduvall 9881369Sdduvall bge_nic_setwin(bgep, addr & ~MWBAR_GRANULE_MASK); 9891369Sdduvall addr &= MWBAR_GRANULE_MASK; 9901369Sdduvall addr += NIC_MEM_WINDOW_OFFSET; 9911369Sdduvall 9921369Sdduvall (void) ddi_device_zero(bgep->io_handle, PIO_ADDR(bgep, addr), 9934588Sml149210 nbytes, 1, DDI_DATA_SZ08_ACC); 9941369Sdduvall BGE_PCICHK(bgep); 9951369Sdduvall } 9961369Sdduvall 9971369Sdduvall /* 9981369Sdduvall * MII (PHY) register get/set access routines 9991369Sdduvall * 10001369Sdduvall * These use the chip's MII auto-access method, controlled by the 10011369Sdduvall * MII Communication register at 0x044c, so the CPU doesn't have 10021369Sdduvall * to fiddle with the individual bits. 10031369Sdduvall */ 10041369Sdduvall 10051369Sdduvall #undef BGE_DBG 10061369Sdduvall #define BGE_DBG BGE_DBG_MII /* debug flag for this code */ 10071369Sdduvall 10081369Sdduvall static uint16_t bge_mii_access(bge_t *bgep, bge_regno_t regno, 10091369Sdduvall uint16_t data, uint32_t cmd); 10101369Sdduvall #pragma no_inline(bge_mii_access) 10111369Sdduvall 10121369Sdduvall static uint16_t 10131369Sdduvall bge_mii_access(bge_t *bgep, bge_regno_t regno, uint16_t data, uint32_t cmd) 10141369Sdduvall { 10151369Sdduvall uint32_t timeout; 10161369Sdduvall uint32_t regval1; 10171369Sdduvall uint32_t regval2; 10181369Sdduvall 10191369Sdduvall BGE_TRACE(("bge_mii_access($%p, 0x%lx, 0x%x, 0x%x)", 10204588Sml149210 (void *)bgep, regno, data, cmd)); 10211369Sdduvall 10221369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 10231369Sdduvall 10241369Sdduvall /* 10251369Sdduvall * Assemble the command ... 10261369Sdduvall */ 10271369Sdduvall cmd |= data << MI_COMMS_DATA_SHIFT; 10281369Sdduvall cmd |= regno << MI_COMMS_REGISTER_SHIFT; 10291369Sdduvall cmd |= bgep->phy_mii_addr << MI_COMMS_ADDRESS_SHIFT; 10301369Sdduvall cmd |= MI_COMMS_START; 10311369Sdduvall 10321369Sdduvall /* 10331369Sdduvall * Wait for any command already in progress ... 10341369Sdduvall * 10351369Sdduvall * Note: this *shouldn't* ever find that there is a command 10361369Sdduvall * in progress, because we already hold the <genlock> mutex. 10371369Sdduvall * Nonetheless, we have sometimes seen the MI_COMMS_START 10381369Sdduvall * bit set here -- it seems that the chip can initiate MII 10391369Sdduvall * accesses internally, even with polling OFF. 10401369Sdduvall */ 10411369Sdduvall regval1 = regval2 = bge_reg_get32(bgep, MI_COMMS_REG); 10421865Sdilpreet for (timeout = 100; ; ) { 10431369Sdduvall if ((regval2 & MI_COMMS_START) == 0) { 10441369Sdduvall bge_reg_put32(bgep, MI_COMMS_REG, cmd); 10451369Sdduvall break; 10461369Sdduvall } 10471369Sdduvall if (--timeout == 0) 10481369Sdduvall break; 10491369Sdduvall drv_usecwait(10); 10501369Sdduvall regval2 = bge_reg_get32(bgep, MI_COMMS_REG); 10511369Sdduvall } 10521369Sdduvall 10531865Sdilpreet if (timeout == 0) 10541865Sdilpreet return ((uint16_t)~0u); 10551865Sdilpreet 10561865Sdilpreet if (timeout != 100) 10571369Sdduvall BGE_REPORT((bgep, "bge_mii_access: cmd 0x%x -- " 10584588Sml149210 "MI_COMMS_START set for %d us; 0x%x->0x%x", 10594588Sml149210 cmd, 10*(100-timeout), regval1, regval2)); 10601369Sdduvall 10611369Sdduvall regval1 = bge_reg_get32(bgep, MI_COMMS_REG); 10621369Sdduvall for (timeout = 1000; ; ) { 10631369Sdduvall if ((regval1 & MI_COMMS_START) == 0) 10641369Sdduvall break; 10651369Sdduvall if (--timeout == 0) 10661369Sdduvall break; 10671369Sdduvall drv_usecwait(10); 10681369Sdduvall regval1 = bge_reg_get32(bgep, MI_COMMS_REG); 10691369Sdduvall } 10701369Sdduvall 10711369Sdduvall /* 10721369Sdduvall * Drop out early if the READ FAILED bit is set -- this chip 10731369Sdduvall * could be a 5703/4S, with a SerDes instead of a PHY! 10741369Sdduvall */ 10751369Sdduvall if (regval2 & MI_COMMS_READ_FAILED) 10761369Sdduvall return ((uint16_t)~0u); 10771369Sdduvall 10781369Sdduvall if (timeout == 0) 10791369Sdduvall return ((uint16_t)~0u); 10801369Sdduvall 10811369Sdduvall /* 10821369Sdduvall * The PRM says to wait 5us after seeing the START bit clear 10831369Sdduvall * and then re-read the register to get the final value of the 10841369Sdduvall * data field, in order to avoid a race condition where the 10851369Sdduvall * START bit is clear but the data field isn't yet valid. 10861369Sdduvall * 10871369Sdduvall * Note: we don't actually seem to be encounter this race; 10881369Sdduvall * except when the START bit is seen set again (see below), 10891369Sdduvall * the data field doesn't change during this 5us interval. 10901369Sdduvall */ 10911369Sdduvall drv_usecwait(5); 10921369Sdduvall regval2 = bge_reg_get32(bgep, MI_COMMS_REG); 10931369Sdduvall 10941369Sdduvall /* 10951369Sdduvall * Unfortunately, when following the PRMs instructions above, 10961369Sdduvall * we have occasionally seen the START bit set again(!) in the 10971369Sdduvall * value read after the 5us delay. This seems to be due to the 10981369Sdduvall * chip autonomously starting another MII access internally. 10991369Sdduvall * In such cases, the command/data/etc fields relate to the 11001369Sdduvall * internal command, rather than the one that we thought had 11011369Sdduvall * just finished. So in this case, we fall back to returning 11021369Sdduvall * the data from the original read that showed START clear. 11031369Sdduvall */ 11041369Sdduvall if (regval2 & MI_COMMS_START) { 11051369Sdduvall BGE_REPORT((bgep, "bge_mii_access: cmd 0x%x -- " 11064588Sml149210 "MI_COMMS_START set after transaction; 0x%x->0x%x", 11074588Sml149210 cmd, regval1, regval2)); 11081369Sdduvall regval2 = regval1; 11091369Sdduvall } 11101369Sdduvall 11111369Sdduvall if (regval2 & MI_COMMS_START) 11121369Sdduvall return ((uint16_t)~0u); 11131369Sdduvall 11141369Sdduvall if (regval2 & MI_COMMS_READ_FAILED) 11151369Sdduvall return ((uint16_t)~0u); 11161369Sdduvall 11171369Sdduvall return ((regval2 & MI_COMMS_DATA_MASK) >> MI_COMMS_DATA_SHIFT); 11181369Sdduvall } 11191369Sdduvall 11201369Sdduvall uint16_t bge_mii_get16(bge_t *bgep, bge_regno_t regno); 11211369Sdduvall #pragma no_inline(bge_mii_get16) 11221369Sdduvall 11231369Sdduvall uint16_t 11241369Sdduvall bge_mii_get16(bge_t *bgep, bge_regno_t regno) 11251369Sdduvall { 11261369Sdduvall BGE_TRACE(("bge_mii_get16($%p, 0x%lx)", 11274588Sml149210 (void *)bgep, regno)); 11281369Sdduvall 11291369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 11301369Sdduvall 1131*7678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep) && ((regno == MII_AUX_CONTROL) || 1132*7678SYong.Tan@Sun.COM (regno == MII_1000BASE_T_CONTROL))) 1133*7678SYong.Tan@Sun.COM return (0); 1134*7678SYong.Tan@Sun.COM 11351369Sdduvall return (bge_mii_access(bgep, regno, 0, MI_COMMS_COMMAND_READ)); 11361369Sdduvall } 11371369Sdduvall 11381369Sdduvall void bge_mii_put16(bge_t *bgep, bge_regno_t regno, uint16_t data); 11391369Sdduvall #pragma no_inline(bge_mii_put16) 11401369Sdduvall 11411369Sdduvall void 11421369Sdduvall bge_mii_put16(bge_t *bgep, bge_regno_t regno, uint16_t data) 11431369Sdduvall { 11441369Sdduvall BGE_TRACE(("bge_mii_put16($%p, 0x%lx, 0x%x)", 11454588Sml149210 (void *)bgep, regno, data)); 11461369Sdduvall 11471369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 11481369Sdduvall 1149*7678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep) && ((regno == MII_AUX_CONTROL) || 1150*7678SYong.Tan@Sun.COM (regno == MII_1000BASE_T_CONTROL))) 1151*7678SYong.Tan@Sun.COM return; 1152*7678SYong.Tan@Sun.COM 11531369Sdduvall (void) bge_mii_access(bgep, regno, data, MI_COMMS_COMMAND_WRITE); 11541369Sdduvall } 11551369Sdduvall 11561369Sdduvall #undef BGE_DBG 11571369Sdduvall #define BGE_DBG BGE_DBG_SEEPROM /* debug flag for this code */ 11581369Sdduvall 11591369Sdduvall #if BGE_SEE_IO32 || BGE_FLASH_IO32 11601369Sdduvall 11611369Sdduvall /* 11621369Sdduvall * Basic SEEPROM get/set access routine 11631369Sdduvall * 11641369Sdduvall * This uses the chip's SEEPROM auto-access method, controlled by the 11651369Sdduvall * Serial EEPROM Address/Data Registers at 0x6838/683c, so the CPU 11661369Sdduvall * doesn't have to fiddle with the individual bits. 11671369Sdduvall * 11681369Sdduvall * The caller should hold <genlock> and *also* have already acquired 11691369Sdduvall * the right to access the SEEPROM, via bge_nvmem_acquire() above. 11701369Sdduvall * 11711369Sdduvall * Return value: 11721369Sdduvall * 0 on success, 11731369Sdduvall * ENODATA on access timeout (maybe retryable: device may just be busy) 11741369Sdduvall * EPROTO on other h/w or s/w errors. 11751369Sdduvall * 11761369Sdduvall * <*dp> is an input to a SEEPROM_ACCESS_WRITE operation, or an output 11771369Sdduvall * from a (successful) SEEPROM_ACCESS_READ. 11781369Sdduvall */ 11791369Sdduvall static int bge_seeprom_access(bge_t *bgep, uint32_t cmd, bge_regno_t addr, 11801369Sdduvall uint32_t *dp); 11811369Sdduvall #pragma no_inline(bge_seeprom_access) 11821369Sdduvall 11831369Sdduvall static int 11841369Sdduvall bge_seeprom_access(bge_t *bgep, uint32_t cmd, bge_regno_t addr, uint32_t *dp) 11851369Sdduvall { 11861369Sdduvall uint32_t tries; 11871369Sdduvall uint32_t regval; 11881369Sdduvall 11891369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 11901369Sdduvall 11911369Sdduvall /* 11921369Sdduvall * On the newer chips that support both SEEPROM & Flash, we need 11931369Sdduvall * to specifically enable SEEPROM access (Flash is the default). 11941369Sdduvall * On older chips, we don't; SEEPROM is the only NVtype supported, 11951369Sdduvall * and the NVM control registers don't exist ... 11961369Sdduvall */ 11971369Sdduvall switch (bgep->chipid.nvtype) { 11981369Sdduvall case BGE_NVTYPE_NONE: 11991369Sdduvall case BGE_NVTYPE_UNKNOWN: 12001369Sdduvall _NOTE(NOTREACHED) 12011369Sdduvall case BGE_NVTYPE_SEEPROM: 12021369Sdduvall break; 12031369Sdduvall 12041369Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 12051369Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 12061369Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 12071369Sdduvall default: 12081369Sdduvall bge_reg_set32(bgep, NVM_CONFIG1_REG, 12094588Sml149210 NVM_CFG1_LEGACY_SEEPROM_MODE); 12101369Sdduvall break; 12111369Sdduvall } 12121369Sdduvall 12131369Sdduvall /* 12141369Sdduvall * Check there's no command in progress. 12151369Sdduvall * 12161369Sdduvall * Note: this *shouldn't* ever find that there is a command 12171369Sdduvall * in progress, because we already hold the <genlock> mutex. 12181369Sdduvall * Also, to ensure we don't have a conflict with the chip's 12191369Sdduvall * internal firmware or a process accessing the same (shared) 12201369Sdduvall * SEEPROM through the other port of a 5704, we've already 12211369Sdduvall * been through the "software arbitration" protocol. 12221369Sdduvall * So this is just a final consistency check: we shouldn't 12231369Sdduvall * see EITHER the START bit (command started but not complete) 12241369Sdduvall * OR the COMPLETE bit (command completed but not cleared). 12251369Sdduvall */ 12261369Sdduvall regval = bge_reg_get32(bgep, SERIAL_EEPROM_ADDRESS_REG); 12271369Sdduvall if (regval & SEEPROM_ACCESS_START) 12281369Sdduvall return (EPROTO); 12291369Sdduvall if (regval & SEEPROM_ACCESS_COMPLETE) 12301369Sdduvall return (EPROTO); 12311369Sdduvall 12321369Sdduvall /* 12331369Sdduvall * Assemble the command ... 12341369Sdduvall */ 12351369Sdduvall cmd |= addr & SEEPROM_ACCESS_ADDRESS_MASK; 12361369Sdduvall addr >>= SEEPROM_ACCESS_ADDRESS_SIZE; 12371369Sdduvall addr <<= SEEPROM_ACCESS_DEVID_SHIFT; 12381369Sdduvall cmd |= addr & SEEPROM_ACCESS_DEVID_MASK; 12391369Sdduvall cmd |= SEEPROM_ACCESS_START; 12401369Sdduvall cmd |= SEEPROM_ACCESS_COMPLETE; 12411369Sdduvall cmd |= regval & SEEPROM_ACCESS_HALFCLOCK_MASK; 12421369Sdduvall 12431369Sdduvall bge_reg_put32(bgep, SERIAL_EEPROM_DATA_REG, *dp); 12441369Sdduvall bge_reg_put32(bgep, SERIAL_EEPROM_ADDRESS_REG, cmd); 12451369Sdduvall 12461369Sdduvall /* 12471369Sdduvall * By observation, a successful access takes ~20us on a 5703/4, 12481369Sdduvall * but apparently much longer (up to 1000us) on the obsolescent 12491369Sdduvall * BCM5700/BCM5701. We want to be sure we don't get any false 12501369Sdduvall * timeouts here; but OTOH, we don't want a bogus access to lock 12511369Sdduvall * out interrupts for longer than necessary. So we'll allow up 12521369Sdduvall * to 1000us ... 12531369Sdduvall */ 12541369Sdduvall for (tries = 0; tries < 1000; ++tries) { 12551369Sdduvall regval = bge_reg_get32(bgep, SERIAL_EEPROM_ADDRESS_REG); 12561369Sdduvall if (regval & SEEPROM_ACCESS_COMPLETE) 12571369Sdduvall break; 12581369Sdduvall drv_usecwait(1); 12591369Sdduvall } 12601369Sdduvall 12611369Sdduvall if (regval & SEEPROM_ACCESS_COMPLETE) { 12621369Sdduvall /* 12631369Sdduvall * All OK; read the SEEPROM data register, then write back 12641369Sdduvall * the value read from the address register in order to 12651369Sdduvall * clear the <complete> bit and leave the SEEPROM access 12661369Sdduvall * state machine idle, ready for the next access ... 12671369Sdduvall */ 12681369Sdduvall BGE_DEBUG(("bge_seeprom_access: complete after %d us", tries)); 12691369Sdduvall *dp = bge_reg_get32(bgep, SERIAL_EEPROM_DATA_REG); 12701369Sdduvall bge_reg_put32(bgep, SERIAL_EEPROM_ADDRESS_REG, regval); 12711369Sdduvall return (0); 12721369Sdduvall } 12731369Sdduvall 12741369Sdduvall /* 12751369Sdduvall * Hmm ... what happened here? 12761369Sdduvall * 12772135Szh199473 * Most likely, the user addressed a non-existent SEEPROM. Or 12781369Sdduvall * maybe the SEEPROM was busy internally (e.g. processing a write) 12791369Sdduvall * and didn't respond to being addressed. Either way, it's left 12801369Sdduvall * the SEEPROM access state machine wedged. So we'll reset it 12811369Sdduvall * before we leave, so it's ready for next time ... 12821369Sdduvall */ 12831369Sdduvall BGE_DEBUG(("bge_seeprom_access: timed out after %d us", tries)); 12841369Sdduvall bge_reg_set32(bgep, SERIAL_EEPROM_ADDRESS_REG, SEEPROM_ACCESS_INIT); 12851369Sdduvall return (ENODATA); 12861369Sdduvall } 12871369Sdduvall 12881369Sdduvall /* 12891369Sdduvall * Basic Flash get/set access routine 12901369Sdduvall * 12911369Sdduvall * These use the chip's Flash auto-access method, controlled by the 12921369Sdduvall * Flash Access Registers at 0x7000-701c, so the CPU doesn't have to 12931369Sdduvall * fiddle with the individual bits. 12941369Sdduvall * 12951369Sdduvall * The caller should hold <genlock> and *also* have already acquired 12961369Sdduvall * the right to access the Flash, via bge_nvmem_acquire() above. 12971369Sdduvall * 12981369Sdduvall * Return value: 12991369Sdduvall * 0 on success, 13001369Sdduvall * ENODATA on access timeout (maybe retryable: device may just be busy) 13011369Sdduvall * ENODEV if the NVmem device is missing or otherwise unusable 13021369Sdduvall * 13031369Sdduvall * <*dp> is an input to a NVM_FLASH_CMD_WR operation, or an output 13041369Sdduvall * from a (successful) NVM_FLASH_CMD_RD. 13051369Sdduvall */ 13061369Sdduvall static int bge_flash_access(bge_t *bgep, uint32_t cmd, bge_regno_t addr, 13071369Sdduvall uint32_t *dp); 13081369Sdduvall #pragma no_inline(bge_flash_access) 13091369Sdduvall 13101369Sdduvall static int 13111369Sdduvall bge_flash_access(bge_t *bgep, uint32_t cmd, bge_regno_t addr, uint32_t *dp) 13121369Sdduvall { 13131369Sdduvall uint32_t tries; 13141369Sdduvall uint32_t regval; 13151369Sdduvall 13161369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 13171369Sdduvall 13181369Sdduvall /* 13191369Sdduvall * On the newer chips that support both SEEPROM & Flash, we need 13201369Sdduvall * to specifically disable SEEPROM access while accessing Flash. 13211369Sdduvall * The older chips don't support Flash, and the NVM registers don't 13221369Sdduvall * exist, so we shouldn't be here at all! 13231369Sdduvall */ 13241369Sdduvall switch (bgep->chipid.nvtype) { 13251369Sdduvall case BGE_NVTYPE_NONE: 13261369Sdduvall case BGE_NVTYPE_UNKNOWN: 13271369Sdduvall _NOTE(NOTREACHED) 13281369Sdduvall case BGE_NVTYPE_SEEPROM: 13291369Sdduvall return (ENODEV); 13301369Sdduvall 13311369Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 13321369Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 13331369Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 13341369Sdduvall default: 13351369Sdduvall bge_reg_clr32(bgep, NVM_CONFIG1_REG, 13364588Sml149210 NVM_CFG1_LEGACY_SEEPROM_MODE); 13371369Sdduvall break; 13381369Sdduvall } 13391369Sdduvall 13401369Sdduvall /* 13411369Sdduvall * Assemble the command ... 13421369Sdduvall */ 13431369Sdduvall addr &= NVM_FLASH_ADDR_MASK; 13441369Sdduvall cmd |= NVM_FLASH_CMD_DOIT; 13451369Sdduvall cmd |= NVM_FLASH_CMD_FIRST; 13461369Sdduvall cmd |= NVM_FLASH_CMD_LAST; 13471369Sdduvall cmd |= NVM_FLASH_CMD_DONE; 13481369Sdduvall 13491369Sdduvall bge_reg_put32(bgep, NVM_FLASH_WRITE_REG, *dp); 13501369Sdduvall bge_reg_put32(bgep, NVM_FLASH_ADDR_REG, addr); 13511369Sdduvall bge_reg_put32(bgep, NVM_FLASH_CMD_REG, cmd); 13521369Sdduvall 13531369Sdduvall /* 13541369Sdduvall * Allow up to 1000ms ... 13551369Sdduvall */ 13561369Sdduvall for (tries = 0; tries < 1000; ++tries) { 13571369Sdduvall regval = bge_reg_get32(bgep, NVM_FLASH_CMD_REG); 13581369Sdduvall if (regval & NVM_FLASH_CMD_DONE) 13591369Sdduvall break; 13601369Sdduvall drv_usecwait(1); 13611369Sdduvall } 13621369Sdduvall 13631369Sdduvall if (regval & NVM_FLASH_CMD_DONE) { 13641369Sdduvall /* 13651369Sdduvall * All OK; read the data from the Flash read register 13661369Sdduvall */ 13671369Sdduvall BGE_DEBUG(("bge_flash_access: complete after %d us", tries)); 13681369Sdduvall *dp = bge_reg_get32(bgep, NVM_FLASH_READ_REG); 13691369Sdduvall return (0); 13701369Sdduvall } 13711369Sdduvall 13721369Sdduvall /* 13731369Sdduvall * Hmm ... what happened here? 13741369Sdduvall * 13752135Szh199473 * Most likely, the user addressed a non-existent Flash. Or 13761369Sdduvall * maybe the Flash was busy internally (e.g. processing a write) 13771369Sdduvall * and didn't respond to being addressed. Either way, there's 13781369Sdduvall * nothing we can here ... 13791369Sdduvall */ 13801369Sdduvall BGE_DEBUG(("bge_flash_access: timed out after %d us", tries)); 13811369Sdduvall return (ENODATA); 13821369Sdduvall } 13831369Sdduvall 13841369Sdduvall /* 13851369Sdduvall * The next two functions regulate access to the NVram (if fitted). 13861369Sdduvall * 13871369Sdduvall * On a 5704 (dual core) chip, there's only one SEEPROM and one Flash 13881369Sdduvall * (SPI) interface, but they can be accessed through either port. These 13891369Sdduvall * are managed by different instance of this driver and have no software 13901369Sdduvall * state in common. 13911369Sdduvall * 13921369Sdduvall * In addition (and even on a single core chip) the chip's internal 13931369Sdduvall * firmware can access the SEEPROM/Flash, most notably after a RESET 13941369Sdduvall * when it may download code to run internally. 13951369Sdduvall * 13961369Sdduvall * So we need to arbitrate between these various software agents. For 13971369Sdduvall * this purpose, the chip provides the Software Arbitration Register, 13981369Sdduvall * which implements hardware(!) arbitration. 13991369Sdduvall * 14001369Sdduvall * This functionality didn't exist on older (5700/5701) chips, so there's 14011369Sdduvall * nothing we can do by way of arbitration on those; also, if there's no 14021369Sdduvall * SEEPROM/Flash fitted (or we couldn't determine what type), there's also 14031369Sdduvall * nothing to do. 14041369Sdduvall * 14051369Sdduvall * The internal firmware appears to use Request 0, which is the highest 14061369Sdduvall * priority. So we'd like to use Request 2, leaving one higher and one 14071369Sdduvall * lower for any future developments ... but apparently this doesn't 14081369Sdduvall * always work. So for now, the code uses Request 1 ;-( 14091369Sdduvall */ 14101369Sdduvall 14111369Sdduvall #define NVM_READ_REQ NVM_READ_REQ1 14121369Sdduvall #define NVM_RESET_REQ NVM_RESET_REQ1 14131369Sdduvall #define NVM_SET_REQ NVM_SET_REQ1 14141369Sdduvall 14151369Sdduvall static void bge_nvmem_relinquish(bge_t *bgep); 14161369Sdduvall #pragma no_inline(bge_nvmem_relinquish) 14171369Sdduvall 14181369Sdduvall static void 14191369Sdduvall bge_nvmem_relinquish(bge_t *bgep) 14201369Sdduvall { 14211369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 14221369Sdduvall 14231369Sdduvall switch (bgep->chipid.nvtype) { 14241369Sdduvall case BGE_NVTYPE_NONE: 14251369Sdduvall case BGE_NVTYPE_UNKNOWN: 14261369Sdduvall _NOTE(NOTREACHED) 14271369Sdduvall return; 14281369Sdduvall 14291369Sdduvall case BGE_NVTYPE_SEEPROM: 14301369Sdduvall /* 14311369Sdduvall * No arbitration performed, no release needed 14321369Sdduvall */ 14331369Sdduvall return; 14341369Sdduvall 14351369Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 14361369Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 14371369Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 14381369Sdduvall default: 14391369Sdduvall break; 14401369Sdduvall } 14411369Sdduvall 14421369Sdduvall /* 14431369Sdduvall * Our own request should be present (whether or not granted) ... 14441369Sdduvall */ 14451865Sdilpreet (void) bge_reg_get32(bgep, NVM_SW_ARBITRATION_REG); 14461369Sdduvall 14471369Sdduvall /* 14481369Sdduvall * ... this will make it go away. 14491369Sdduvall */ 14501369Sdduvall bge_reg_put32(bgep, NVM_SW_ARBITRATION_REG, NVM_RESET_REQ); 14511865Sdilpreet (void) bge_reg_get32(bgep, NVM_SW_ARBITRATION_REG); 14521369Sdduvall } 14531369Sdduvall 14541369Sdduvall /* 14551369Sdduvall * Arbitrate for access to the NVmem, if necessary 14561369Sdduvall * 14571369Sdduvall * Return value: 14581369Sdduvall * 0 on success 14591369Sdduvall * EAGAIN if the device is in use (retryable) 14601369Sdduvall * ENODEV if the NVmem device is missing or otherwise unusable 14611369Sdduvall */ 14621369Sdduvall static int bge_nvmem_acquire(bge_t *bgep); 14631369Sdduvall #pragma no_inline(bge_nvmem_acquire) 14641369Sdduvall 14651369Sdduvall static int 14661369Sdduvall bge_nvmem_acquire(bge_t *bgep) 14671369Sdduvall { 14681369Sdduvall uint32_t regval; 14691369Sdduvall uint32_t tries; 14701369Sdduvall 14711369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 14721369Sdduvall 14731369Sdduvall switch (bgep->chipid.nvtype) { 14741369Sdduvall case BGE_NVTYPE_NONE: 14751369Sdduvall case BGE_NVTYPE_UNKNOWN: 14761369Sdduvall /* 14771369Sdduvall * Access denied: no (recognisable) device fitted 14781369Sdduvall */ 14791369Sdduvall return (ENODEV); 14801369Sdduvall 14811369Sdduvall case BGE_NVTYPE_SEEPROM: 14821369Sdduvall /* 14831369Sdduvall * Access granted: no arbitration needed (or possible) 14841369Sdduvall */ 14851369Sdduvall return (0); 14861369Sdduvall 14871369Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 14881369Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 14891369Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 14901369Sdduvall default: 14911369Sdduvall /* 14921369Sdduvall * Access conditional: conduct arbitration protocol 14931369Sdduvall */ 14941369Sdduvall break; 14951369Sdduvall } 14961369Sdduvall 14971369Sdduvall /* 14981369Sdduvall * We're holding the per-port mutex <genlock>, so no-one other 14992135Szh199473 * thread can be attempting to access the NVmem through *this* 15001369Sdduvall * port. But it could be in use by the *other* port (of a 5704), 15011369Sdduvall * or by the chip's internal firmware, so we have to go through 15021369Sdduvall * the full (hardware) arbitration protocol ... 15031369Sdduvall * 15041369Sdduvall * Note that *because* we're holding <genlock>, the interrupt handler 15051369Sdduvall * won't be able to progress. So we're only willing to spin for a 15061369Sdduvall * fairly short time. Specifically: 15071369Sdduvall * 15081369Sdduvall * We *must* wait long enough for the hardware to resolve all 15091369Sdduvall * requests and determine the winner. Fortunately, this is 15101369Sdduvall * "almost instantaneous", even as observed by GHz CPUs. 15111369Sdduvall * 15121369Sdduvall * A successful access by another Solaris thread (via either 15131369Sdduvall * port) typically takes ~20us. So waiting a bit longer than 15141369Sdduvall * that will give a good chance of success, if the other user 15151369Sdduvall * *is* another thread on the other port. 15161369Sdduvall * 15171369Sdduvall * However, the internal firmware can hold on to the NVmem 15181369Sdduvall * for *much* longer: at least 10 milliseconds just after a 15191369Sdduvall * RESET, and maybe even longer if the NVmem actually contains 15201369Sdduvall * code to download and run on the internal CPUs. 15211369Sdduvall * 15221369Sdduvall * So, we'll allow 50us; if that's not enough then it's up to the 15231369Sdduvall * caller to retry later (hence the choice of return code EAGAIN). 15241369Sdduvall */ 15251369Sdduvall regval = bge_reg_get32(bgep, NVM_SW_ARBITRATION_REG); 15261369Sdduvall bge_reg_put32(bgep, NVM_SW_ARBITRATION_REG, NVM_SET_REQ); 15271369Sdduvall 15281369Sdduvall for (tries = 0; tries < 50; ++tries) { 15291369Sdduvall regval = bge_reg_get32(bgep, NVM_SW_ARBITRATION_REG); 15301369Sdduvall if (regval & NVM_WON_REQ1) 15311369Sdduvall break; 15321369Sdduvall drv_usecwait(1); 15331369Sdduvall } 15341369Sdduvall 15351369Sdduvall if (regval & NVM_WON_REQ1) { 15361369Sdduvall BGE_DEBUG(("bge_nvmem_acquire: won after %d us", tries)); 15371369Sdduvall return (0); 15381369Sdduvall } 15391369Sdduvall 15401369Sdduvall /* 15411369Sdduvall * Somebody else must be accessing the NVmem, so abandon our 15421369Sdduvall * attempt take control of it. The caller can try again later ... 15431369Sdduvall */ 15441369Sdduvall BGE_DEBUG(("bge_nvmem_acquire: lost after %d us", tries)); 15451369Sdduvall bge_nvmem_relinquish(bgep); 15461369Sdduvall return (EAGAIN); 15471369Sdduvall } 15481369Sdduvall 15491369Sdduvall /* 15501369Sdduvall * This code assumes that the GPIO1 bit has been wired up to the NVmem 15511369Sdduvall * write protect line in such a way that the NVmem is protected when 15521369Sdduvall * GPIO1 is an input, or is an output but driven high. Thus, to make the 15531369Sdduvall * NVmem writable we have to change GPIO1 to an output AND drive it low. 15541369Sdduvall * 15551369Sdduvall * Note: there's only one set of GPIO pins on a 5704, even though they 15561369Sdduvall * can be accessed through either port. So the chip has to resolve what 15571369Sdduvall * happens if the two ports program a single pin differently ... the rule 15581369Sdduvall * it uses is that if the ports disagree about the *direction* of a pin, 15591369Sdduvall * "output" wins over "input", but if they disagree about its *value* as 15601369Sdduvall * an output, then the pin is TRISTATED instead! In such a case, no-one 15611369Sdduvall * wins, and the external signal does whatever the external circuitry 15621369Sdduvall * defines as the default -- which we've assumed is the PROTECTED state. 15631369Sdduvall * So, we always change GPIO1 back to being an *input* whenever we're not 15641369Sdduvall * specifically using it to unprotect the NVmem. This allows either port 15652135Szh199473 * to update the NVmem, although obviously only one at a time! 15661369Sdduvall * 15671369Sdduvall * The caller should hold <genlock> and *also* have already acquired the 15681369Sdduvall * right to access the NVmem, via bge_nvmem_acquire() above. 15691369Sdduvall */ 15701369Sdduvall static void bge_nvmem_protect(bge_t *bgep, boolean_t protect); 15711369Sdduvall #pragma inline(bge_nvmem_protect) 15721369Sdduvall 15731369Sdduvall static void 15741369Sdduvall bge_nvmem_protect(bge_t *bgep, boolean_t protect) 15751369Sdduvall { 15761369Sdduvall uint32_t regval; 15771369Sdduvall 15781369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 15791369Sdduvall 15801369Sdduvall regval = bge_reg_get32(bgep, MISC_LOCAL_CONTROL_REG); 15811369Sdduvall if (protect) { 15821369Sdduvall regval |= MLCR_MISC_PINS_OUTPUT_1; 15831369Sdduvall regval &= ~MLCR_MISC_PINS_OUTPUT_ENABLE_1; 15841369Sdduvall } else { 15851369Sdduvall regval &= ~MLCR_MISC_PINS_OUTPUT_1; 15861369Sdduvall regval |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 15871369Sdduvall } 15881369Sdduvall bge_reg_put32(bgep, MISC_LOCAL_CONTROL_REG, regval); 15891369Sdduvall } 15901369Sdduvall 15911369Sdduvall /* 15921369Sdduvall * Now put it all together ... 15931369Sdduvall * 15941369Sdduvall * Try to acquire control of the NVmem; if successful, then: 15951369Sdduvall * unprotect it (if we want to write to it) 15961369Sdduvall * perform the requested access 15971369Sdduvall * reprotect it (after a write) 15981369Sdduvall * relinquish control 15991369Sdduvall * 16001369Sdduvall * Return value: 16011369Sdduvall * 0 on success, 16021369Sdduvall * EAGAIN if the device is in use (retryable) 16031369Sdduvall * ENODATA on access timeout (maybe retryable: device may just be busy) 16041369Sdduvall * ENODEV if the NVmem device is missing or otherwise unusable 16051369Sdduvall * EPROTO on other h/w or s/w errors. 16061369Sdduvall */ 16071369Sdduvall static int 16081369Sdduvall bge_nvmem_rw32(bge_t *bgep, uint32_t cmd, bge_regno_t addr, uint32_t *dp) 16091369Sdduvall { 16101369Sdduvall int err; 16111369Sdduvall 16121369Sdduvall if ((err = bge_nvmem_acquire(bgep)) == 0) { 16131369Sdduvall switch (cmd) { 16141369Sdduvall case BGE_SEE_READ: 16151369Sdduvall err = bge_seeprom_access(bgep, 16161369Sdduvall SEEPROM_ACCESS_READ, addr, dp); 16171369Sdduvall break; 16181369Sdduvall 16191369Sdduvall case BGE_SEE_WRITE: 16201369Sdduvall bge_nvmem_protect(bgep, B_FALSE); 16211369Sdduvall err = bge_seeprom_access(bgep, 16221369Sdduvall SEEPROM_ACCESS_WRITE, addr, dp); 16231369Sdduvall bge_nvmem_protect(bgep, B_TRUE); 16241369Sdduvall break; 16251369Sdduvall 16261369Sdduvall case BGE_FLASH_READ: 16271369Sdduvall if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 16281369Sdduvall DEVICE_5714_SERIES_CHIPSETS(bgep)) { 16291369Sdduvall bge_reg_set32(bgep, NVM_ACCESS_REG, 16301369Sdduvall NVM_ACCESS_ENABLE); 16311369Sdduvall } 16321369Sdduvall err = bge_flash_access(bgep, 16331369Sdduvall NVM_FLASH_CMD_RD, addr, dp); 16341369Sdduvall if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 16351369Sdduvall DEVICE_5714_SERIES_CHIPSETS(bgep)) { 16361369Sdduvall bge_reg_clr32(bgep, NVM_ACCESS_REG, 16371369Sdduvall NVM_ACCESS_ENABLE); 16381369Sdduvall } 16391369Sdduvall break; 16401369Sdduvall 16411369Sdduvall case BGE_FLASH_WRITE: 16421369Sdduvall if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 16431369Sdduvall DEVICE_5714_SERIES_CHIPSETS(bgep)) { 16441369Sdduvall bge_reg_set32(bgep, NVM_ACCESS_REG, 16451369Sdduvall NVM_WRITE_ENABLE|NVM_ACCESS_ENABLE); 16461369Sdduvall } 16471369Sdduvall bge_nvmem_protect(bgep, B_FALSE); 16481369Sdduvall err = bge_flash_access(bgep, 16491369Sdduvall NVM_FLASH_CMD_WR, addr, dp); 16501369Sdduvall bge_nvmem_protect(bgep, B_TRUE); 16511369Sdduvall if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 16521369Sdduvall DEVICE_5714_SERIES_CHIPSETS(bgep)) { 16531369Sdduvall bge_reg_clr32(bgep, NVM_ACCESS_REG, 16541369Sdduvall NVM_WRITE_ENABLE|NVM_ACCESS_ENABLE); 16551369Sdduvall } 16561369Sdduvall 16571369Sdduvall break; 16581369Sdduvall 16591369Sdduvall default: 16601369Sdduvall _NOTE(NOTREACHED) 16611369Sdduvall break; 16621369Sdduvall } 16631369Sdduvall bge_nvmem_relinquish(bgep); 16641369Sdduvall } 16651369Sdduvall 16661369Sdduvall BGE_DEBUG(("bge_nvmem_rw32: err %d", err)); 16671369Sdduvall return (err); 16681369Sdduvall } 16691369Sdduvall 16701369Sdduvall /* 16711369Sdduvall * Attempt to get a MAC address from the SEEPROM or Flash, if any 16721369Sdduvall */ 16731369Sdduvall static uint64_t bge_get_nvmac(bge_t *bgep); 16741369Sdduvall #pragma no_inline(bge_get_nvmac) 16751369Sdduvall 16761369Sdduvall static uint64_t 16771369Sdduvall bge_get_nvmac(bge_t *bgep) 16781369Sdduvall { 16791369Sdduvall uint32_t mac_high; 16801369Sdduvall uint32_t mac_low; 16811369Sdduvall uint32_t addr; 16821369Sdduvall uint32_t cmd; 16831369Sdduvall uint64_t mac; 16841369Sdduvall 16851369Sdduvall BGE_TRACE(("bge_get_nvmac($%p)", 16864588Sml149210 (void *)bgep)); 16871369Sdduvall 16881369Sdduvall switch (bgep->chipid.nvtype) { 16891369Sdduvall case BGE_NVTYPE_NONE: 16901369Sdduvall case BGE_NVTYPE_UNKNOWN: 16911369Sdduvall default: 16921369Sdduvall return (0ULL); 16931369Sdduvall 16941369Sdduvall case BGE_NVTYPE_SEEPROM: 16951369Sdduvall case BGE_NVTYPE_LEGACY_SEEPROM: 16961369Sdduvall cmd = BGE_SEE_READ; 16971369Sdduvall break; 16981369Sdduvall 16991369Sdduvall case BGE_NVTYPE_UNBUFFERED_FLASH: 17001369Sdduvall case BGE_NVTYPE_BUFFERED_FLASH: 17011369Sdduvall cmd = BGE_FLASH_READ; 17021369Sdduvall break; 17031369Sdduvall } 17041369Sdduvall 1705*7678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 1706*7678SYong.Tan@Sun.COM addr = NVMEM_DATA_MAC_ADDRESS_5906; 1707*7678SYong.Tan@Sun.COM else 1708*7678SYong.Tan@Sun.COM addr = NVMEM_DATA_MAC_ADDRESS; 1709*7678SYong.Tan@Sun.COM 17101369Sdduvall if (bge_nvmem_rw32(bgep, cmd, addr, &mac_high)) 17111369Sdduvall return (0ULL); 17121369Sdduvall addr += 4; 17131369Sdduvall if (bge_nvmem_rw32(bgep, cmd, addr, &mac_low)) 17141369Sdduvall return (0ULL); 17151369Sdduvall 17161369Sdduvall /* 17171369Sdduvall * The Broadcom chip is natively BIG-endian, so that's how the 17181369Sdduvall * MAC address is represented in NVmem. We may need to swap it 17191369Sdduvall * around on a little-endian host ... 17201369Sdduvall */ 17211369Sdduvall #ifdef _BIG_ENDIAN 17221369Sdduvall mac = mac_high; 17231369Sdduvall mac = mac << 32; 17241369Sdduvall mac |= mac_low; 17251369Sdduvall #else 17261369Sdduvall mac = BGE_BSWAP_32(mac_high); 17271369Sdduvall mac = mac << 32; 17281369Sdduvall mac |= BGE_BSWAP_32(mac_low); 17291369Sdduvall #endif /* _BIG_ENDIAN */ 17301369Sdduvall 17311369Sdduvall return (mac); 17321369Sdduvall } 17331369Sdduvall 17341369Sdduvall #else /* BGE_SEE_IO32 || BGE_FLASH_IO32 */ 17351369Sdduvall 17361369Sdduvall /* 17371369Sdduvall * Dummy version for when we're not supporting NVmem access 17381369Sdduvall */ 17391369Sdduvall static uint64_t bge_get_nvmac(bge_t *bgep); 17401369Sdduvall #pragma inline(bge_get_nvmac) 17411369Sdduvall 17421369Sdduvall static uint64_t 17431369Sdduvall bge_get_nvmac(bge_t *bgep) 17441369Sdduvall { 17451369Sdduvall _NOTE(ARGUNUSED(bgep)) 17461369Sdduvall return (0ULL); 17471369Sdduvall } 17481369Sdduvall 17491369Sdduvall #endif /* BGE_SEE_IO32 || BGE_FLASH_IO32 */ 17501369Sdduvall 17511369Sdduvall /* 17521369Sdduvall * Determine the type of NVmem that is (or may be) attached to this chip, 17531369Sdduvall */ 17541369Sdduvall static enum bge_nvmem_type bge_nvmem_id(bge_t *bgep); 17551369Sdduvall #pragma no_inline(bge_nvmem_id) 17561369Sdduvall 17571369Sdduvall static enum bge_nvmem_type 17581369Sdduvall bge_nvmem_id(bge_t *bgep) 17591369Sdduvall { 17601369Sdduvall enum bge_nvmem_type nvtype; 17611369Sdduvall uint32_t config1; 17621369Sdduvall 17631369Sdduvall BGE_TRACE(("bge_nvmem_id($%p)", 17644588Sml149210 (void *)bgep)); 17651369Sdduvall 17661369Sdduvall switch (bgep->chipid.device) { 17671369Sdduvall default: 17681369Sdduvall /* 17691369Sdduvall * We shouldn't get here; it means we don't recognise 17701369Sdduvall * the chip, which means we don't know how to determine 17711369Sdduvall * what sort of NVmem (if any) it has. So we'll say 17721369Sdduvall * NONE, to disable the NVmem access code ... 17731369Sdduvall */ 17741369Sdduvall nvtype = BGE_NVTYPE_NONE; 17751369Sdduvall break; 17761369Sdduvall 17771369Sdduvall case DEVICE_ID_5700: 17781369Sdduvall case DEVICE_ID_5700x: 17791369Sdduvall case DEVICE_ID_5701: 17801369Sdduvall /* 17811369Sdduvall * These devices support *only* SEEPROMs 17821369Sdduvall */ 17831369Sdduvall nvtype = BGE_NVTYPE_SEEPROM; 17841369Sdduvall break; 17851369Sdduvall 17861369Sdduvall case DEVICE_ID_5702: 17871369Sdduvall case DEVICE_ID_5702fe: 17881369Sdduvall case DEVICE_ID_5703C: 17891369Sdduvall case DEVICE_ID_5703S: 17901369Sdduvall case DEVICE_ID_5704C: 17911369Sdduvall case DEVICE_ID_5704S: 17921369Sdduvall case DEVICE_ID_5704: 17931369Sdduvall case DEVICE_ID_5705M: 17941369Sdduvall case DEVICE_ID_5705C: 17953170Sml149210 case DEVICE_ID_5705_2: 17961369Sdduvall case DEVICE_ID_5706: 17971369Sdduvall case DEVICE_ID_5782: 17986989Sml40262 case DEVICE_ID_5787: 17996989Sml40262 case DEVICE_ID_5787M: 18001369Sdduvall case DEVICE_ID_5788: 18012135Szh199473 case DEVICE_ID_5789: 18021369Sdduvall case DEVICE_ID_5751: 18031369Sdduvall case DEVICE_ID_5751M: 18042675Szh199473 case DEVICE_ID_5752: 18052675Szh199473 case DEVICE_ID_5752M: 18063771Sml149210 case DEVICE_ID_5754: 18074330Sml149210 case DEVICE_ID_5755: 18086546Sgh162552 case DEVICE_ID_5755M: 18091369Sdduvall case DEVICE_ID_5721: 18107316SCrisson.Hu@Sun.COM case DEVICE_ID_5722: 18111369Sdduvall case DEVICE_ID_5714C: 18121369Sdduvall case DEVICE_ID_5714S: 18131369Sdduvall case DEVICE_ID_5715C: 18143170Sml149210 case DEVICE_ID_5715S: 18151369Sdduvall config1 = bge_reg_get32(bgep, NVM_CONFIG1_REG); 18161369Sdduvall if (config1 & NVM_CFG1_FLASH_MODE) 18171369Sdduvall if (config1 & NVM_CFG1_BUFFERED_MODE) 18181369Sdduvall nvtype = BGE_NVTYPE_BUFFERED_FLASH; 18191369Sdduvall else 18201369Sdduvall nvtype = BGE_NVTYPE_UNBUFFERED_FLASH; 18211369Sdduvall else 18221369Sdduvall nvtype = BGE_NVTYPE_LEGACY_SEEPROM; 18231369Sdduvall break; 1824*7678SYong.Tan@Sun.COM case DEVICE_ID_5906: 1825*7678SYong.Tan@Sun.COM case DEVICE_ID_5906M: 1826*7678SYong.Tan@Sun.COM nvtype = BGE_NVTYPE_BUFFERED_FLASH; 1827*7678SYong.Tan@Sun.COM break; 18281369Sdduvall } 18291369Sdduvall 18301369Sdduvall return (nvtype); 18311369Sdduvall } 18321369Sdduvall 18331369Sdduvall #undef BGE_DBG 18341369Sdduvall #define BGE_DBG BGE_DBG_CHIP /* debug flag for this code */ 18351369Sdduvall 18361369Sdduvall static void 18371369Sdduvall bge_init_recv_rule(bge_t *bgep) 18381369Sdduvall { 18391369Sdduvall bge_recv_rule_t *rulep; 18401369Sdduvall uint32_t i; 18411369Sdduvall 18421369Sdduvall /* 18431369Sdduvall * receive rule: direct all TCP traffic to ring RULE_MATCH_TO_RING 18441369Sdduvall * 1. to direct UDP traffic, set: 18451369Sdduvall * rulep->control = RULE_PROTO_CONTROL; 18461369Sdduvall * rulep->mask_value = RULE_UDP_MASK_VALUE; 18471369Sdduvall * 2. to direct ICMP traffic, set: 18481369Sdduvall * rulep->control = RULE_PROTO_CONTROL; 18491369Sdduvall * rulep->mask_value = RULE_ICMP_MASK_VALUE; 18501369Sdduvall * 3. to direct traffic by source ip, set: 18511369Sdduvall * rulep->control = RULE_SIP_CONTROL; 18521369Sdduvall * rulep->mask_value = RULE_SIP_MASK_VALUE; 18531369Sdduvall */ 18541369Sdduvall rulep = bgep->recv_rules; 18551369Sdduvall rulep->control = RULE_PROTO_CONTROL; 18561369Sdduvall rulep->mask_value = RULE_TCP_MASK_VALUE; 18571369Sdduvall 18581369Sdduvall /* 18591369Sdduvall * set receive rule registers 18601369Sdduvall */ 18611369Sdduvall rulep = bgep->recv_rules; 18621369Sdduvall for (i = 0; i < RECV_RULES_NUM_MAX; i++, rulep++) { 18631369Sdduvall bge_reg_put32(bgep, RECV_RULE_MASK_REG(i), rulep->mask_value); 18641369Sdduvall bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i), rulep->control); 18651369Sdduvall } 18661369Sdduvall } 18671369Sdduvall 18681369Sdduvall /* 18691369Sdduvall * Using the values captured by bge_chip_cfg_init(), and additional probes 18701369Sdduvall * as required, characterise the chip fully: determine the label by which 18711369Sdduvall * to refer to this chip, the correct settings for various registers, and 18721369Sdduvall * of course whether the device and/or subsystem are supported! 18731369Sdduvall */ 18741865Sdilpreet int bge_chip_id_init(bge_t *bgep); 18751369Sdduvall #pragma no_inline(bge_chip_id_init) 18761369Sdduvall 18771865Sdilpreet int 18781369Sdduvall bge_chip_id_init(bge_t *bgep) 18791369Sdduvall { 18801369Sdduvall char buf[MAXPATHLEN]; /* any risk of stack overflow? */ 18811369Sdduvall boolean_t sys_ok; 18821369Sdduvall boolean_t dev_ok; 18831369Sdduvall chip_id_t *cidp; 18841369Sdduvall uint32_t subid; 18851369Sdduvall char *devname; 18861369Sdduvall char *sysname; 18871369Sdduvall int *ids; 18881369Sdduvall int err; 18891369Sdduvall uint_t i; 18901369Sdduvall 18911369Sdduvall sys_ok = dev_ok = B_FALSE; 18921369Sdduvall cidp = &bgep->chipid; 18931369Sdduvall 18941369Sdduvall /* 18951369Sdduvall * Check the PCI device ID to determine the generic chip type and 18961369Sdduvall * select parameters that depend on this. 18971369Sdduvall * 18981369Sdduvall * Note: because the SPARC platforms in general don't fit the 18991369Sdduvall * SEEPROM 'behind' the chip, the PCI revision ID register reads 19001369Sdduvall * as zero - which is why we use <asic_rev> rather than <revision> 19011369Sdduvall * below ... 19021369Sdduvall * 19031369Sdduvall * Note: in general we can't distinguish between the Copper/SerDes 19041369Sdduvall * versions by ID alone, as some Copper devices (e.g. some but not 19051369Sdduvall * all 5703Cs) have the same ID as the SerDes equivalents. So we 19061369Sdduvall * treat them the same here, and the MII code works out the media 19071369Sdduvall * type later on ... 19081369Sdduvall */ 19091369Sdduvall cidp->mbuf_base = bge_mbuf_pool_base; 19101369Sdduvall cidp->mbuf_length = bge_mbuf_pool_len; 19111369Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_USED; 19121369Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl; 19131369Sdduvall cidp->pci_type = BGE_PCI_X; 19141369Sdduvall cidp->statistic_type = BGE_STAT_BLK; 19151908Sly149593 cidp->mbuf_lo_water_rdma = bge_mbuf_lo_water_rdma; 19161908Sly149593 cidp->mbuf_lo_water_rmac = bge_mbuf_lo_water_rmac; 19171908Sly149593 cidp->mbuf_hi_water = bge_mbuf_hi_water; 19185903Ssowmini cidp->rx_ticks_norm = bge_rx_ticks_norm; 19195903Ssowmini cidp->rx_count_norm = bge_rx_count_norm; 19201369Sdduvall 19211369Sdduvall if (cidp->rx_rings == 0 || cidp->rx_rings > BGE_RECV_RINGS_MAX) 19221369Sdduvall cidp->rx_rings = BGE_RECV_RINGS_DEFAULT; 19231369Sdduvall if (cidp->tx_rings == 0 || cidp->tx_rings > BGE_SEND_RINGS_MAX) 19241369Sdduvall cidp->tx_rings = BGE_SEND_RINGS_DEFAULT; 19251369Sdduvall 19261369Sdduvall cidp->msi_enabled = B_FALSE; 19271369Sdduvall 19281369Sdduvall switch (cidp->device) { 19291369Sdduvall case DEVICE_ID_5700: 19301369Sdduvall case DEVICE_ID_5700x: 19311369Sdduvall cidp->chip_label = 5700; 19322135Szh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 19331369Sdduvall break; 19341369Sdduvall 19351369Sdduvall case DEVICE_ID_5701: 19361369Sdduvall cidp->chip_label = 5701; 19371369Sdduvall dev_ok = B_TRUE; 19382135Szh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 19391369Sdduvall break; 19401369Sdduvall 19411369Sdduvall case DEVICE_ID_5702: 19421369Sdduvall case DEVICE_ID_5702fe: 19431369Sdduvall cidp->chip_label = 5702; 19441369Sdduvall dev_ok = B_TRUE; 19452135Szh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 19462135Szh199473 cidp->pci_type = BGE_PCI; 19471369Sdduvall break; 19481369Sdduvall 19491369Sdduvall case DEVICE_ID_5703C: 19501369Sdduvall case DEVICE_ID_5703S: 19511369Sdduvall case DEVICE_ID_5703: 19521369Sdduvall /* 19531369Sdduvall * Revision A0 of the 5703/5793 had various errata 19541369Sdduvall * that we can't or don't work around, so it's not 19551369Sdduvall * supported, but all later versions are 19561369Sdduvall */ 19571369Sdduvall cidp->chip_label = cidp->subven == VENDOR_ID_SUN ? 5793 : 5703; 19581369Sdduvall if (bgep->chipid.asic_rev != MHCR_CHIP_REV_5703_A0) 19591369Sdduvall dev_ok = B_TRUE; 19602135Szh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 19611369Sdduvall break; 19621369Sdduvall 19631369Sdduvall case DEVICE_ID_5704C: 19641369Sdduvall case DEVICE_ID_5704S: 19651369Sdduvall case DEVICE_ID_5704: 19661369Sdduvall cidp->chip_label = cidp->subven == VENDOR_ID_SUN ? 5794 : 5704; 19671369Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5704; 19681369Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5704; 19691369Sdduvall dev_ok = B_TRUE; 19706133Sgh162552 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 19711369Sdduvall break; 19721369Sdduvall 19731369Sdduvall case DEVICE_ID_5705C: 19741369Sdduvall case DEVICE_ID_5705M: 19751369Sdduvall case DEVICE_ID_5705MA3: 19761369Sdduvall case DEVICE_ID_5705F: 19773170Sml149210 case DEVICE_ID_5705_2: 19783771Sml149210 case DEVICE_ID_5754: 19793771Sml149210 if (cidp->device == DEVICE_ID_5754) { 19803771Sml149210 cidp->chip_label = 5754; 19813771Sml149210 cidp->pci_type = BGE_PCI_E; 19823771Sml149210 } else { 19833771Sml149210 cidp->chip_label = 5705; 19843771Sml149210 cidp->pci_type = BGE_PCI; 19853771Sml149210 } 19861908Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 19871908Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 19881908Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 19891369Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5705; 19901369Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5705; 19911369Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5705; 19921369Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 19931908Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 19941369Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 19952135Szh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 19961369Sdduvall cidp->statistic_type = BGE_STAT_REG; 19971369Sdduvall dev_ok = B_TRUE; 19981369Sdduvall break; 19991369Sdduvall 2000*7678SYong.Tan@Sun.COM case DEVICE_ID_5906: 2001*7678SYong.Tan@Sun.COM case DEVICE_ID_5906M: 2002*7678SYong.Tan@Sun.COM cidp->chip_label = 5906; 2003*7678SYong.Tan@Sun.COM cidp->pci_type = BGE_PCI_E; 2004*7678SYong.Tan@Sun.COM cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5906; 2005*7678SYong.Tan@Sun.COM cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5906; 2006*7678SYong.Tan@Sun.COM cidp->mbuf_hi_water = MBUF_HIWAT_5906; 2007*7678SYong.Tan@Sun.COM cidp->mbuf_base = bge_mbuf_pool_base; 2008*7678SYong.Tan@Sun.COM cidp->mbuf_length = bge_mbuf_pool_len; 2009*7678SYong.Tan@Sun.COM cidp->recv_slots = BGE_RECV_SLOTS_5705; 2010*7678SYong.Tan@Sun.COM cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 2011*7678SYong.Tan@Sun.COM cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 2012*7678SYong.Tan@Sun.COM cidp->flags |= CHIP_FLAG_NO_JUMBO; 2013*7678SYong.Tan@Sun.COM cidp->statistic_type = BGE_STAT_REG; 2014*7678SYong.Tan@Sun.COM dev_ok = B_TRUE; 2015*7678SYong.Tan@Sun.COM break; 2016*7678SYong.Tan@Sun.COM 20174588Sml149210 case DEVICE_ID_5753: 20184588Sml149210 cidp->chip_label = 5753; 20194588Sml149210 cidp->pci_type = BGE_PCI_E; 20204588Sml149210 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 20214588Sml149210 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 20224588Sml149210 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 20234588Sml149210 cidp->mbuf_base = bge_mbuf_pool_base_5705; 20244588Sml149210 cidp->mbuf_length = bge_mbuf_pool_len_5705; 20254588Sml149210 cidp->recv_slots = BGE_RECV_SLOTS_5705; 20264588Sml149210 cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 20274588Sml149210 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 20284588Sml149210 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 20294588Sml149210 cidp->flags |= CHIP_FLAG_NO_JUMBO; 20304588Sml149210 cidp->statistic_type = BGE_STAT_REG; 20314588Sml149210 dev_ok = B_TRUE; 20324588Sml149210 break; 20334588Sml149210 20344330Sml149210 case DEVICE_ID_5755: 20356546Sgh162552 case DEVICE_ID_5755M: 20364330Sml149210 cidp->chip_label = 5755; 20374330Sml149210 cidp->pci_type = BGE_PCI_E; 20384330Sml149210 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 20394330Sml149210 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 20404330Sml149210 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 20414330Sml149210 cidp->mbuf_base = bge_mbuf_pool_base_5705; 20424330Sml149210 cidp->mbuf_length = bge_mbuf_pool_len_5705; 20434330Sml149210 cidp->recv_slots = BGE_RECV_SLOTS_5705; 20444330Sml149210 cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 20454330Sml149210 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 20464330Sml149210 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 20474330Sml149210 cidp->flags |= CHIP_FLAG_NO_JUMBO; 20484330Sml149210 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 20494330Sml149210 cidp->statistic_type = BGE_STAT_REG; 20504330Sml149210 dev_ok = B_TRUE; 20514330Sml149210 break; 20524330Sml149210 20536989Sml40262 case DEVICE_ID_5787: 20546989Sml40262 case DEVICE_ID_5787M: 20556989Sml40262 cidp->chip_label = 5787; 20566989Sml40262 cidp->pci_type = BGE_PCI_E; 20576989Sml40262 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 20586989Sml40262 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 20596989Sml40262 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 20606989Sml40262 cidp->mbuf_base = bge_mbuf_pool_base_5705; 20616989Sml40262 cidp->mbuf_length = bge_mbuf_pool_len_5705; 20626989Sml40262 cidp->recv_slots = BGE_RECV_SLOTS_5705; 20636989Sml40262 cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 20646989Sml40262 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 20656989Sml40262 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 20666989Sml40262 cidp->flags |= CHIP_FLAG_NO_JUMBO; 20676989Sml40262 cidp->statistic_type = BGE_STAT_REG; 20686989Sml40262 dev_ok = B_TRUE; 20696989Sml40262 break; 20706989Sml40262 20711369Sdduvall case DEVICE_ID_5706: 20721369Sdduvall cidp->chip_label = 5706; 20731369Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 20741369Sdduvall break; 20751369Sdduvall 20761369Sdduvall case DEVICE_ID_5782: 20771369Sdduvall /* 20781369Sdduvall * Apart from the label, we treat this as a 5705(?) 20791369Sdduvall */ 20801369Sdduvall cidp->chip_label = 5782; 20811908Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 20821908Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 20831908Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 20841369Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5705; 20851369Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5705; 20861369Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5705; 20871369Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 20881908Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 20891369Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 20902135Szh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 20911369Sdduvall cidp->statistic_type = BGE_STAT_REG; 20921369Sdduvall dev_ok = B_TRUE; 20931369Sdduvall break; 20941369Sdduvall 20951369Sdduvall case DEVICE_ID_5788: 20961369Sdduvall /* 20971369Sdduvall * Apart from the label, we treat this as a 5705(?) 20981369Sdduvall */ 20991369Sdduvall cidp->chip_label = 5788; 21001908Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 21011908Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 21021908Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 21031369Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5705; 21041369Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5705; 21051369Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5705; 21061369Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 21071908Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 21081369Sdduvall cidp->statistic_type = BGE_STAT_REG; 21091369Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 21101369Sdduvall dev_ok = B_TRUE; 21111369Sdduvall break; 21121369Sdduvall 21131369Sdduvall case DEVICE_ID_5714C: 21141369Sdduvall if (cidp->revision >= REVISION_ID_5714_A2) 21151369Sdduvall cidp->msi_enabled = bge_enable_msi; 21161369Sdduvall /* FALLTHRU */ 21171369Sdduvall case DEVICE_ID_5714S: 21181369Sdduvall cidp->chip_label = 5714; 21191908Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 21201908Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 21211908Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 21221369Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5721; 21231369Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5721; 21241369Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5721; 21251369Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl_5714; 21261369Sdduvall cidp->bge_mlcr_default = bge_mlcr_default_5714; 21271369Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 21281908Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 21291369Sdduvall cidp->pci_type = BGE_PCI_E; 21301369Sdduvall cidp->statistic_type = BGE_STAT_REG; 21311369Sdduvall dev_ok = B_TRUE; 21321369Sdduvall break; 21331369Sdduvall 21341369Sdduvall case DEVICE_ID_5715C: 21353170Sml149210 case DEVICE_ID_5715S: 21361369Sdduvall cidp->chip_label = 5715; 21371908Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 21381908Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 21391908Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 21401369Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5721; 21411369Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5721; 21421369Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5721; 21431369Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl_5715; 21441369Sdduvall cidp->bge_mlcr_default = bge_mlcr_default_5714; 21451369Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 21461908Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 21471369Sdduvall cidp->pci_type = BGE_PCI_E; 21481369Sdduvall cidp->statistic_type = BGE_STAT_REG; 21491908Sly149593 if (cidp->revision >= REVISION_ID_5715_A2) 21501908Sly149593 cidp->msi_enabled = bge_enable_msi; 21511369Sdduvall dev_ok = B_TRUE; 21521369Sdduvall break; 21531369Sdduvall 21541369Sdduvall case DEVICE_ID_5721: 21551369Sdduvall cidp->chip_label = 5721; 21561908Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 21571908Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 21581908Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 21591369Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5721; 21601369Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5721; 21611369Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5721; 21621369Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721; 21631369Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 21641908Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 21651369Sdduvall cidp->pci_type = BGE_PCI_E; 21661369Sdduvall cidp->statistic_type = BGE_STAT_REG; 21671369Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 21681369Sdduvall dev_ok = B_TRUE; 21691369Sdduvall break; 21701369Sdduvall 21717316SCrisson.Hu@Sun.COM case DEVICE_ID_5722: 21727316SCrisson.Hu@Sun.COM cidp->chip_label = 5722; 21737316SCrisson.Hu@Sun.COM cidp->pci_type = BGE_PCI_E; 21747316SCrisson.Hu@Sun.COM cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 21757316SCrisson.Hu@Sun.COM cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 21767316SCrisson.Hu@Sun.COM cidp->mbuf_hi_water = MBUF_HIWAT_5705; 21777316SCrisson.Hu@Sun.COM cidp->mbuf_base = bge_mbuf_pool_base_5705; 21787316SCrisson.Hu@Sun.COM cidp->mbuf_length = bge_mbuf_pool_len_5705; 21797316SCrisson.Hu@Sun.COM cidp->recv_slots = BGE_RECV_SLOTS_5705; 21807316SCrisson.Hu@Sun.COM cidp->bge_mlcr_default |= MLCR_MISC_PINS_OUTPUT_ENABLE_1; 21817316SCrisson.Hu@Sun.COM cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 21827316SCrisson.Hu@Sun.COM cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 21837316SCrisson.Hu@Sun.COM cidp->flags |= CHIP_FLAG_NO_JUMBO; 21847316SCrisson.Hu@Sun.COM cidp->statistic_type = BGE_STAT_REG; 21857316SCrisson.Hu@Sun.COM dev_ok = B_TRUE; 21867316SCrisson.Hu@Sun.COM break; 21877316SCrisson.Hu@Sun.COM 21881369Sdduvall case DEVICE_ID_5751: 21891369Sdduvall case DEVICE_ID_5751M: 21901369Sdduvall cidp->chip_label = 5751; 21911908Sly149593 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 21921908Sly149593 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 21931908Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 21941369Sdduvall cidp->mbuf_base = bge_mbuf_pool_base_5721; 21951369Sdduvall cidp->mbuf_length = bge_mbuf_pool_len_5721; 21961369Sdduvall cidp->recv_slots = BGE_RECV_SLOTS_5721; 21971369Sdduvall cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721; 21981369Sdduvall cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 21991908Sly149593 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 22001369Sdduvall cidp->pci_type = BGE_PCI_E; 22011369Sdduvall cidp->statistic_type = BGE_STAT_REG; 22021369Sdduvall cidp->flags |= CHIP_FLAG_NO_JUMBO; 22031369Sdduvall dev_ok = B_TRUE; 22041369Sdduvall break; 22051369Sdduvall 22062675Szh199473 case DEVICE_ID_5752: 22072675Szh199473 case DEVICE_ID_5752M: 22082675Szh199473 cidp->chip_label = 5752; 22092675Szh199473 cidp->mbuf_lo_water_rdma = RDMA_MBUF_LOWAT_5705; 22102675Szh199473 cidp->mbuf_lo_water_rmac = MAC_RX_MBUF_LOWAT_5705; 22112675Szh199473 cidp->mbuf_hi_water = MBUF_HIWAT_5705; 22122675Szh199473 cidp->mbuf_base = bge_mbuf_pool_base_5721; 22132675Szh199473 cidp->mbuf_length = bge_mbuf_pool_len_5721; 22142675Szh199473 cidp->recv_slots = BGE_RECV_SLOTS_5721; 22152675Szh199473 cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721; 22162675Szh199473 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 22172675Szh199473 cidp->tx_rings = BGE_SEND_RINGS_MAX_5705; 22182675Szh199473 cidp->pci_type = BGE_PCI_E; 22192675Szh199473 cidp->statistic_type = BGE_STAT_REG; 22202675Szh199473 cidp->flags |= CHIP_FLAG_NO_JUMBO; 22212675Szh199473 dev_ok = B_TRUE; 22222675Szh199473 break; 22232675Szh199473 22242135Szh199473 case DEVICE_ID_5789: 22252135Szh199473 cidp->chip_label = 5789; 22262135Szh199473 cidp->mbuf_base = bge_mbuf_pool_base_5721; 22272135Szh199473 cidp->mbuf_length = bge_mbuf_pool_len_5721; 22282135Szh199473 cidp->recv_slots = BGE_RECV_SLOTS_5721; 22292135Szh199473 cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721; 22302135Szh199473 cidp->rx_rings = BGE_RECV_RINGS_MAX_5705; 22312135Szh199473 cidp->tx_rings = BGE_RECV_RINGS_MAX_5705; 22322135Szh199473 cidp->pci_type = BGE_PCI_E; 22332135Szh199473 cidp->statistic_type = BGE_STAT_REG; 22342135Szh199473 cidp->flags |= CHIP_FLAG_PARTIAL_CSUM; 22352135Szh199473 cidp->flags |= CHIP_FLAG_NO_JUMBO; 22362135Szh199473 cidp->msi_enabled = B_TRUE; 22372135Szh199473 dev_ok = B_TRUE; 22382135Szh199473 break; 22392135Szh199473 22401369Sdduvall } 22411369Sdduvall 22421369Sdduvall /* 22431369Sdduvall * Setup the default jumbo parameter. 22441369Sdduvall */ 22451369Sdduvall cidp->ethmax_size = ETHERMAX; 22461369Sdduvall cidp->snd_buff_size = BGE_SEND_BUFF_SIZE_DEFAULT; 22471908Sly149593 cidp->std_buf_size = BGE_STD_BUFF_SIZE; 22481369Sdduvall 22491369Sdduvall /* 22501369Sdduvall * If jumbo is enabled and this kind of chipset supports jumbo feature, 22511369Sdduvall * setup below jumbo specific parameters. 22521908Sly149593 * 22531908Sly149593 * For BCM5714/5715, there is only one standard receive ring. So the 22541908Sly149593 * std buffer size should be set to BGE_JUMBO_BUFF_SIZE when jumbo 22551908Sly149593 * feature is enabled. 22561369Sdduvall */ 22571369Sdduvall if (bge_jumbo_enable && 22581369Sdduvall !(cidp->flags & CHIP_FLAG_NO_JUMBO) && 22591369Sdduvall (cidp->default_mtu > BGE_DEFAULT_MTU) && 22601369Sdduvall (cidp->default_mtu <= BGE_MAXIMUM_MTU)) { 22614588Sml149210 if (DEVICE_5714_SERIES_CHIPSETS(bgep)) { 22621908Sly149593 cidp->mbuf_lo_water_rdma = 22631908Sly149593 RDMA_MBUF_LOWAT_5714_JUMBO; 22641908Sly149593 cidp->mbuf_lo_water_rmac = 22651908Sly149593 MAC_RX_MBUF_LOWAT_5714_JUMBO; 22661908Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_5714_JUMBO; 22671908Sly149593 cidp->jumbo_slots = 0; 22681908Sly149593 cidp->std_buf_size = BGE_JUMBO_BUFF_SIZE; 22694588Sml149210 } else { 22701908Sly149593 cidp->mbuf_lo_water_rdma = 22711908Sly149593 RDMA_MBUF_LOWAT_JUMBO; 22721908Sly149593 cidp->mbuf_lo_water_rmac = 22731908Sly149593 MAC_RX_MBUF_LOWAT_JUMBO; 22741908Sly149593 cidp->mbuf_hi_water = MBUF_HIWAT_JUMBO; 22751908Sly149593 cidp->jumbo_slots = BGE_JUMBO_SLOTS_USED; 22761908Sly149593 } 22771369Sdduvall cidp->recv_jumbo_size = BGE_JUMBO_BUFF_SIZE; 22781369Sdduvall cidp->snd_buff_size = BGE_SEND_BUFF_SIZE_JUMBO; 22791369Sdduvall cidp->ethmax_size = cidp->default_mtu + 22801369Sdduvall sizeof (struct ether_header); 22811369Sdduvall } 22821369Sdduvall 22831369Sdduvall /* 22841369Sdduvall * Identify the NV memory type: SEEPROM or Flash? 22851369Sdduvall */ 22861369Sdduvall cidp->nvtype = bge_nvmem_id(bgep); 22871369Sdduvall 22881369Sdduvall /* 22891369Sdduvall * Now, we want to check whether this device is part of a 22901369Sdduvall * supported subsystem (e.g., on the motherboard of a Sun 22911369Sdduvall * branded platform). 22921369Sdduvall * 22931369Sdduvall * Rule 1: If the Subsystem Vendor ID is "Sun", then it's OK ;-) 22941369Sdduvall */ 22951369Sdduvall if (cidp->subven == VENDOR_ID_SUN) 22961369Sdduvall sys_ok = B_TRUE; 22971369Sdduvall 22981369Sdduvall /* 22991369Sdduvall * Rule 2: If it's on the list on known subsystems, then it's OK. 23001369Sdduvall * Note: 0x14e41647 should *not* appear in the list, but the code 23011369Sdduvall * doesn't enforce that. 23021369Sdduvall */ 23031369Sdduvall err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo, 23044588Sml149210 DDI_PROP_DONTPASS, knownids_propname, &ids, &i); 23051369Sdduvall if (err == DDI_PROP_SUCCESS) { 23061369Sdduvall /* 23071369Sdduvall * Got the list; scan for a matching subsystem vendor/device 23081369Sdduvall */ 23091369Sdduvall subid = (cidp->subven << 16) | cidp->subdev; 23101369Sdduvall while (i--) 23111369Sdduvall if (ids[i] == subid) 23121369Sdduvall sys_ok = B_TRUE; 23131369Sdduvall ddi_prop_free(ids); 23141369Sdduvall } 23151369Sdduvall 23161369Sdduvall /* 23171369Sdduvall * Rule 3: If it's a Taco/ENWS motherboard device, then it's OK 23181369Sdduvall * 23191369Sdduvall * Unfortunately, early SunBlade 1500s and 2500s didn't reprogram 23201369Sdduvall * the Subsystem Vendor ID, so it defaults to Broadcom. Therefore, 23211369Sdduvall * we have to check specially for the exact device paths to the 23221369Sdduvall * motherboard devices on those platforms ;-( 23231369Sdduvall * 23241369Sdduvall * Note: we can't just use the "supported-subsystems" mechanism 23251369Sdduvall * above, because the entry would have to be 0x14e41647 -- which 23261369Sdduvall * would then accept *any* plugin card that *didn't* contain a 23271369Sdduvall * (valid) SEEPROM ;-( 23281369Sdduvall */ 23291369Sdduvall sysname = ddi_node_name(ddi_root_node()); 23301369Sdduvall devname = ddi_pathname(bgep->devinfo, buf); 23311369Sdduvall ASSERT(strlen(devname) > 0); 23321369Sdduvall if (strcmp(sysname, "SUNW,Sun-Blade-1500") == 0) /* Taco */ 23331369Sdduvall if (strcmp(devname, "/pci@1f,700000/network@2") == 0) 23341369Sdduvall sys_ok = B_TRUE; 23351369Sdduvall if (strcmp(sysname, "SUNW,Sun-Blade-2500") == 0) /* ENWS */ 23361369Sdduvall if (strcmp(devname, "/pci@1c,600000/network@3") == 0) 23371369Sdduvall sys_ok = B_TRUE; 23381369Sdduvall 23391369Sdduvall /* 23401369Sdduvall * Now check what we've discovered: is this truly a supported 23411369Sdduvall * chip on (the motherboard of) a supported platform? 23421369Sdduvall * 23431369Sdduvall * Possible problems here: 23441369Sdduvall * 1) it's a completely unheard-of chip (e.g. 5761) 23451369Sdduvall * 2) it's a recognised but unsupported chip (e.g. 5701, 5703C-A0) 23461369Sdduvall * 3) it's a chip we would support if it were on the motherboard 23471369Sdduvall * of a Sun platform, but this one isn't ;-( 23481369Sdduvall */ 23491369Sdduvall if (cidp->chip_label == 0) 23501369Sdduvall bge_problem(bgep, 23514588Sml149210 "Device 'pci%04x,%04x' not recognized (%d?)", 23524588Sml149210 cidp->vendor, cidp->device, cidp->device); 23531369Sdduvall else if (!dev_ok) 23541369Sdduvall bge_problem(bgep, 23554588Sml149210 "Device 'pci%04x,%04x' (%d) revision %d not supported", 23564588Sml149210 cidp->vendor, cidp->device, cidp->chip_label, 23574588Sml149210 cidp->revision); 23581369Sdduvall #if BGE_DEBUGGING 23591369Sdduvall else if (!sys_ok) 23601369Sdduvall bge_problem(bgep, 23614588Sml149210 "%d-based subsystem 'pci%04x,%04x' not validated", 23624588Sml149210 cidp->chip_label, cidp->subven, cidp->subdev); 23631369Sdduvall #endif 23641369Sdduvall else 23651369Sdduvall cidp->flags |= CHIP_FLAG_SUPPORTED; 23661865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 23671865Sdilpreet return (EIO); 23681865Sdilpreet return (0); 23691369Sdduvall } 23701369Sdduvall 23711369Sdduvall void 23721369Sdduvall bge_chip_msi_trig(bge_t *bgep) 23731369Sdduvall { 23741369Sdduvall uint32_t regval; 23751369Sdduvall 23761369Sdduvall regval = bgep->param_msi_cnt<<4; 23771369Sdduvall bge_reg_set32(bgep, HOST_COALESCE_MODE_REG, regval); 23781369Sdduvall BGE_DEBUG(("bge_chip_msi_trig:data = %d", regval)); 23791369Sdduvall } 23801369Sdduvall 23811369Sdduvall /* 23821369Sdduvall * Various registers that control the chip's internal engines (state 23831369Sdduvall * machines) have a <reset> and <enable> bits (fortunately, in the 23841369Sdduvall * same place in each such register :-). 23851369Sdduvall * 23861369Sdduvall * To reset the state machine, the <reset> bit must be written with 1; 23871369Sdduvall * it will then read back as 1 while the reset is in progress, but 23881369Sdduvall * self-clear to 0 when the reset completes. 23891369Sdduvall * 23901369Sdduvall * To enable a state machine, one must set the <enable> bit, which 23911369Sdduvall * will continue to read back as 0 until the state machine is running. 23921369Sdduvall * 23931369Sdduvall * To disable a state machine, the <enable> bit must be cleared, but 23941369Sdduvall * it will continue to read back as 1 until the state machine actually 23951369Sdduvall * stops. 23961369Sdduvall * 23971369Sdduvall * This routine implements polling for completion of a reset, enable 23981369Sdduvall * or disable operation, returning B_TRUE on success (bit reached the 23991369Sdduvall * required state) or B_FALSE on timeout (200*100us == 20ms). 24001369Sdduvall */ 24011369Sdduvall static boolean_t bge_chip_poll_engine(bge_t *bgep, bge_regno_t regno, 24021369Sdduvall uint32_t mask, uint32_t val); 24031369Sdduvall #pragma no_inline(bge_chip_poll_engine) 24041369Sdduvall 24051369Sdduvall static boolean_t 24061369Sdduvall bge_chip_poll_engine(bge_t *bgep, bge_regno_t regno, 24071369Sdduvall uint32_t mask, uint32_t val) 24081369Sdduvall { 24091369Sdduvall uint32_t regval; 24101369Sdduvall uint32_t n; 24111369Sdduvall 24121369Sdduvall BGE_TRACE(("bge_chip_poll_engine($%p, 0x%lx, 0x%x, 0x%x)", 24134588Sml149210 (void *)bgep, regno, mask, val)); 24141369Sdduvall 24151369Sdduvall for (n = 200; n; --n) { 24161369Sdduvall regval = bge_reg_get32(bgep, regno); 24171369Sdduvall if ((regval & mask) == val) 24181369Sdduvall return (B_TRUE); 24191369Sdduvall drv_usecwait(100); 24201369Sdduvall } 24211369Sdduvall 24221865Sdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE); 24231369Sdduvall return (B_FALSE); 24241369Sdduvall } 24251369Sdduvall 24261369Sdduvall /* 24271369Sdduvall * Various registers that control the chip's internal engines (state 24281369Sdduvall * machines) have a <reset> bit (fortunately, in the same place in 24291369Sdduvall * each such register :-). To reset the state machine, this bit must 24301369Sdduvall * be written with 1; it will then read back as 1 while the reset is 24311369Sdduvall * in progress, but self-clear to 0 when the reset completes. 24321369Sdduvall * 24331369Sdduvall * This code sets the bit, then polls for it to read back as zero. 24341369Sdduvall * The return value is B_TRUE on success (reset bit cleared itself), 24351369Sdduvall * or B_FALSE if the state machine didn't recover :( 24361369Sdduvall * 24371369Sdduvall * NOTE: the Core reset is similar to other resets, except that we 24381369Sdduvall * can't poll for completion, since the Core reset disables memory 24391369Sdduvall * access! So we just have to assume that it will all complete in 24401369Sdduvall * 100us. See Broadcom document 570X-PG102-R, p102, steps 4-5. 24411369Sdduvall */ 24421369Sdduvall static boolean_t bge_chip_reset_engine(bge_t *bgep, bge_regno_t regno); 24431369Sdduvall #pragma no_inline(bge_chip_reset_engine) 24441369Sdduvall 24451369Sdduvall static boolean_t 24461369Sdduvall bge_chip_reset_engine(bge_t *bgep, bge_regno_t regno) 24471369Sdduvall { 24481369Sdduvall uint32_t regval; 24491369Sdduvall uint32_t val32; 24501369Sdduvall 24511369Sdduvall regval = bge_reg_get32(bgep, regno); 24521369Sdduvall 24531369Sdduvall BGE_TRACE(("bge_chip_reset_engine($%p, 0x%lx)", 24544588Sml149210 (void *)bgep, regno)); 24551369Sdduvall BGE_DEBUG(("bge_chip_reset_engine: 0x%lx before reset = 0x%08x", 24564588Sml149210 regno, regval)); 24571369Sdduvall 24581369Sdduvall regval |= STATE_MACHINE_RESET_BIT; 24591369Sdduvall 24601369Sdduvall switch (regno) { 24611369Sdduvall case MISC_CONFIG_REG: 24621369Sdduvall /* 24631369Sdduvall * BCM5714/5721/5751 pcie chip special case. In order to avoid 24641369Sdduvall * resetting PCIE block and bringing PCIE link down, bit 29 24651369Sdduvall * in the register needs to be set first, and then set it again 24661369Sdduvall * while the reset bit is written. 24671369Sdduvall * See:P500 of 57xx-PG102-RDS.pdf. 24681369Sdduvall */ 24691369Sdduvall if (DEVICE_5705_SERIES_CHIPSETS(bgep)|| 24701369Sdduvall DEVICE_5721_SERIES_CHIPSETS(bgep)|| 2471*7678SYong.Tan@Sun.COM DEVICE_5714_SERIES_CHIPSETS(bgep)|| 2472*7678SYong.Tan@Sun.COM DEVICE_5906_SERIES_CHIPSETS(bgep)) { 24731369Sdduvall regval |= MISC_CONFIG_GPHY_POWERDOWN_OVERRIDE; 24741369Sdduvall if (bgep->chipid.pci_type == BGE_PCI_E) { 24751369Sdduvall if (bgep->chipid.asic_rev == 24761369Sdduvall MHCR_CHIP_REV_5751_A0 || 24771369Sdduvall bgep->chipid.asic_rev == 24784330Sml149210 MHCR_CHIP_REV_5721_A0 || 24794330Sml149210 bgep->chipid.asic_rev == 24804330Sml149210 MHCR_CHIP_REV_5755_A0) { 24811369Sdduvall val32 = bge_reg_get32(bgep, 24821369Sdduvall PHY_TEST_CTRL_REG); 24831369Sdduvall if (val32 == (PHY_PCIE_SCRAM_MODE | 24841369Sdduvall PHY_PCIE_LTASS_MODE)) 24851369Sdduvall bge_reg_put32(bgep, 24861369Sdduvall PHY_TEST_CTRL_REG, 24871369Sdduvall PHY_PCIE_SCRAM_MODE); 24881369Sdduvall val32 = pci_config_get32 24891369Sdduvall (bgep->cfg_handle, 24901369Sdduvall PCI_CONF_BGE_CLKCTL); 24911369Sdduvall val32 |= CLKCTL_PCIE_A0_FIX; 24921369Sdduvall pci_config_put32(bgep->cfg_handle, 24931369Sdduvall PCI_CONF_BGE_CLKCTL, val32); 24941369Sdduvall } 24951369Sdduvall bge_reg_set32(bgep, regno, 24964588Sml149210 MISC_CONFIG_GRC_RESET_DISABLE); 24971369Sdduvall regval |= MISC_CONFIG_GRC_RESET_DISABLE; 24981369Sdduvall } 24991369Sdduvall } 25001369Sdduvall 25011369Sdduvall /* 25021369Sdduvall * Special case - causes Core reset 25031369Sdduvall * 25041369Sdduvall * On SPARC v9 we want to ensure that we don't start 25051369Sdduvall * timing until the I/O access has actually reached 25061369Sdduvall * the chip, otherwise we might make the next access 25071369Sdduvall * too early. And we can't just force the write out 25081369Sdduvall * by following it with a read (even to config space) 25091369Sdduvall * because that would cause the fault we're trying 25101369Sdduvall * to avoid. Hence the need for membar_sync() here. 25111369Sdduvall */ 25121369Sdduvall ddi_put32(bgep->io_handle, PIO_ADDR(bgep, regno), regval); 25131369Sdduvall #ifdef __sparcv9 25141369Sdduvall membar_sync(); 25151369Sdduvall #endif /* __sparcv9 */ 25161369Sdduvall /* 25171369Sdduvall * On some platforms,system need about 300us for 25181369Sdduvall * link setup. 25191369Sdduvall */ 25201369Sdduvall drv_usecwait(300); 2521*7678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { 2522*7678SYong.Tan@Sun.COM bge_reg_set32(bgep, VCPU_STATUS_REG, VCPU_DRV_RESET); 2523*7678SYong.Tan@Sun.COM bge_reg_clr32( 2524*7678SYong.Tan@Sun.COM bgep, VCPU_EXT_CTL, VCPU_EXT_CTL_HALF); 2525*7678SYong.Tan@Sun.COM } 25261369Sdduvall 25271369Sdduvall if (bgep->chipid.pci_type == BGE_PCI_E) { 25281369Sdduvall /* PCI-E device need more reset time */ 25291369Sdduvall drv_usecwait(120000); 25301369Sdduvall 25311369Sdduvall /* Set PCIE max payload size and clear error status. */ 25322135Szh199473 if ((bgep->chipid.chip_label == 5721) || 25332135Szh199473 (bgep->chipid.chip_label == 5751) || 25342675Szh199473 (bgep->chipid.chip_label == 5752) || 2535*7678SYong.Tan@Sun.COM (bgep->chipid.chip_label == 5789) || 2536*7678SYong.Tan@Sun.COM (bgep->chipid.chip_label == 5906)) { 25371369Sdduvall pci_config_put16(bgep->cfg_handle, 25384588Sml149210 PCI_CONF_DEV_CTRL, READ_REQ_SIZE_MAX); 25391369Sdduvall pci_config_put16(bgep->cfg_handle, 25404588Sml149210 PCI_CONF_DEV_STUS, DEVICE_ERROR_STUS); 25411369Sdduvall } 25421369Sdduvall } 25431369Sdduvall 25441369Sdduvall BGE_PCICHK(bgep); 25451369Sdduvall return (B_TRUE); 25461369Sdduvall 25471369Sdduvall default: 25481369Sdduvall bge_reg_put32(bgep, regno, regval); 25491369Sdduvall return (bge_chip_poll_engine(bgep, regno, 25501865Sdilpreet STATE_MACHINE_RESET_BIT, 0)); 25511369Sdduvall } 25521369Sdduvall } 25531369Sdduvall 25541369Sdduvall /* 25551369Sdduvall * Various registers that control the chip's internal engines (state 25561369Sdduvall * machines) have an <enable> bit (fortunately, in the same place in 25571369Sdduvall * each such register :-). To stop the state machine, this bit must 25581369Sdduvall * be written with 0, then polled to see when the state machine has 25591369Sdduvall * actually stopped. 25601369Sdduvall * 25611369Sdduvall * The return value is B_TRUE on success (enable bit cleared), or 25621369Sdduvall * B_FALSE if the state machine didn't stop :( 25631369Sdduvall */ 25641369Sdduvall static boolean_t bge_chip_disable_engine(bge_t *bgep, bge_regno_t regno, 25651369Sdduvall uint32_t morebits); 25661369Sdduvall #pragma no_inline(bge_chip_disable_engine) 25671369Sdduvall 25681369Sdduvall static boolean_t 25691369Sdduvall bge_chip_disable_engine(bge_t *bgep, bge_regno_t regno, uint32_t morebits) 25701369Sdduvall { 25711369Sdduvall uint32_t regval; 25721369Sdduvall 25731369Sdduvall BGE_TRACE(("bge_chip_disable_engine($%p, 0x%lx, 0x%x)", 25744588Sml149210 (void *)bgep, regno, morebits)); 25751369Sdduvall 25761369Sdduvall switch (regno) { 25771369Sdduvall case FTQ_RESET_REG: 25781369Sdduvall /* 25793918Sml149210 * For Schumacher's bugfix CR6490108 25803918Sml149210 */ 25813918Sml149210 #ifdef BGE_IPMI_ASF 25823918Sml149210 #ifdef BGE_NETCONSOLE 25833918Sml149210 if (bgep->asf_enabled) 25843918Sml149210 return (B_TRUE); 25853918Sml149210 #endif 25863918Sml149210 #endif 25873918Sml149210 /* 25881369Sdduvall * Not quite like the others; it doesn't 25891369Sdduvall * have an <enable> bit, but instead we 25901369Sdduvall * have to set and then clear all the bits 25911369Sdduvall */ 25921369Sdduvall bge_reg_put32(bgep, regno, ~(uint32_t)0); 25931369Sdduvall drv_usecwait(100); 25941369Sdduvall bge_reg_put32(bgep, regno, 0); 25951369Sdduvall return (B_TRUE); 25961369Sdduvall 25971369Sdduvall default: 25981369Sdduvall regval = bge_reg_get32(bgep, regno); 25991369Sdduvall regval &= ~STATE_MACHINE_ENABLE_BIT; 26001369Sdduvall regval &= ~morebits; 26011369Sdduvall bge_reg_put32(bgep, regno, regval); 26021369Sdduvall return (bge_chip_poll_engine(bgep, regno, 26031865Sdilpreet STATE_MACHINE_ENABLE_BIT, 0)); 26041369Sdduvall } 26051369Sdduvall } 26061369Sdduvall 26071369Sdduvall /* 26081369Sdduvall * Various registers that control the chip's internal engines (state 26091369Sdduvall * machines) have an <enable> bit (fortunately, in the same place in 26101369Sdduvall * each such register :-). To start the state machine, this bit must 26111369Sdduvall * be written with 1, then polled to see when the state machine has 26121369Sdduvall * actually started. 26131369Sdduvall * 26141369Sdduvall * The return value is B_TRUE on success (enable bit set), or 26151369Sdduvall * B_FALSE if the state machine didn't start :( 26161369Sdduvall */ 26171369Sdduvall static boolean_t bge_chip_enable_engine(bge_t *bgep, bge_regno_t regno, 26181369Sdduvall uint32_t morebits); 26191369Sdduvall #pragma no_inline(bge_chip_enable_engine) 26201369Sdduvall 26211369Sdduvall static boolean_t 26221369Sdduvall bge_chip_enable_engine(bge_t *bgep, bge_regno_t regno, uint32_t morebits) 26231369Sdduvall { 26241369Sdduvall uint32_t regval; 26251369Sdduvall 26261369Sdduvall BGE_TRACE(("bge_chip_enable_engine($%p, 0x%lx, 0x%x)", 26274588Sml149210 (void *)bgep, regno, morebits)); 26281369Sdduvall 26291369Sdduvall switch (regno) { 26301369Sdduvall case FTQ_RESET_REG: 26313918Sml149210 #ifdef BGE_IPMI_ASF 26323918Sml149210 #ifdef BGE_NETCONSOLE 26333918Sml149210 if (bgep->asf_enabled) 26343918Sml149210 return (B_TRUE); 26353918Sml149210 #endif 26363918Sml149210 #endif 26371369Sdduvall /* 26381369Sdduvall * Not quite like the others; it doesn't 26391369Sdduvall * have an <enable> bit, but instead we 26401369Sdduvall * have to set and then clear all the bits 26411369Sdduvall */ 26421369Sdduvall bge_reg_put32(bgep, regno, ~(uint32_t)0); 26431369Sdduvall drv_usecwait(100); 26441369Sdduvall bge_reg_put32(bgep, regno, 0); 26451369Sdduvall return (B_TRUE); 26461369Sdduvall 26471369Sdduvall default: 26481369Sdduvall regval = bge_reg_get32(bgep, regno); 26491369Sdduvall regval |= STATE_MACHINE_ENABLE_BIT; 26501369Sdduvall regval |= morebits; 26511369Sdduvall bge_reg_put32(bgep, regno, regval); 26521369Sdduvall return (bge_chip_poll_engine(bgep, regno, 26531865Sdilpreet STATE_MACHINE_ENABLE_BIT, STATE_MACHINE_ENABLE_BIT)); 26541369Sdduvall } 26551369Sdduvall } 26561369Sdduvall 26571369Sdduvall /* 26581369Sdduvall * Reprogram the Ethernet, Transmit, and Receive MAC 26591369Sdduvall * modes to match the param_* variables 26601369Sdduvall */ 26615903Ssowmini void bge_sync_mac_modes(bge_t *bgep); 26621369Sdduvall #pragma no_inline(bge_sync_mac_modes) 26631369Sdduvall 26645903Ssowmini void 26651369Sdduvall bge_sync_mac_modes(bge_t *bgep) 26661369Sdduvall { 26671369Sdduvall uint32_t macmode; 26681369Sdduvall uint32_t regval; 26691369Sdduvall 26701369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 26711369Sdduvall 26721369Sdduvall /* 26731369Sdduvall * Reprogram the Ethernet MAC mode ... 26741369Sdduvall */ 26751369Sdduvall macmode = regval = bge_reg_get32(bgep, ETHERNET_MAC_MODE_REG); 26761369Sdduvall if ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 26774588Sml149210 (bgep->param_loop_mode != BGE_LOOP_INTERNAL_MAC)) 26787561SCrisson.Hu@Sun.COM if (DEVICE_5714_SERIES_CHIPSETS(bgep)) 26797561SCrisson.Hu@Sun.COM macmode |= ETHERNET_MODE_LINK_POLARITY; 26807561SCrisson.Hu@Sun.COM else 26817561SCrisson.Hu@Sun.COM macmode &= ~ETHERNET_MODE_LINK_POLARITY; 26821369Sdduvall else 26831369Sdduvall macmode |= ETHERNET_MODE_LINK_POLARITY; 26841369Sdduvall macmode &= ~ETHERNET_MODE_PORTMODE_MASK; 26851369Sdduvall if ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 26867561SCrisson.Hu@Sun.COM (bgep->param_loop_mode != BGE_LOOP_INTERNAL_MAC)) { 26877561SCrisson.Hu@Sun.COM if (DEVICE_5714_SERIES_CHIPSETS(bgep)) 26887561SCrisson.Hu@Sun.COM macmode |= ETHERNET_MODE_PORTMODE_GMII; 26897561SCrisson.Hu@Sun.COM else 26907561SCrisson.Hu@Sun.COM macmode |= ETHERNET_MODE_PORTMODE_TBI; 26917561SCrisson.Hu@Sun.COM } else if (bgep->param_link_speed == 10 || 26927561SCrisson.Hu@Sun.COM bgep->param_link_speed == 100) 26931369Sdduvall macmode |= ETHERNET_MODE_PORTMODE_MII; 26941369Sdduvall else 26951369Sdduvall macmode |= ETHERNET_MODE_PORTMODE_GMII; 26961369Sdduvall if (bgep->param_link_duplex == LINK_DUPLEX_HALF) 26971369Sdduvall macmode |= ETHERNET_MODE_HALF_DUPLEX; 26981369Sdduvall else 26991369Sdduvall macmode &= ~ETHERNET_MODE_HALF_DUPLEX; 27001369Sdduvall if (bgep->param_loop_mode == BGE_LOOP_INTERNAL_MAC) 27011369Sdduvall macmode |= ETHERNET_MODE_MAC_LOOPBACK; 27021369Sdduvall else 27031369Sdduvall macmode &= ~ETHERNET_MODE_MAC_LOOPBACK; 27041369Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, macmode); 27051369Sdduvall BGE_DEBUG(("bge_sync_mac_modes($%p) Ethernet MAC mode 0x%x => 0x%x", 27064588Sml149210 (void *)bgep, regval, macmode)); 27071369Sdduvall 27081369Sdduvall /* 27091369Sdduvall * ... the Transmit MAC mode ... 27101369Sdduvall */ 27111369Sdduvall macmode = regval = bge_reg_get32(bgep, TRANSMIT_MAC_MODE_REG); 27121369Sdduvall if (bgep->param_link_tx_pause) 27131369Sdduvall macmode |= TRANSMIT_MODE_FLOW_CONTROL; 27141369Sdduvall else 27151369Sdduvall macmode &= ~TRANSMIT_MODE_FLOW_CONTROL; 27161369Sdduvall bge_reg_put32(bgep, TRANSMIT_MAC_MODE_REG, macmode); 27171369Sdduvall BGE_DEBUG(("bge_sync_mac_modes($%p) Transmit MAC mode 0x%x => 0x%x", 27184588Sml149210 (void *)bgep, regval, macmode)); 27191369Sdduvall 27201369Sdduvall /* 27211369Sdduvall * ... and the Receive MAC mode 27221369Sdduvall */ 27231369Sdduvall macmode = regval = bge_reg_get32(bgep, RECEIVE_MAC_MODE_REG); 27241369Sdduvall if (bgep->param_link_rx_pause) 27251369Sdduvall macmode |= RECEIVE_MODE_FLOW_CONTROL; 27261369Sdduvall else 27271369Sdduvall macmode &= ~RECEIVE_MODE_FLOW_CONTROL; 27281369Sdduvall bge_reg_put32(bgep, RECEIVE_MAC_MODE_REG, macmode); 27291369Sdduvall BGE_DEBUG(("bge_sync_mac_modes($%p) Receive MAC mode 0x%x => 0x%x", 27304588Sml149210 (void *)bgep, regval, macmode)); 27311369Sdduvall } 27321369Sdduvall 27331369Sdduvall /* 27341369Sdduvall * bge_chip_sync() -- program the chip with the unicast MAC address, 27351369Sdduvall * the multicast hash table, the required level of promiscuity, and 27361369Sdduvall * the current loopback mode ... 27371369Sdduvall */ 27381408Srandyf #ifdef BGE_IPMI_ASF 27391865Sdilpreet int bge_chip_sync(bge_t *bgep, boolean_t asf_keeplive); 27401408Srandyf #else 27411865Sdilpreet int bge_chip_sync(bge_t *bgep); 27421408Srandyf #endif 27431369Sdduvall #pragma no_inline(bge_chip_sync) 27441369Sdduvall 27451865Sdilpreet int 27461408Srandyf #ifdef BGE_IPMI_ASF 27471408Srandyf bge_chip_sync(bge_t *bgep, boolean_t asf_keeplive) 27481408Srandyf #else 27491369Sdduvall bge_chip_sync(bge_t *bgep) 27501408Srandyf #endif 27511369Sdduvall { 27521369Sdduvall void (*opfn)(bge_t *bgep, bge_regno_t reg, uint32_t bits); 27531369Sdduvall boolean_t promisc; 27541369Sdduvall uint64_t macaddr; 27551369Sdduvall uint32_t fill; 27562331Skrgopi int i, j; 27571865Sdilpreet int retval = DDI_SUCCESS; 27581369Sdduvall 27591369Sdduvall BGE_TRACE(("bge_chip_sync($%p)", 27605903Ssowmini (void *)bgep)); 27611369Sdduvall 27621369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 27631369Sdduvall 27641369Sdduvall promisc = B_FALSE; 27651369Sdduvall fill = ~(uint32_t)0; 27661369Sdduvall 27671369Sdduvall if (bgep->promisc) 27681369Sdduvall promisc = B_TRUE; 27691369Sdduvall else 27701369Sdduvall fill = (uint32_t)0; 27711369Sdduvall 27721369Sdduvall /* 27731369Sdduvall * If the TX/RX MAC engines are already running, we should stop 27741369Sdduvall * them (and reset the RX engine) before changing the parameters. 27751369Sdduvall * If they're not running, this will have no effect ... 27761369Sdduvall * 27771369Sdduvall * NOTE: this is currently disabled by default because stopping 27781369Sdduvall * and restarting the Tx engine may cause an outgoing packet in 27791369Sdduvall * transit to be truncated. Also, stopping and restarting the 27801369Sdduvall * Rx engine seems to not work correctly on the 5705. Testing 27811369Sdduvall * has not (yet!) revealed any problems with NOT stopping and 27821369Sdduvall * restarting these engines (and Broadcom say their drivers don't 27831369Sdduvall * do this), but if it is found to cause problems, this variable 27841369Sdduvall * can be patched to re-enable the old behaviour ... 27851369Sdduvall */ 27861369Sdduvall if (bge_stop_start_on_sync) { 27871408Srandyf #ifdef BGE_IPMI_ASF 27881865Sdilpreet if (!bgep->asf_enabled) { 27891865Sdilpreet if (!bge_chip_disable_engine(bgep, 27901865Sdilpreet RECEIVE_MAC_MODE_REG, RECEIVE_MODE_KEEP_VLAN_TAG)) 27911865Sdilpreet retval = DDI_FAILURE; 27921408Srandyf } else { 27931865Sdilpreet if (!bge_chip_disable_engine(bgep, 27941865Sdilpreet RECEIVE_MAC_MODE_REG, 0)) 27951865Sdilpreet retval = DDI_FAILURE; 27961408Srandyf } 27971408Srandyf #else 27981865Sdilpreet if (!bge_chip_disable_engine(bgep, RECEIVE_MAC_MODE_REG, 27991865Sdilpreet RECEIVE_MODE_KEEP_VLAN_TAG)) 28001865Sdilpreet retval = DDI_FAILURE; 28011408Srandyf #endif 28021865Sdilpreet if (!bge_chip_disable_engine(bgep, TRANSMIT_MAC_MODE_REG, 0)) 28031865Sdilpreet retval = DDI_FAILURE; 28041865Sdilpreet if (!bge_chip_reset_engine(bgep, RECEIVE_MAC_MODE_REG)) 28051865Sdilpreet retval = DDI_FAILURE; 28061369Sdduvall } 28071369Sdduvall 28081369Sdduvall /* 28091369Sdduvall * Reprogram the hashed multicast address table ... 28101369Sdduvall */ 28111369Sdduvall for (i = 0; i < BGE_HASH_TABLE_SIZE/32; ++i) 28126546Sgh162552 bge_reg_put32(bgep, MAC_HASH_REG(i), 0); 28136546Sgh162552 28146546Sgh162552 for (i = 0; i < BGE_HASH_TABLE_SIZE/32; ++i) 28151369Sdduvall bge_reg_put32(bgep, MAC_HASH_REG(i), 28161369Sdduvall bgep->mcast_hash[i] | fill); 28171369Sdduvall 28181408Srandyf #ifdef BGE_IPMI_ASF 28191408Srandyf if (!bgep->asf_enabled || !asf_keeplive) { 28201408Srandyf #endif 28211408Srandyf /* 28222331Skrgopi * Transform the MAC address(es) from host to chip format, then 28231408Srandyf * reprogram the transmit random backoff seed and the unicast 28241408Srandyf * MAC address(es) ... 28251408Srandyf */ 28262331Skrgopi for (j = 0; j < MAC_ADDRESS_REGS_MAX; j++) { 28272331Skrgopi for (i = 0, fill = 0, macaddr = 0ull; 28282331Skrgopi i < ETHERADDRL; ++i) { 28292331Skrgopi macaddr <<= 8; 28302331Skrgopi macaddr |= bgep->curr_addr[j].addr[i]; 28312331Skrgopi fill += bgep->curr_addr[j].addr[i]; 28322331Skrgopi } 28332331Skrgopi bge_reg_put32(bgep, MAC_TX_RANDOM_BACKOFF_REG, fill); 28342331Skrgopi bge_reg_put64(bgep, MAC_ADDRESS_REG(j), macaddr); 28351408Srandyf } 28361408Srandyf 28371408Srandyf BGE_DEBUG(("bge_chip_sync($%p) setting MAC address %012llx", 28381408Srandyf (void *)bgep, macaddr)); 28391408Srandyf #ifdef BGE_IPMI_ASF 28401369Sdduvall } 28411408Srandyf #endif 28421369Sdduvall 28431369Sdduvall /* 28441369Sdduvall * Set or clear the PROMISCUOUS mode bit 28451369Sdduvall */ 28461369Sdduvall opfn = promisc ? bge_reg_set32 : bge_reg_clr32; 28471369Sdduvall (*opfn)(bgep, RECEIVE_MAC_MODE_REG, RECEIVE_MODE_PROMISCUOUS); 28481369Sdduvall 28491369Sdduvall /* 28501369Sdduvall * Sync the rest of the MAC modes too ... 28511369Sdduvall */ 28521369Sdduvall bge_sync_mac_modes(bgep); 28531369Sdduvall 28541369Sdduvall /* 28551369Sdduvall * Restart RX/TX MAC engines if required ... 28561369Sdduvall */ 28571369Sdduvall if (bgep->bge_chip_state == BGE_CHIP_RUNNING) { 28581865Sdilpreet if (!bge_chip_enable_engine(bgep, TRANSMIT_MAC_MODE_REG, 0)) 28591865Sdilpreet retval = DDI_FAILURE; 28601408Srandyf #ifdef BGE_IPMI_ASF 28611865Sdilpreet if (!bgep->asf_enabled) { 28621865Sdilpreet if (!bge_chip_enable_engine(bgep, 28631865Sdilpreet RECEIVE_MAC_MODE_REG, RECEIVE_MODE_KEEP_VLAN_TAG)) 28641865Sdilpreet retval = DDI_FAILURE; 28651408Srandyf } else { 28661865Sdilpreet if (!bge_chip_enable_engine(bgep, 28671865Sdilpreet RECEIVE_MAC_MODE_REG, 0)) 28681865Sdilpreet retval = DDI_FAILURE; 28691408Srandyf } 28701408Srandyf #else 28711865Sdilpreet if (!bge_chip_enable_engine(bgep, RECEIVE_MAC_MODE_REG, 28721865Sdilpreet RECEIVE_MODE_KEEP_VLAN_TAG)) 28731865Sdilpreet retval = DDI_FAILURE; 28741408Srandyf #endif 28751369Sdduvall } 28761865Sdilpreet return (retval); 28771369Sdduvall } 28781369Sdduvall 28791369Sdduvall /* 28801369Sdduvall * This array defines the sequence of state machine control registers 28811369Sdduvall * in which the <enable> bit must be cleared to bring the chip to a 28821369Sdduvall * clean stop. Taken from Broadcom document 570X-PG102-R, p116. 28831369Sdduvall */ 28841369Sdduvall static bge_regno_t shutdown_engine_regs[] = { 28851369Sdduvall RECEIVE_MAC_MODE_REG, 28861369Sdduvall RCV_BD_INITIATOR_MODE_REG, 28871369Sdduvall RCV_LIST_PLACEMENT_MODE_REG, 28881369Sdduvall RCV_LIST_SELECTOR_MODE_REG, /* BCM5704 series only */ 28891369Sdduvall RCV_DATA_BD_INITIATOR_MODE_REG, 28901369Sdduvall RCV_DATA_COMPLETION_MODE_REG, 28911369Sdduvall RCV_BD_COMPLETION_MODE_REG, 28921369Sdduvall 28931369Sdduvall SEND_BD_SELECTOR_MODE_REG, 28941369Sdduvall SEND_BD_INITIATOR_MODE_REG, 28951369Sdduvall SEND_DATA_INITIATOR_MODE_REG, 28961369Sdduvall READ_DMA_MODE_REG, 28971369Sdduvall SEND_DATA_COMPLETION_MODE_REG, 28981369Sdduvall DMA_COMPLETION_MODE_REG, /* BCM5704 series only */ 28991369Sdduvall SEND_BD_COMPLETION_MODE_REG, 29001369Sdduvall TRANSMIT_MAC_MODE_REG, 29011369Sdduvall 29021369Sdduvall HOST_COALESCE_MODE_REG, 29031369Sdduvall WRITE_DMA_MODE_REG, 29041369Sdduvall MBUF_CLUSTER_FREE_MODE_REG, /* BCM5704 series only */ 29051369Sdduvall FTQ_RESET_REG, /* special - see code */ 29061369Sdduvall BUFFER_MANAGER_MODE_REG, /* BCM5704 series only */ 29071369Sdduvall MEMORY_ARBITER_MODE_REG, /* BCM5704 series only */ 29081369Sdduvall BGE_REGNO_NONE /* terminator */ 29091369Sdduvall }; 29101369Sdduvall 29117656SSherry.Moore@Sun.COM #ifndef __sparc 29127656SSherry.Moore@Sun.COM static bge_regno_t quiesce_regs[] = { 29137656SSherry.Moore@Sun.COM READ_DMA_MODE_REG, 29147656SSherry.Moore@Sun.COM DMA_COMPLETION_MODE_REG, 29157656SSherry.Moore@Sun.COM WRITE_DMA_MODE_REG, 29167656SSherry.Moore@Sun.COM BGE_REGNO_NONE 29177656SSherry.Moore@Sun.COM }; 29187656SSherry.Moore@Sun.COM 29197656SSherry.Moore@Sun.COM void bge_chip_stop_nonblocking(bge_t *bgep); 29207656SSherry.Moore@Sun.COM #pragma no_inline(bge_chip_stop_nonblocking) 29217656SSherry.Moore@Sun.COM 29227656SSherry.Moore@Sun.COM /* 29237656SSherry.Moore@Sun.COM * This function is called by bge_quiesce(). We 29247656SSherry.Moore@Sun.COM * turn off all the DMA engines here. 29257656SSherry.Moore@Sun.COM */ 29267656SSherry.Moore@Sun.COM void 29277656SSherry.Moore@Sun.COM bge_chip_stop_nonblocking(bge_t *bgep) 29287656SSherry.Moore@Sun.COM { 29297656SSherry.Moore@Sun.COM bge_regno_t *rbp; 29307656SSherry.Moore@Sun.COM 29317656SSherry.Moore@Sun.COM /* 29327656SSherry.Moore@Sun.COM * Flag that no more activity may be initiated 29337656SSherry.Moore@Sun.COM */ 29347656SSherry.Moore@Sun.COM bgep->progress &= ~PROGRESS_READY; 29357656SSherry.Moore@Sun.COM 29367656SSherry.Moore@Sun.COM rbp = quiesce_regs; 29377656SSherry.Moore@Sun.COM while (*rbp != BGE_REGNO_NONE) { 29387656SSherry.Moore@Sun.COM (void) bge_chip_disable_engine(bgep, *rbp, 0); 29397656SSherry.Moore@Sun.COM ++rbp; 29407656SSherry.Moore@Sun.COM } 29417656SSherry.Moore@Sun.COM 29427656SSherry.Moore@Sun.COM bgep->bge_chip_state = BGE_CHIP_STOPPED; 29437656SSherry.Moore@Sun.COM } 29447656SSherry.Moore@Sun.COM 29457656SSherry.Moore@Sun.COM #endif 29467656SSherry.Moore@Sun.COM 29471369Sdduvall /* 29481369Sdduvall * bge_chip_stop() -- stop all chip processing 29491369Sdduvall * 29501369Sdduvall * If the <fault> parameter is B_TRUE, we're stopping the chip because 29511369Sdduvall * we've detected a problem internally; otherwise, this is a normal 29521369Sdduvall * (clean) stop (at user request i.e. the last STREAM has been closed). 29531369Sdduvall */ 29541369Sdduvall void bge_chip_stop(bge_t *bgep, boolean_t fault); 29551369Sdduvall #pragma no_inline(bge_chip_stop) 29561369Sdduvall 29571369Sdduvall void 29581369Sdduvall bge_chip_stop(bge_t *bgep, boolean_t fault) 29591369Sdduvall { 29601369Sdduvall bge_regno_t regno; 29611369Sdduvall bge_regno_t *rbp; 29621369Sdduvall boolean_t ok; 29631369Sdduvall 29641369Sdduvall BGE_TRACE(("bge_chip_stop($%p)", 29654588Sml149210 (void *)bgep)); 29661369Sdduvall 29671369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 29681369Sdduvall 29691369Sdduvall rbp = shutdown_engine_regs; 29701369Sdduvall /* 29711369Sdduvall * When driver try to shutdown the BCM5705/5788/5721/5751/ 29721369Sdduvall * 5752/5714 and 5715 chipsets,the buffer manager and the mem 29731369Sdduvall * -ory arbiter should not be disabled. 29741369Sdduvall */ 29751369Sdduvall for (ok = B_TRUE; (regno = *rbp) != BGE_REGNO_NONE; ++rbp) { 29761369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 29774588Sml149210 ok &= bge_chip_disable_engine(bgep, regno, 0); 29781369Sdduvall else if ((regno != RCV_LIST_SELECTOR_MODE_REG) && 29794588Sml149210 (regno != DMA_COMPLETION_MODE_REG) && 29804588Sml149210 (regno != MBUF_CLUSTER_FREE_MODE_REG)&& 29814588Sml149210 (regno != BUFFER_MANAGER_MODE_REG) && 29824588Sml149210 (regno != MEMORY_ARBITER_MODE_REG)) 29834588Sml149210 ok &= bge_chip_disable_engine(bgep, 29844588Sml149210 regno, 0); 29851369Sdduvall } 29861369Sdduvall 29871865Sdilpreet if (!ok && !fault) 29881865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 29891865Sdilpreet 29901369Sdduvall /* 29911369Sdduvall * Finally, disable (all) MAC events & clear the MAC status 29921369Sdduvall */ 29931369Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_EVENT_ENABLE_REG, 0); 29941369Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_STATUS_REG, ~0); 29951369Sdduvall 29961369Sdduvall /* 29971865Sdilpreet * if we're stopping the chip because of a detected fault then do 29981865Sdilpreet * appropriate actions 29991369Sdduvall */ 30001865Sdilpreet if (fault) { 30011865Sdilpreet if (bgep->bge_chip_state != BGE_CHIP_FAULT) { 30021865Sdilpreet bgep->bge_chip_state = BGE_CHIP_FAULT; 30035903Ssowmini if (!bgep->manual_reset) 30045903Ssowmini ddi_fm_service_impact(bgep->devinfo, 30055903Ssowmini DDI_SERVICE_LOST); 30061865Sdilpreet if (bgep->bge_dma_error) { 30071865Sdilpreet /* 30081865Sdilpreet * need to free buffers in case the fault was 30091865Sdilpreet * due to a memory error in a buffer - got to 30101865Sdilpreet * do a fair bit of tidying first 30111865Sdilpreet */ 30121865Sdilpreet if (bgep->progress & PROGRESS_KSTATS) { 30131865Sdilpreet bge_fini_kstats(bgep); 30141865Sdilpreet bgep->progress &= ~PROGRESS_KSTATS; 30151865Sdilpreet } 30161865Sdilpreet if (bgep->progress & PROGRESS_INTR) { 30171865Sdilpreet bge_intr_disable(bgep); 30181865Sdilpreet rw_enter(bgep->errlock, RW_WRITER); 30191865Sdilpreet bge_fini_rings(bgep); 30201865Sdilpreet rw_exit(bgep->errlock); 30211865Sdilpreet bgep->progress &= ~PROGRESS_INTR; 30221865Sdilpreet } 30231865Sdilpreet if (bgep->progress & PROGRESS_BUFS) { 30241865Sdilpreet bge_free_bufs(bgep); 30251865Sdilpreet bgep->progress &= ~PROGRESS_BUFS; 30261865Sdilpreet } 30271865Sdilpreet bgep->bge_dma_error = B_FALSE; 30281865Sdilpreet } 30291865Sdilpreet } 30301865Sdilpreet } else 30311369Sdduvall bgep->bge_chip_state = BGE_CHIP_STOPPED; 30321369Sdduvall } 30331369Sdduvall 30341369Sdduvall /* 30351369Sdduvall * Poll for completion of chip's ROM firmware; also, at least on the 30361369Sdduvall * first time through, find and return the hardware MAC address, if any. 30371369Sdduvall */ 30381369Sdduvall static uint64_t bge_poll_firmware(bge_t *bgep); 30391369Sdduvall #pragma no_inline(bge_poll_firmware) 30401369Sdduvall 30411369Sdduvall static uint64_t 30421369Sdduvall bge_poll_firmware(bge_t *bgep) 30431369Sdduvall { 30441369Sdduvall uint64_t magic; 30451369Sdduvall uint64_t mac; 3046*7678SYong.Tan@Sun.COM uint32_t gen, val; 30471369Sdduvall uint32_t i; 30481369Sdduvall 30491369Sdduvall /* 30501369Sdduvall * Step 19: poll for firmware completion (GENCOMM port set 30511369Sdduvall * to the ones complement of T3_MAGIC_NUMBER). 30521369Sdduvall * 30531369Sdduvall * While we're at it, we also read the MAC address register; 30542135Szh199473 * at some stage the firmware will load this with the 30551369Sdduvall * factory-set value. 30561369Sdduvall * 30571369Sdduvall * When both the magic number and the MAC address are set, 30581369Sdduvall * we're done; but we impose a time limit of one second 30591369Sdduvall * (1000*1000us) in case the firmware fails in some fashion 30601369Sdduvall * or the SEEPROM that provides that MAC address isn't fitted. 30611369Sdduvall * 30621369Sdduvall * After the first time through (chip state != INITIAL), we 30631369Sdduvall * don't need the MAC address to be set (we've already got it 30641369Sdduvall * or not, from the first time), so we don't wait for it, but 30651369Sdduvall * we still have to wait for the T3_MAGIC_NUMBER. 30661369Sdduvall * 30671369Sdduvall * Note: the magic number is only a 32-bit quantity, but the NIC 30681369Sdduvall * memory is 64-bit (and big-endian) internally. Addressing the 30691369Sdduvall * GENCOMM word as "the upper half of a 64-bit quantity" makes 30701369Sdduvall * it work correctly on both big- and little-endian hosts. 30711369Sdduvall */ 3072*7678SYong.Tan@Sun.COM if (MHCR_CHIP_ASIC_REV(bgep->chipid.asic_rev) == 3073*7678SYong.Tan@Sun.COM MHCR_CHIP_ASIC_REV_5906) { 3074*7678SYong.Tan@Sun.COM for (i = 0; i < 1000; ++i) { 3075*7678SYong.Tan@Sun.COM drv_usecwait(1000); 3076*7678SYong.Tan@Sun.COM val = bge_reg_get32(bgep, VCPU_STATUS_REG); 3077*7678SYong.Tan@Sun.COM if (val & VCPU_INIT_DONE) 3078*7678SYong.Tan@Sun.COM break; 3079*7678SYong.Tan@Sun.COM } 3080*7678SYong.Tan@Sun.COM BGE_DEBUG(("bge_poll_firmware($%p): return after %d loops", 3081*7678SYong.Tan@Sun.COM (void *)bgep, i)); 30821369Sdduvall mac = bge_reg_get64(bgep, MAC_ADDRESS_REG(0)); 3083*7678SYong.Tan@Sun.COM } else { 3084*7678SYong.Tan@Sun.COM for (i = 0; i < 1000; ++i) { 3085*7678SYong.Tan@Sun.COM drv_usecwait(1000); 3086*7678SYong.Tan@Sun.COM gen = bge_nic_get64(bgep, NIC_MEM_GENCOMM) >> 32; 3087*7678SYong.Tan@Sun.COM if (i == 0 && DEVICE_5704_SERIES_CHIPSETS(bgep)) 3088*7678SYong.Tan@Sun.COM drv_usecwait(100000); 3089*7678SYong.Tan@Sun.COM mac = bge_reg_get64(bgep, MAC_ADDRESS_REG(0)); 30901408Srandyf #ifdef BGE_IPMI_ASF 3091*7678SYong.Tan@Sun.COM if (!bgep->asf_enabled) { 30921408Srandyf #endif 3093*7678SYong.Tan@Sun.COM if (gen != ~T3_MAGIC_NUMBER) 3094*7678SYong.Tan@Sun.COM continue; 30951408Srandyf #ifdef BGE_IPMI_ASF 3096*7678SYong.Tan@Sun.COM } 30971408Srandyf #endif 3098*7678SYong.Tan@Sun.COM if (mac != 0ULL) 3099*7678SYong.Tan@Sun.COM break; 3100*7678SYong.Tan@Sun.COM if (bgep->bge_chip_state != BGE_CHIP_INITIAL) 3101*7678SYong.Tan@Sun.COM break; 3102*7678SYong.Tan@Sun.COM } 31031369Sdduvall } 31041369Sdduvall 31051369Sdduvall magic = bge_nic_get64(bgep, NIC_MEM_GENCOMM); 31061369Sdduvall BGE_DEBUG(("bge_poll_firmware($%p): PXE magic 0x%x after %d loops", 31074588Sml149210 (void *)bgep, gen, i)); 31081369Sdduvall BGE_DEBUG(("bge_poll_firmware: MAC %016llx, GENCOMM %016llx", 31094588Sml149210 mac, magic)); 31101369Sdduvall 31111369Sdduvall return (mac); 31121369Sdduvall } 31131369Sdduvall 31143390Szh199473 /* 31153390Szh199473 * Maximum times of trying to get the NVRAM access lock 31163390Szh199473 * by calling bge_nvmem_acquire() 31173390Szh199473 */ 31183390Szh199473 #define MAX_TRY_NVMEM_ACQUIRE 10000 31193390Szh199473 31201408Srandyf #ifdef BGE_IPMI_ASF 31211865Sdilpreet int bge_chip_reset(bge_t *bgep, boolean_t enable_dma, uint_t asf_mode); 31221408Srandyf #else 31231865Sdilpreet int bge_chip_reset(bge_t *bgep, boolean_t enable_dma); 31241408Srandyf #endif 31251369Sdduvall #pragma no_inline(bge_chip_reset) 31261369Sdduvall 31271865Sdilpreet int 31281408Srandyf #ifdef BGE_IPMI_ASF 31291408Srandyf bge_chip_reset(bge_t *bgep, boolean_t enable_dma, uint_t asf_mode) 31301408Srandyf #else 31311369Sdduvall bge_chip_reset(bge_t *bgep, boolean_t enable_dma) 31321408Srandyf #endif 31331369Sdduvall { 31341369Sdduvall chip_id_t chipid; 31351369Sdduvall uint64_t mac; 31361908Sly149593 uint64_t magic; 31371369Sdduvall uint32_t modeflags; 31381369Sdduvall uint32_t mhcr; 31391369Sdduvall uint32_t sx0; 31403390Szh199473 uint32_t i, tries; 31411408Srandyf #ifdef BGE_IPMI_ASF 31421408Srandyf uint32_t mailbox; 31431408Srandyf #endif 31441865Sdilpreet int retval = DDI_SUCCESS; 31451369Sdduvall 31461369Sdduvall BGE_TRACE(("bge_chip_reset($%p, %d)", 31471369Sdduvall (void *)bgep, enable_dma)); 31481369Sdduvall 31491369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 31501369Sdduvall 31511369Sdduvall BGE_DEBUG(("bge_chip_reset($%p, %d): current state is %d", 31521369Sdduvall (void *)bgep, enable_dma, bgep->bge_chip_state)); 31531369Sdduvall 31541369Sdduvall /* 31551369Sdduvall * Do we need to stop the chip cleanly before resetting? 31561369Sdduvall */ 31571369Sdduvall switch (bgep->bge_chip_state) { 31581369Sdduvall default: 31591369Sdduvall _NOTE(NOTREACHED) 31601865Sdilpreet return (DDI_FAILURE); 31611369Sdduvall 31621369Sdduvall case BGE_CHIP_INITIAL: 31631369Sdduvall case BGE_CHIP_STOPPED: 31641369Sdduvall case BGE_CHIP_RESET: 31651369Sdduvall break; 31661369Sdduvall 31671369Sdduvall case BGE_CHIP_RUNNING: 31681369Sdduvall case BGE_CHIP_ERROR: 31691369Sdduvall case BGE_CHIP_FAULT: 31701369Sdduvall bge_chip_stop(bgep, B_FALSE); 31711369Sdduvall break; 31721369Sdduvall } 31731369Sdduvall 31741408Srandyf #ifdef BGE_IPMI_ASF 31751408Srandyf if (bgep->asf_enabled) { 31763918Sml149210 #ifdef __sparc 31773918Sml149210 mhcr = MHCR_ENABLE_INDIRECT_ACCESS | 31783918Sml149210 MHCR_ENABLE_TAGGED_STATUS_MODE | 31793918Sml149210 MHCR_MASK_INTERRUPT_MODE | 31803918Sml149210 MHCR_MASK_PCI_INT_OUTPUT | 31813918Sml149210 MHCR_CLEAR_INTERRUPT_INTA | 31823918Sml149210 MHCR_ENABLE_ENDIAN_WORD_SWAP | 31833918Sml149210 MHCR_ENABLE_ENDIAN_BYTE_SWAP; 31843918Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcr); 31853918Sml149210 bge_reg_put32(bgep, MEMORY_ARBITER_MODE_REG, 31863918Sml149210 bge_reg_get32(bgep, MEMORY_ARBITER_MODE_REG) | 31873918Sml149210 MEMORY_ARBITER_ENABLE); 31883918Sml149210 #endif 31891408Srandyf if (asf_mode == ASF_MODE_INIT) { 31901408Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 31911408Srandyf } else if (asf_mode == ASF_MODE_SHUTDOWN) { 31921408Srandyf bge_asf_pre_reset_operations(bgep, BGE_SHUTDOWN_RESET); 31931408Srandyf } 31941408Srandyf } 31951408Srandyf #endif 31961369Sdduvall /* 31971369Sdduvall * Adapted from Broadcom document 570X-PG102-R, pp 102-116. 31981369Sdduvall * Updated to reflect Broadcom document 570X-PG104-R, pp 146-159. 31991369Sdduvall * 32001369Sdduvall * Before reset Core clock,it is 32011369Sdduvall * also required to initialize the Memory Arbiter as specified in step9 32021369Sdduvall * and Misc Host Control Register as specified in step-13 32031369Sdduvall * Step 4-5: reset Core clock & wait for completion 32041369Sdduvall * Steps 6-8: are done by bge_chip_cfg_init() 32051908Sly149593 * put the T3_MAGIC_NUMBER into the GENCOMM port before reset 32061369Sdduvall */ 32071865Sdilpreet if (!bge_chip_enable_engine(bgep, MEMORY_ARBITER_MODE_REG, 0)) 32081865Sdilpreet retval = DDI_FAILURE; 32091369Sdduvall 32101369Sdduvall mhcr = MHCR_ENABLE_INDIRECT_ACCESS | 32111369Sdduvall MHCR_ENABLE_TAGGED_STATUS_MODE | 32121369Sdduvall MHCR_MASK_INTERRUPT_MODE | 32131369Sdduvall MHCR_MASK_PCI_INT_OUTPUT | 32141369Sdduvall MHCR_CLEAR_INTERRUPT_INTA; 32151369Sdduvall #ifdef _BIG_ENDIAN 32161369Sdduvall mhcr |= MHCR_ENABLE_ENDIAN_WORD_SWAP | MHCR_ENABLE_ENDIAN_BYTE_SWAP; 32171369Sdduvall #endif /* _BIG_ENDIAN */ 32181369Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcr); 32191408Srandyf #ifdef BGE_IPMI_ASF 32201408Srandyf if (bgep->asf_enabled) 32211408Srandyf bgep->asf_wordswapped = B_FALSE; 32221408Srandyf #endif 32232675Szh199473 /* 32242675Szh199473 * NVRAM Corruption Workaround 32252675Szh199473 */ 32263390Szh199473 for (tries = 0; tries < MAX_TRY_NVMEM_ACQUIRE; tries++) 32273534Szh199473 if (bge_nvmem_acquire(bgep) != EAGAIN) 32282675Szh199473 break; 32293440Szh199473 if (tries >= MAX_TRY_NVMEM_ACQUIRE) 32302675Szh199473 BGE_DEBUG(("%s: fail to acquire nvram lock", 32312675Szh199473 bgep->ifname)); 32322675Szh199473 32331908Sly149593 #ifdef BGE_IPMI_ASF 32341908Sly149593 if (!bgep->asf_enabled) { 32351908Sly149593 #endif 32361908Sly149593 magic = (uint64_t)T3_MAGIC_NUMBER << 32; 32371908Sly149593 bge_nic_put64(bgep, NIC_MEM_GENCOMM, magic); 32381908Sly149593 #ifdef BGE_IPMI_ASF 32391908Sly149593 } 32401908Sly149593 #endif 32411908Sly149593 32421865Sdilpreet if (!bge_chip_reset_engine(bgep, MISC_CONFIG_REG)) 32431865Sdilpreet retval = DDI_FAILURE; 32441369Sdduvall bge_chip_cfg_init(bgep, &chipid, enable_dma); 32451369Sdduvall 32461369Sdduvall /* 32471369Sdduvall * Step 8a: This may belong elsewhere, but BCM5721 needs 32481369Sdduvall * a bit set to avoid a fifo overflow/underflow bug. 32491369Sdduvall */ 32502135Szh199473 if ((bgep->chipid.chip_label == 5721) || 32512135Szh199473 (bgep->chipid.chip_label == 5751) || 32522675Szh199473 (bgep->chipid.chip_label == 5752) || 32534330Sml149210 (bgep->chipid.chip_label == 5755) || 3254*7678SYong.Tan@Sun.COM (bgep->chipid.chip_label == 5789) || 3255*7678SYong.Tan@Sun.COM (bgep->chipid.chip_label == 5906)) 32561369Sdduvall bge_reg_set32(bgep, TLP_CONTROL_REG, TLP_DATA_FIFO_PROTECT); 32571369Sdduvall 32581369Sdduvall 32591369Sdduvall /* 32601369Sdduvall * Step 9: enable MAC memory arbiter,bit30 and bit31 of 5714/5715 should 32611369Sdduvall * not be changed. 32621369Sdduvall */ 32631865Sdilpreet if (!bge_chip_enable_engine(bgep, MEMORY_ARBITER_MODE_REG, 0)) 32641865Sdilpreet retval = DDI_FAILURE; 32651369Sdduvall 32661369Sdduvall /* 32671369Sdduvall * Steps 10-11: configure PIO endianness options and 32681369Sdduvall * enable indirect register access -- already done 32691369Sdduvall * Steps 12-13: enable writing to the PCI state & clock 32701369Sdduvall * control registers -- not required; we aren't going to 32711369Sdduvall * use those features. 32721369Sdduvall * Steps 14-15: Configure DMA endianness options. See 32731369Sdduvall * the comments on the setting of the MHCR above. 32741369Sdduvall */ 32751369Sdduvall #ifdef _BIG_ENDIAN 32761369Sdduvall modeflags = MODE_WORD_SWAP_FRAME | MODE_BYTE_SWAP_FRAME | 32771369Sdduvall MODE_WORD_SWAP_NONFRAME | MODE_BYTE_SWAP_NONFRAME; 32781369Sdduvall #else 32791369Sdduvall modeflags = MODE_WORD_SWAP_FRAME | MODE_BYTE_SWAP_FRAME; 32801369Sdduvall #endif /* _BIG_ENDIAN */ 32811408Srandyf #ifdef BGE_IPMI_ASF 32821408Srandyf if (bgep->asf_enabled) 32831408Srandyf modeflags |= MODE_HOST_STACK_UP; 32841408Srandyf #endif 32851369Sdduvall bge_reg_put32(bgep, MODE_CONTROL_REG, modeflags); 32861369Sdduvall 32871408Srandyf #ifdef BGE_IPMI_ASF 32881408Srandyf if (bgep->asf_enabled) { 32893918Sml149210 #ifdef __sparc 32903918Sml149210 bge_reg_put32(bgep, MEMORY_ARBITER_MODE_REG, 32913918Sml149210 MEMORY_ARBITER_ENABLE | 32923918Sml149210 bge_reg_get32(bgep, MEMORY_ARBITER_MODE_REG)); 32933918Sml149210 #endif 32943918Sml149210 32953918Sml149210 #ifdef BGE_NETCONSOLE 32963918Sml149210 if (!bgep->asf_newhandshake) { 32973918Sml149210 if ((asf_mode == ASF_MODE_INIT) || 32983918Sml149210 (asf_mode == ASF_MODE_POST_INIT)) { 32993918Sml149210 bge_asf_post_reset_old_mode(bgep, 33003918Sml149210 BGE_INIT_RESET); 33013918Sml149210 } else { 33023918Sml149210 bge_asf_post_reset_old_mode(bgep, 33033918Sml149210 BGE_SHUTDOWN_RESET); 33041408Srandyf } 33051408Srandyf } 33063918Sml149210 #endif 33073918Sml149210 33083918Sml149210 /* Wait for NVRAM init */ 33093918Sml149210 i = 0; 33103918Sml149210 drv_usecwait(5000); 33113918Sml149210 mailbox = bge_nic_get32(bgep, BGE_FIRMWARE_MAILBOX); 33123918Sml149210 33133918Sml149210 while ((mailbox != (uint32_t) 33143918Sml149210 ~BGE_MAGIC_NUM_FIRMWARE_INIT_DONE) && 33153918Sml149210 (i < 10000)) { 33163918Sml149210 drv_usecwait(100); 33173918Sml149210 mailbox = bge_nic_get32(bgep, 33183918Sml149210 BGE_FIRMWARE_MAILBOX); 33193918Sml149210 i++; 33203918Sml149210 } 33213918Sml149210 33223918Sml149210 #ifndef BGE_NETCONSOLE 33233918Sml149210 if (!bgep->asf_newhandshake) { 33243918Sml149210 if ((asf_mode == ASF_MODE_INIT) || 33253918Sml149210 (asf_mode == ASF_MODE_POST_INIT)) { 33263918Sml149210 33273918Sml149210 bge_asf_post_reset_old_mode(bgep, 33283918Sml149210 BGE_INIT_RESET); 33293918Sml149210 } else { 33303918Sml149210 bge_asf_post_reset_old_mode(bgep, 33313918Sml149210 BGE_SHUTDOWN_RESET); 33323918Sml149210 } 33333918Sml149210 } 33343918Sml149210 #endif 33351408Srandyf } 33361408Srandyf #endif 33371369Sdduvall /* 33381369Sdduvall * Steps 16-17: poll for firmware completion 33391369Sdduvall */ 33401369Sdduvall mac = bge_poll_firmware(bgep); 33411369Sdduvall 33421369Sdduvall /* 33431369Sdduvall * Step 18: enable external memory -- doesn't apply. 33441369Sdduvall * 33451369Sdduvall * However we take the opportunity to set the MLCR anyway, as 33461369Sdduvall * this register also controls the SEEPROM auto-access method 33471369Sdduvall * which we may want to use later ... 33481369Sdduvall * 33491369Sdduvall * The proper value here depends on the way the chip is wired 33501369Sdduvall * into the circuit board, as this register *also* controls which 33511369Sdduvall * of the "Miscellaneous I/O" pins are driven as outputs and the 33521369Sdduvall * values driven onto those pins! 33531369Sdduvall * 33541369Sdduvall * See also step 74 in the PRM ... 33551369Sdduvall */ 33561369Sdduvall bge_reg_put32(bgep, MISC_LOCAL_CONTROL_REG, 33571369Sdduvall bgep->chipid.bge_mlcr_default); 33581369Sdduvall bge_reg_set32(bgep, SERIAL_EEPROM_ADDRESS_REG, SEEPROM_ACCESS_INIT); 33591369Sdduvall 33601369Sdduvall /* 33611369Sdduvall * Step 20: clear the Ethernet MAC mode register 33621369Sdduvall */ 33631369Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, 0); 33641369Sdduvall 33651369Sdduvall /* 33661369Sdduvall * Step 21: restore cache-line-size, latency timer, and 33671369Sdduvall * subsystem ID registers to their original values (not 33681369Sdduvall * those read into the local structure <chipid>, 'cos 33691369Sdduvall * that was after they were cleared by the RESET). 33701369Sdduvall * 33711369Sdduvall * Note: the Subsystem Vendor/Device ID registers are not 33721369Sdduvall * directly writable in config space, so we use the shadow 33731369Sdduvall * copy in "Page Zero" of register space to restore them 33741369Sdduvall * both in one go ... 33751369Sdduvall */ 33761369Sdduvall pci_config_put8(bgep->cfg_handle, PCI_CONF_CACHE_LINESZ, 33771369Sdduvall bgep->chipid.clsize); 33781369Sdduvall pci_config_put8(bgep->cfg_handle, PCI_CONF_LATENCY_TIMER, 33791369Sdduvall bgep->chipid.latency); 33801369Sdduvall bge_reg_put32(bgep, PCI_CONF_SUBVENID, 33811369Sdduvall (bgep->chipid.subdev << 16) | bgep->chipid.subven); 33821369Sdduvall 33831369Sdduvall /* 33841369Sdduvall * The SEND INDEX registers should be reset to zero by the 33851369Sdduvall * global chip reset; if they're not, there'll be trouble 33861865Sdilpreet * later on. 33871369Sdduvall */ 33881369Sdduvall sx0 = bge_reg_get32(bgep, NIC_DIAG_SEND_INDEX_REG(0)); 33891865Sdilpreet if (sx0 != 0) { 33901865Sdilpreet BGE_REPORT((bgep, "SEND INDEX - device didn't RESET")); 33911865Sdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE); 33923170Sml149210 retval = DDI_FAILURE; 33931865Sdilpreet } 33941369Sdduvall 33951369Sdduvall /* Enable MSI code */ 33961369Sdduvall if (bgep->intr_type == DDI_INTR_TYPE_MSI) 33971369Sdduvall bge_reg_set32(bgep, MSI_MODE_REG, 33983907Szh199473 MSI_PRI_HIGHEST|MSI_MSI_ENABLE|MSI_ERROR_ATTENTION); 33991369Sdduvall 34001369Sdduvall /* 34011369Sdduvall * On the first time through, save the factory-set MAC address 34021369Sdduvall * (if any). If bge_poll_firmware() above didn't return one 34031369Sdduvall * (from a chip register) consider looking in the attached NV 34041369Sdduvall * memory device, if any. Once we have it, we save it in both 34051369Sdduvall * register-image (64-bit) and byte-array forms. All-zero and 34061369Sdduvall * all-one addresses are not valid, and we refuse to stash those. 34071369Sdduvall */ 34081369Sdduvall if (bgep->bge_chip_state == BGE_CHIP_INITIAL) { 34091369Sdduvall if (mac == 0ULL) 34101369Sdduvall mac = bge_get_nvmac(bgep); 34111369Sdduvall if (mac != 0ULL && mac != ~0ULL) { 34121369Sdduvall bgep->chipid.hw_mac_addr = mac; 34131369Sdduvall for (i = ETHERADDRL; i-- != 0; ) { 34141369Sdduvall bgep->chipid.vendor_addr.addr[i] = (uchar_t)mac; 34151369Sdduvall mac >>= 8; 34161369Sdduvall } 34172331Skrgopi bgep->chipid.vendor_addr.set = B_TRUE; 34181369Sdduvall } 34191369Sdduvall } 34201369Sdduvall 34211408Srandyf #ifdef BGE_IPMI_ASF 34221408Srandyf if (bgep->asf_enabled && bgep->asf_newhandshake) { 34231408Srandyf if (asf_mode != ASF_MODE_NONE) { 34241408Srandyf if ((asf_mode == ASF_MODE_INIT) || 34251408Srandyf (asf_mode == ASF_MODE_POST_INIT)) { 34261408Srandyf 34271408Srandyf bge_asf_post_reset_new_mode(bgep, 34281408Srandyf BGE_INIT_RESET); 34291408Srandyf } else { 34301408Srandyf bge_asf_post_reset_new_mode(bgep, 34311408Srandyf BGE_SHUTDOWN_RESET); 34321408Srandyf } 34331408Srandyf } 34341408Srandyf } 34351408Srandyf #endif 34361408Srandyf 34371369Sdduvall /* 34381369Sdduvall * Record the new state 34391369Sdduvall */ 34401369Sdduvall bgep->chip_resets += 1; 34411369Sdduvall bgep->bge_chip_state = BGE_CHIP_RESET; 34421865Sdilpreet return (retval); 34431369Sdduvall } 34441369Sdduvall 34451369Sdduvall /* 34461369Sdduvall * bge_chip_start() -- start the chip transmitting and/or receiving, 34471369Sdduvall * including enabling interrupts 34481369Sdduvall */ 34491865Sdilpreet int bge_chip_start(bge_t *bgep, boolean_t reset_phys); 34501369Sdduvall #pragma no_inline(bge_chip_start) 34511369Sdduvall 34521865Sdilpreet int 34531369Sdduvall bge_chip_start(bge_t *bgep, boolean_t reset_phys) 34541369Sdduvall { 34551369Sdduvall uint32_t coalmode; 34561369Sdduvall uint32_t ledctl; 34571369Sdduvall uint32_t mtu; 34581369Sdduvall uint32_t maxring; 34593534Szh199473 uint32_t stats_mask; 34604330Sml149210 uint32_t dma_wrprio; 34611369Sdduvall uint64_t ring; 34621865Sdilpreet int retval = DDI_SUCCESS; 34631369Sdduvall 34641369Sdduvall BGE_TRACE(("bge_chip_start($%p)", 34654588Sml149210 (void *)bgep)); 34661369Sdduvall 34671369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 34681369Sdduvall ASSERT(bgep->bge_chip_state == BGE_CHIP_RESET); 34691369Sdduvall 34701369Sdduvall /* 34711369Sdduvall * Taken from Broadcom document 570X-PG102-R, pp 102-116. 34721369Sdduvall * The document specifies 95 separate steps to fully 34731369Sdduvall * initialise the chip!!!! 34741369Sdduvall * 34751369Sdduvall * The reset code above has already got us as far as step 34761369Sdduvall * 21, so we continue with ... 34771369Sdduvall * 34781369Sdduvall * Step 22: clear the MAC statistics block 34791369Sdduvall * (0x0300-0x0aff in NIC-local memory) 34801369Sdduvall */ 34811369Sdduvall if (bgep->chipid.statistic_type == BGE_STAT_BLK) 34821369Sdduvall bge_nic_zero(bgep, NIC_MEM_STATISTICS, 34831369Sdduvall NIC_MEM_STATISTICS_SIZE); 34841369Sdduvall 34851369Sdduvall /* 34861369Sdduvall * Step 23: clear the status block (in host memory) 34871369Sdduvall */ 34881369Sdduvall DMA_ZERO(bgep->status_block); 34891369Sdduvall 34901369Sdduvall /* 34911369Sdduvall * Step 24: set DMA read/write control register 34921369Sdduvall */ 34931369Sdduvall pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_PDRWCR, 34944588Sml149210 bgep->chipid.bge_dma_rwctrl); 34951369Sdduvall 34961369Sdduvall /* 34971369Sdduvall * Step 25: Configure DMA endianness -- already done (16/17) 34981369Sdduvall * Step 26: Configure Host-Based Send Rings 34991369Sdduvall * Step 27: Indicate Host Stack Up 35001369Sdduvall */ 35011369Sdduvall bge_reg_set32(bgep, MODE_CONTROL_REG, 35024588Sml149210 MODE_HOST_SEND_BDS | 35034588Sml149210 MODE_HOST_STACK_UP); 35041369Sdduvall 35051369Sdduvall /* 35061369Sdduvall * Step 28: Configure checksum options: 35071611Szh199473 * Solaris supports the hardware default checksum options. 35081611Szh199473 * 35091611Szh199473 * Workaround for Incorrect pseudo-header checksum calculation. 35101369Sdduvall */ 35112135Szh199473 if (bgep->chipid.flags & CHIP_FLAG_PARTIAL_CSUM) 35121611Szh199473 bge_reg_set32(bgep, MODE_CONTROL_REG, 35132311Sseb MODE_SEND_NO_PSEUDO_HDR_CSUM); 35141369Sdduvall 35151369Sdduvall /* 35161369Sdduvall * Step 29: configure Timer Prescaler. The value is always the 35171369Sdduvall * same: the Core Clock frequency in MHz (66), minus 1, shifted 35181369Sdduvall * into bits 7-1. Don't set bit 0, 'cos that's the RESET bit 35191369Sdduvall * for the whole chip! 35201369Sdduvall */ 35211369Sdduvall bge_reg_put32(bgep, MISC_CONFIG_REG, MISC_CONFIG_DEFAULT); 35221369Sdduvall 3523*7678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { 3524*7678SYong.Tan@Sun.COM drv_usecwait(40); 3525*7678SYong.Tan@Sun.COM /* put PHY into ready state */ 3526*7678SYong.Tan@Sun.COM bge_reg_clr32(bgep, MISC_CONFIG_REG, MISC_CONFIG_EPHY_IDDQ); 3527*7678SYong.Tan@Sun.COM (void) bge_reg_get32(bgep, MISC_CONFIG_REG); /* flush */ 3528*7678SYong.Tan@Sun.COM drv_usecwait(40); 3529*7678SYong.Tan@Sun.COM } 3530*7678SYong.Tan@Sun.COM 35311369Sdduvall /* 35321369Sdduvall * Steps 30-31: Configure MAC local memory pool & DMA pool registers 35331369Sdduvall * 35341369Sdduvall * If the mbuf_length is specified as 0, we just leave these at 35351369Sdduvall * their hardware defaults, rather than explicitly setting them. 35361369Sdduvall * As the Broadcom HRM,driver better not change the parameters 35371369Sdduvall * when the chipsets is 5705/5788/5721/5751/5714 and 5715. 35381369Sdduvall */ 35391369Sdduvall if ((bgep->chipid.mbuf_length != 0) && 35404588Sml149210 (DEVICE_5704_SERIES_CHIPSETS(bgep))) { 35411369Sdduvall bge_reg_put32(bgep, MBUF_POOL_BASE_REG, 35424588Sml149210 bgep->chipid.mbuf_base); 35431369Sdduvall bge_reg_put32(bgep, MBUF_POOL_LENGTH_REG, 35444588Sml149210 bgep->chipid.mbuf_length); 35451369Sdduvall bge_reg_put32(bgep, DMAD_POOL_BASE_REG, 35464588Sml149210 DMAD_POOL_BASE_DEFAULT); 35471369Sdduvall bge_reg_put32(bgep, DMAD_POOL_LENGTH_REG, 35484588Sml149210 DMAD_POOL_LENGTH_DEFAULT); 35491369Sdduvall } 35501369Sdduvall 35511369Sdduvall /* 35521369Sdduvall * Step 32: configure MAC memory pool watermarks 35531369Sdduvall */ 35541369Sdduvall bge_reg_put32(bgep, RDMA_MBUF_LOWAT_REG, 35554588Sml149210 bgep->chipid.mbuf_lo_water_rdma); 35561369Sdduvall bge_reg_put32(bgep, MAC_RX_MBUF_LOWAT_REG, 35574588Sml149210 bgep->chipid.mbuf_lo_water_rmac); 35581369Sdduvall bge_reg_put32(bgep, MBUF_HIWAT_REG, 35594588Sml149210 bgep->chipid.mbuf_hi_water); 35601369Sdduvall 35611369Sdduvall /* 35621369Sdduvall * Step 33: configure DMA resource watermarks 35631369Sdduvall */ 35641369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 35651369Sdduvall bge_reg_put32(bgep, DMAD_POOL_LOWAT_REG, 35661369Sdduvall bge_dmad_lo_water); 35671369Sdduvall bge_reg_put32(bgep, DMAD_POOL_HIWAT_REG, 35681369Sdduvall bge_dmad_hi_water); 35691369Sdduvall } 35701369Sdduvall bge_reg_put32(bgep, LOWAT_MAX_RECV_FRAMES_REG, bge_lowat_recv_frames); 35711369Sdduvall 35721369Sdduvall /* 35731369Sdduvall * Steps 34-36: enable buffer manager & internal h/w queues 35741369Sdduvall */ 35751865Sdilpreet if (!bge_chip_enable_engine(bgep, BUFFER_MANAGER_MODE_REG, 35761865Sdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 35771865Sdilpreet retval = DDI_FAILURE; 35781865Sdilpreet if (!bge_chip_enable_engine(bgep, FTQ_RESET_REG, 0)) 35791865Sdilpreet retval = DDI_FAILURE; 35801369Sdduvall 35811369Sdduvall /* 35821369Sdduvall * Steps 37-39: initialise Receive Buffer (Producer) RCBs 35831369Sdduvall */ 35841369Sdduvall bge_reg_putrcb(bgep, STD_RCV_BD_RING_RCB_REG, 35854588Sml149210 &bgep->buff[BGE_STD_BUFF_RING].hw_rcb); 35861369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 35871369Sdduvall bge_reg_putrcb(bgep, JUMBO_RCV_BD_RING_RCB_REG, 35884588Sml149210 &bgep->buff[BGE_JUMBO_BUFF_RING].hw_rcb); 35891369Sdduvall bge_reg_putrcb(bgep, MINI_RCV_BD_RING_RCB_REG, 35904588Sml149210 &bgep->buff[BGE_MINI_BUFF_RING].hw_rcb); 35911369Sdduvall } 35921369Sdduvall 35931369Sdduvall /* 35941369Sdduvall * Step 40: set Receive Buffer Descriptor Ring replenish thresholds 35951369Sdduvall */ 35961369Sdduvall bge_reg_put32(bgep, STD_RCV_BD_REPLENISH_REG, bge_replenish_std); 35971369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 35981369Sdduvall bge_reg_put32(bgep, JUMBO_RCV_BD_REPLENISH_REG, 35991369Sdduvall bge_replenish_jumbo); 36001369Sdduvall bge_reg_put32(bgep, MINI_RCV_BD_REPLENISH_REG, 36011369Sdduvall bge_replenish_mini); 36021369Sdduvall } 36031369Sdduvall 36041369Sdduvall /* 36051369Sdduvall * Steps 41-43: clear Send Ring Producer Indices and initialise 36061369Sdduvall * Send Producer Rings (0x0100-0x01ff in NIC-local memory) 36071369Sdduvall */ 36081369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 36091369Sdduvall maxring = BGE_SEND_RINGS_MAX; 36101369Sdduvall else 36111369Sdduvall maxring = BGE_SEND_RINGS_MAX_5705; 36121369Sdduvall for (ring = 0; ring < maxring; ++ring) { 36131369Sdduvall bge_mbx_put(bgep, SEND_RING_HOST_INDEX_REG(ring), 0); 36141369Sdduvall bge_mbx_put(bgep, SEND_RING_NIC_INDEX_REG(ring), 0); 36151369Sdduvall bge_nic_putrcb(bgep, NIC_MEM_SEND_RING(ring), 36164588Sml149210 &bgep->send[ring].hw_rcb); 36171369Sdduvall } 36181369Sdduvall 36191369Sdduvall /* 36201369Sdduvall * Steps 44-45: initialise Receive Return Rings 36211369Sdduvall * (0x0200-0x02ff in NIC-local memory) 36221369Sdduvall */ 36231369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 36241369Sdduvall maxring = BGE_RECV_RINGS_MAX; 36251369Sdduvall else 36261369Sdduvall maxring = BGE_RECV_RINGS_MAX_5705; 36271369Sdduvall for (ring = 0; ring < maxring; ++ring) 36281369Sdduvall bge_nic_putrcb(bgep, NIC_MEM_RECV_RING(ring), 36294588Sml149210 &bgep->recv[ring].hw_rcb); 36301369Sdduvall 36311369Sdduvall /* 36321369Sdduvall * Step 46: initialise Receive Buffer (Producer) Ring indexes 36331369Sdduvall */ 36341369Sdduvall bge_mbx_put(bgep, RECV_STD_PROD_INDEX_REG, 0); 36351369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 36361369Sdduvall bge_mbx_put(bgep, RECV_JUMBO_PROD_INDEX_REG, 0); 36371369Sdduvall bge_mbx_put(bgep, RECV_MINI_PROD_INDEX_REG, 0); 36381369Sdduvall } 36391369Sdduvall /* 36401369Sdduvall * Step 47: configure the MAC unicast address 36411369Sdduvall * Step 48: configure the random backoff seed 36421369Sdduvall * Step 96: set up multicast filters 36431369Sdduvall */ 36441408Srandyf #ifdef BGE_IPMI_ASF 36451865Sdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) 36461408Srandyf #else 36471865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) 36481408Srandyf #endif 36491865Sdilpreet retval = DDI_FAILURE; 36501369Sdduvall 36511369Sdduvall /* 36521369Sdduvall * Step 49: configure the MTU 36531369Sdduvall */ 36541369Sdduvall mtu = bgep->chipid.ethmax_size+ETHERFCSL+VLAN_TAGSZ; 36551369Sdduvall bge_reg_put32(bgep, MAC_RX_MTU_SIZE_REG, mtu); 36561369Sdduvall 36571369Sdduvall /* 36581369Sdduvall * Step 50: configure the IPG et al 36591369Sdduvall */ 36601369Sdduvall bge_reg_put32(bgep, MAC_TX_LENGTHS_REG, MAC_TX_LENGTHS_DEFAULT); 36611369Sdduvall 36621369Sdduvall /* 36631369Sdduvall * Step 51: configure the default Rx Return Ring 36641369Sdduvall */ 36651369Sdduvall bge_reg_put32(bgep, RCV_RULES_CONFIG_REG, RCV_RULES_CONFIG_DEFAULT); 36661369Sdduvall 36671369Sdduvall /* 36681369Sdduvall * Steps 52-54: configure Receive List Placement, 36691369Sdduvall * and enable Receive List Placement Statistics 36701369Sdduvall */ 36711369Sdduvall bge_reg_put32(bgep, RCV_LP_CONFIG_REG, 36724588Sml149210 RCV_LP_CONFIG(bgep->chipid.rx_rings)); 36733534Szh199473 switch (MHCR_CHIP_ASIC_REV(bgep->chipid.asic_rev)) { 36743534Szh199473 case MHCR_CHIP_ASIC_REV_5700: 36753534Szh199473 case MHCR_CHIP_ASIC_REV_5701: 36763534Szh199473 case MHCR_CHIP_ASIC_REV_5703: 36773534Szh199473 case MHCR_CHIP_ASIC_REV_5704: 36783534Szh199473 bge_reg_put32(bgep, RCV_LP_STATS_ENABLE_MASK_REG, ~0); 36793534Szh199473 break; 36803534Szh199473 case MHCR_CHIP_ASIC_REV_5705: 36813534Szh199473 break; 36823534Szh199473 default: 36833534Szh199473 stats_mask = bge_reg_get32(bgep, RCV_LP_STATS_ENABLE_MASK_REG); 36843534Szh199473 stats_mask &= ~RCV_LP_STATS_DISABLE_MACTQ; 36853534Szh199473 bge_reg_put32(bgep, RCV_LP_STATS_ENABLE_MASK_REG, stats_mask); 36863534Szh199473 break; 36873534Szh199473 } 36881369Sdduvall bge_reg_set32(bgep, RCV_LP_STATS_CONTROL_REG, RCV_LP_STATS_ENABLE); 36891369Sdduvall 36901369Sdduvall if (bgep->chipid.rx_rings > 1) 36911369Sdduvall bge_init_recv_rule(bgep); 36921369Sdduvall 36931369Sdduvall /* 36941369Sdduvall * Steps 55-56: enable Send Data Initiator Statistics 36951369Sdduvall */ 36961369Sdduvall bge_reg_put32(bgep, SEND_INIT_STATS_ENABLE_MASK_REG, ~0); 36971369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 36981369Sdduvall bge_reg_put32(bgep, SEND_INIT_STATS_CONTROL_REG, 36991369Sdduvall SEND_INIT_STATS_ENABLE | SEND_INIT_STATS_FASTER); 37001369Sdduvall } else { 37011369Sdduvall bge_reg_put32(bgep, SEND_INIT_STATS_CONTROL_REG, 37021369Sdduvall SEND_INIT_STATS_ENABLE); 37031369Sdduvall } 37041369Sdduvall /* 37051369Sdduvall * Steps 57-58: stop (?) the Host Coalescing Engine 37061369Sdduvall */ 37071865Sdilpreet if (!bge_chip_disable_engine(bgep, HOST_COALESCE_MODE_REG, ~0)) 37081865Sdilpreet retval = DDI_FAILURE; 37091369Sdduvall 37101369Sdduvall /* 37111369Sdduvall * Steps 59-62: initialise Host Coalescing parameters 37121369Sdduvall */ 37131369Sdduvall bge_reg_put32(bgep, SEND_COALESCE_MAX_BD_REG, bge_tx_count_norm); 37141369Sdduvall bge_reg_put32(bgep, SEND_COALESCE_TICKS_REG, bge_tx_ticks_norm); 37151369Sdduvall bge_reg_put32(bgep, RCV_COALESCE_MAX_BD_REG, bge_rx_count_norm); 37161369Sdduvall bge_reg_put32(bgep, RCV_COALESCE_TICKS_REG, bge_rx_ticks_norm); 37171369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 37181369Sdduvall bge_reg_put32(bgep, SEND_COALESCE_INT_BD_REG, 37191369Sdduvall bge_tx_count_intr); 37201369Sdduvall bge_reg_put32(bgep, SEND_COALESCE_INT_TICKS_REG, 37211369Sdduvall bge_tx_ticks_intr); 37221369Sdduvall bge_reg_put32(bgep, RCV_COALESCE_INT_BD_REG, 37231369Sdduvall bge_rx_count_intr); 37241369Sdduvall bge_reg_put32(bgep, RCV_COALESCE_INT_TICKS_REG, 37251369Sdduvall bge_rx_ticks_intr); 37261369Sdduvall } 37271369Sdduvall 37281369Sdduvall /* 37291369Sdduvall * Steps 63-64: initialise status block & statistics 37301369Sdduvall * host memory addresses 37311369Sdduvall * The statistic block does not exist in some chipsets 37321369Sdduvall * Step 65: initialise Statistics Coalescing Tick Counter 37331369Sdduvall */ 37341369Sdduvall bge_reg_put64(bgep, STATUS_BLOCK_HOST_ADDR_REG, 37354588Sml149210 bgep->status_block.cookie.dmac_laddress); 37361369Sdduvall 37371369Sdduvall /* 37381369Sdduvall * Steps 66-67: initialise status block & statistics 37391369Sdduvall * NIC-local memory addresses 37401369Sdduvall */ 37411369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) { 37421369Sdduvall bge_reg_put64(bgep, STATISTICS_HOST_ADDR_REG, 37431369Sdduvall bgep->statistics.cookie.dmac_laddress); 37441369Sdduvall bge_reg_put32(bgep, STATISTICS_TICKS_REG, 37451369Sdduvall STATISTICS_TICKS_DEFAULT); 37461369Sdduvall bge_reg_put32(bgep, STATUS_BLOCK_BASE_ADDR_REG, 37471369Sdduvall NIC_MEM_STATUS_BLOCK); 37481369Sdduvall bge_reg_put32(bgep, STATISTICS_BASE_ADDR_REG, 37491369Sdduvall NIC_MEM_STATISTICS); 37501369Sdduvall } 37511369Sdduvall 37521369Sdduvall /* 37531369Sdduvall * Steps 68-71: start the Host Coalescing Engine, the Receive BD 37541369Sdduvall * Completion Engine, the Receive List Placement Engine, and the 37551369Sdduvall * Receive List selector.Pay attention:0x3400 is not exist in BCM5714 37561369Sdduvall * and BCM5715. 37571369Sdduvall */ 37581369Sdduvall if (bgep->chipid.tx_rings <= COALESCE_64_BYTE_RINGS && 37591369Sdduvall bgep->chipid.rx_rings <= COALESCE_64_BYTE_RINGS) 37601369Sdduvall coalmode = COALESCE_64_BYTE_STATUS; 37611369Sdduvall else 37621369Sdduvall coalmode = 0; 37631865Sdilpreet if (!bge_chip_enable_engine(bgep, HOST_COALESCE_MODE_REG, coalmode)) 37641865Sdilpreet retval = DDI_FAILURE; 37651865Sdilpreet if (!bge_chip_enable_engine(bgep, RCV_BD_COMPLETION_MODE_REG, 37661865Sdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 37671865Sdilpreet retval = DDI_FAILURE; 37681865Sdilpreet if (!bge_chip_enable_engine(bgep, RCV_LIST_PLACEMENT_MODE_REG, 0)) 37691865Sdilpreet retval = DDI_FAILURE; 37701369Sdduvall 37711369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 37721865Sdilpreet if (!bge_chip_enable_engine(bgep, RCV_LIST_SELECTOR_MODE_REG, 37731865Sdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 37741865Sdilpreet retval = DDI_FAILURE; 37751369Sdduvall 37761369Sdduvall /* 37771369Sdduvall * Step 72: Enable MAC DMA engines 37781369Sdduvall * Step 73: Clear & enable MAC statistics 37791369Sdduvall */ 37801369Sdduvall bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, 37814588Sml149210 ETHERNET_MODE_ENABLE_FHDE | 37824588Sml149210 ETHERNET_MODE_ENABLE_RDE | 37834588Sml149210 ETHERNET_MODE_ENABLE_TDE); 37841369Sdduvall bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, 37854588Sml149210 ETHERNET_MODE_ENABLE_TX_STATS | 37864588Sml149210 ETHERNET_MODE_ENABLE_RX_STATS | 37874588Sml149210 ETHERNET_MODE_CLEAR_TX_STATS | 37884588Sml149210 ETHERNET_MODE_CLEAR_RX_STATS); 37891369Sdduvall 37901369Sdduvall /* 37911369Sdduvall * Step 74: configure the MLCR (Miscellaneous Local Control 37921369Sdduvall * Register); not required, as we set up the MLCR in step 10 37931369Sdduvall * (part of the reset code) above. 37941369Sdduvall * 37951369Sdduvall * Step 75: clear Interrupt Mailbox 0 37961369Sdduvall */ 37971369Sdduvall bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG, 0); 37981369Sdduvall 37991369Sdduvall /* 38001369Sdduvall * Steps 76-87: Gentlemen, start your engines ... 38011369Sdduvall * 38021369Sdduvall * Enable the DMA Completion Engine, the Write DMA Engine, 38031369Sdduvall * the Read DMA Engine, Receive Data Completion Engine, 38041369Sdduvall * the MBuf Cluster Free Engine, the Send Data Completion Engine, 38051369Sdduvall * the Send BD Completion Engine, the Receive BD Initiator Engine, 38061369Sdduvall * the Receive Data Initiator Engine, the Send Data Initiator Engine, 38071369Sdduvall * the Send BD Initiator Engine, and the Send BD Selector Engine. 38081369Sdduvall * 38091369Sdduvall * Beware exhaust fumes? 38101369Sdduvall */ 38111369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 38121865Sdilpreet if (!bge_chip_enable_engine(bgep, DMA_COMPLETION_MODE_REG, 0)) 38131865Sdilpreet retval = DDI_FAILURE; 38144330Sml149210 dma_wrprio = (bge_dma_wrprio << DMA_PRIORITY_SHIFT) | 38154588Sml149210 ALL_DMA_ATTN_BITS; 3816*7678SYong.Tan@Sun.COM if ((MHCR_CHIP_ASIC_REV(bgep->chipid.asic_rev) == 3817*7678SYong.Tan@Sun.COM MHCR_CHIP_ASIC_REV_5755) || 3818*7678SYong.Tan@Sun.COM (MHCR_CHIP_ASIC_REV(bgep->chipid.asic_rev) == 3819*7678SYong.Tan@Sun.COM MHCR_CHIP_ASIC_REV_5906)) { 38204330Sml149210 dma_wrprio |= DMA_STATUS_TAG_FIX_CQ12384; 38214330Sml149210 } 38221865Sdilpreet if (!bge_chip_enable_engine(bgep, WRITE_DMA_MODE_REG, 38234588Sml149210 dma_wrprio)) 38241865Sdilpreet retval = DDI_FAILURE; 38251865Sdilpreet if (!bge_chip_enable_engine(bgep, READ_DMA_MODE_REG, 38261865Sdilpreet (bge_dma_rdprio << DMA_PRIORITY_SHIFT) | ALL_DMA_ATTN_BITS)) 38271865Sdilpreet retval = DDI_FAILURE; 38281865Sdilpreet if (!bge_chip_enable_engine(bgep, RCV_DATA_COMPLETION_MODE_REG, 38291865Sdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 38301865Sdilpreet retval = DDI_FAILURE; 38311369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 38321865Sdilpreet if (!bge_chip_enable_engine(bgep, 38331865Sdilpreet MBUF_CLUSTER_FREE_MODE_REG, 0)) 38341865Sdilpreet retval = DDI_FAILURE; 38351865Sdilpreet if (!bge_chip_enable_engine(bgep, SEND_DATA_COMPLETION_MODE_REG, 0)) 38361865Sdilpreet retval = DDI_FAILURE; 38371865Sdilpreet if (!bge_chip_enable_engine(bgep, SEND_BD_COMPLETION_MODE_REG, 38381865Sdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 38391865Sdilpreet retval = DDI_FAILURE; 38401865Sdilpreet if (!bge_chip_enable_engine(bgep, RCV_BD_INITIATOR_MODE_REG, 38411865Sdilpreet RCV_BD_DISABLED_RING_ATTN)) 38421865Sdilpreet retval = DDI_FAILURE; 38431865Sdilpreet if (!bge_chip_enable_engine(bgep, RCV_DATA_BD_INITIATOR_MODE_REG, 38441865Sdilpreet RCV_DATA_BD_ILL_RING_ATTN)) 38451865Sdilpreet retval = DDI_FAILURE; 38461865Sdilpreet if (!bge_chip_enable_engine(bgep, SEND_DATA_INITIATOR_MODE_REG, 0)) 38471865Sdilpreet retval = DDI_FAILURE; 38481865Sdilpreet if (!bge_chip_enable_engine(bgep, SEND_BD_INITIATOR_MODE_REG, 38491865Sdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 38501865Sdilpreet retval = DDI_FAILURE; 38511865Sdilpreet if (!bge_chip_enable_engine(bgep, SEND_BD_SELECTOR_MODE_REG, 38521865Sdilpreet STATE_MACHINE_ATTN_ENABLE_BIT)) 38531865Sdilpreet retval = DDI_FAILURE; 38541369Sdduvall 38551369Sdduvall /* 38561369Sdduvall * Step 88: download firmware -- doesn't apply 38571369Sdduvall * Steps 89-90: enable Transmit & Receive MAC Engines 38581369Sdduvall */ 38591865Sdilpreet if (!bge_chip_enable_engine(bgep, TRANSMIT_MAC_MODE_REG, 0)) 38601865Sdilpreet retval = DDI_FAILURE; 38611408Srandyf #ifdef BGE_IPMI_ASF 38621865Sdilpreet if (!bgep->asf_enabled) { 38631865Sdilpreet if (!bge_chip_enable_engine(bgep, RECEIVE_MAC_MODE_REG, 38641865Sdilpreet RECEIVE_MODE_KEEP_VLAN_TAG)) 38651865Sdilpreet retval = DDI_FAILURE; 38661408Srandyf } else { 38671865Sdilpreet if (!bge_chip_enable_engine(bgep, RECEIVE_MAC_MODE_REG, 0)) 38681865Sdilpreet retval = DDI_FAILURE; 38691408Srandyf } 38701408Srandyf #else 38711865Sdilpreet if (!bge_chip_enable_engine(bgep, RECEIVE_MAC_MODE_REG, 38721865Sdilpreet RECEIVE_MODE_KEEP_VLAN_TAG)) 38731865Sdilpreet retval = DDI_FAILURE; 38741408Srandyf #endif 38751369Sdduvall 38761369Sdduvall /* 38771369Sdduvall * Step 91: disable auto-polling of PHY status 38781369Sdduvall */ 38791369Sdduvall bge_reg_put32(bgep, MI_MODE_REG, MI_MODE_DEFAULT); 38801369Sdduvall 38811369Sdduvall /* 38821369Sdduvall * Step 92: configure D0 power state (not required) 38831369Sdduvall * Step 93: initialise LED control register () 38841369Sdduvall */ 38851369Sdduvall ledctl = LED_CONTROL_DEFAULT; 38861369Sdduvall switch (bgep->chipid.device) { 38871369Sdduvall case DEVICE_ID_5700: 38881369Sdduvall case DEVICE_ID_5700x: 38891369Sdduvall case DEVICE_ID_5701: 38901369Sdduvall /* 38911369Sdduvall * Switch to 5700 (MAC) mode on these older chips 38921369Sdduvall */ 38931369Sdduvall ledctl &= ~LED_CONTROL_LED_MODE_MASK; 38941369Sdduvall ledctl |= LED_CONTROL_LED_MODE_5700; 38951369Sdduvall break; 38961369Sdduvall 38971369Sdduvall default: 38981369Sdduvall break; 38991369Sdduvall } 39001369Sdduvall bge_reg_put32(bgep, ETHERNET_MAC_LED_CONTROL_REG, ledctl); 39011369Sdduvall 39021369Sdduvall /* 39031369Sdduvall * Step 94: activate link 39041369Sdduvall */ 39051369Sdduvall bge_reg_put32(bgep, MI_STATUS_REG, MI_STATUS_LINK); 39061369Sdduvall 39071369Sdduvall /* 39081369Sdduvall * Step 95: set up physical layer (PHY/SerDes) 39091369Sdduvall * restart autoneg (if required) 39101369Sdduvall */ 39111369Sdduvall if (reset_phys) 39121865Sdilpreet if (bge_phys_update(bgep) == DDI_FAILURE) 39131865Sdilpreet retval = DDI_FAILURE; 39141369Sdduvall 39151369Sdduvall /* 39161369Sdduvall * Extra step (DSG): hand over all the Receive Buffers to the chip 39171369Sdduvall */ 39181369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_USED; ++ring) 39191369Sdduvall bge_mbx_put(bgep, bgep->buff[ring].chip_mbx_reg, 39204588Sml149210 bgep->buff[ring].rf_next); 39211369Sdduvall 39221369Sdduvall /* 39231369Sdduvall * MSI bits:The least significant MSI 16-bit word. 39241369Sdduvall * ISR will be triggered different. 39251369Sdduvall */ 39261369Sdduvall if (bgep->intr_type == DDI_INTR_TYPE_MSI) 39271369Sdduvall bge_reg_set32(bgep, HOST_COALESCE_MODE_REG, 0x70); 39281369Sdduvall 39291369Sdduvall /* 39301369Sdduvall * Extra step (DSG): select which interrupts are enabled 39311369Sdduvall * 39321369Sdduvall * Program the Ethernet MAC engine to signal attention on 39331369Sdduvall * Link Change events, then enable interrupts on MAC, DMA, 39341369Sdduvall * and FLOW attention signals. 39351369Sdduvall */ 39361369Sdduvall bge_reg_set32(bgep, ETHERNET_MAC_EVENT_ENABLE_REG, 39374588Sml149210 ETHERNET_EVENT_LINK_INT | 39384588Sml149210 ETHERNET_STATUS_PCS_ERROR_INT); 39391408Srandyf #ifdef BGE_IPMI_ASF 39401408Srandyf if (bgep->asf_enabled) { 39411408Srandyf bge_reg_set32(bgep, MODE_CONTROL_REG, 39424588Sml149210 MODE_INT_ON_FLOW_ATTN | 39434588Sml149210 MODE_INT_ON_DMA_ATTN | 39444588Sml149210 MODE_HOST_STACK_UP| 39454588Sml149210 MODE_INT_ON_MAC_ATTN); 39461408Srandyf } else { 39471408Srandyf #endif 39481408Srandyf bge_reg_set32(bgep, MODE_CONTROL_REG, 39494588Sml149210 MODE_INT_ON_FLOW_ATTN | 39504588Sml149210 MODE_INT_ON_DMA_ATTN | 39514588Sml149210 MODE_INT_ON_MAC_ATTN); 39521408Srandyf #ifdef BGE_IPMI_ASF 39531408Srandyf } 39541408Srandyf #endif 39551369Sdduvall 39561369Sdduvall /* 39571369Sdduvall * Step 97: enable PCI interrupts!!! 39581369Sdduvall */ 39591369Sdduvall if (bgep->intr_type == DDI_INTR_TYPE_FIXED) 39601369Sdduvall bge_cfg_clr32(bgep, PCI_CONF_BGE_MHCR, 39611369Sdduvall MHCR_MASK_PCI_INT_OUTPUT); 39621369Sdduvall 39631369Sdduvall /* 39641369Sdduvall * All done! 39651369Sdduvall */ 39661369Sdduvall bgep->bge_chip_state = BGE_CHIP_RUNNING; 39671865Sdilpreet return (retval); 39681369Sdduvall } 39691369Sdduvall 39701369Sdduvall 39711369Sdduvall /* 39721369Sdduvall * ========== Hardware interrupt handler ========== 39731369Sdduvall */ 39741369Sdduvall 39751369Sdduvall #undef BGE_DBG 39761369Sdduvall #define BGE_DBG BGE_DBG_INT /* debug flag for this code */ 39771369Sdduvall 39781369Sdduvall /* 39791369Sdduvall * Sync the status block, then atomically clear the specified bits in 39801369Sdduvall * the <flags-and-tag> field of the status block. 39811369Sdduvall * the <flags> word of the status block, returning the value of the 39821369Sdduvall * <tag> and the <flags> before the bits were cleared. 39831369Sdduvall */ 39841865Sdilpreet static int bge_status_sync(bge_t *bgep, uint64_t bits, uint64_t *flags); 39851369Sdduvall #pragma inline(bge_status_sync) 39861369Sdduvall 39871865Sdilpreet static int 39881865Sdilpreet bge_status_sync(bge_t *bgep, uint64_t bits, uint64_t *flags) 39891369Sdduvall { 39901369Sdduvall bge_status_t *bsp; 39911865Sdilpreet int retval; 39921369Sdduvall 39931369Sdduvall BGE_TRACE(("bge_status_sync($%p, 0x%llx)", 39944588Sml149210 (void *)bgep, bits)); 39951369Sdduvall 39961369Sdduvall ASSERT(bgep->bge_guard == BGE_GUARD); 39971369Sdduvall 39981369Sdduvall DMA_SYNC(bgep->status_block, DDI_DMA_SYNC_FORKERNEL); 39991865Sdilpreet retval = bge_check_dma_handle(bgep, bgep->status_block.dma_hdl); 40001865Sdilpreet if (retval != DDI_FM_OK) 40011865Sdilpreet return (retval); 40021865Sdilpreet 40031369Sdduvall bsp = DMA_VPTR(bgep->status_block); 40041865Sdilpreet *flags = bge_atomic_clr64(&bsp->flags_n_tag, bits); 40051369Sdduvall 40061369Sdduvall BGE_DEBUG(("bge_status_sync($%p, 0x%llx) returning 0x%llx", 40074588Sml149210 (void *)bgep, bits, *flags)); 40081865Sdilpreet 40091865Sdilpreet return (retval); 40101369Sdduvall } 40111369Sdduvall 40125903Ssowmini void bge_wake_factotum(bge_t *bgep); 40131369Sdduvall #pragma inline(bge_wake_factotum) 40141369Sdduvall 40155903Ssowmini void 40161369Sdduvall bge_wake_factotum(bge_t *bgep) 40171369Sdduvall { 40181369Sdduvall mutex_enter(bgep->softintrlock); 40191369Sdduvall if (bgep->factotum_flag == 0) { 40201369Sdduvall bgep->factotum_flag = 1; 40211369Sdduvall ddi_trigger_softintr(bgep->factotum_id); 40221369Sdduvall } 40231369Sdduvall mutex_exit(bgep->softintrlock); 40241369Sdduvall } 40251369Sdduvall 40261369Sdduvall /* 40271369Sdduvall * bge_intr() -- handle chip interrupts 40281369Sdduvall */ 40291369Sdduvall uint_t bge_intr(caddr_t arg1, caddr_t arg2); 40301369Sdduvall #pragma no_inline(bge_intr) 40311369Sdduvall 40321369Sdduvall uint_t 40331369Sdduvall bge_intr(caddr_t arg1, caddr_t arg2) 40341369Sdduvall { 40357099Syt223700 bge_t *bgep = (void *)arg1; /* private device info */ 40361369Sdduvall bge_status_t *bsp; 40371369Sdduvall uint64_t flags; 40383907Szh199473 uint32_t regval; 40391369Sdduvall uint_t result; 40403918Sml149210 int retval, loop_cnt = 0; 40411369Sdduvall 40421369Sdduvall BGE_TRACE(("bge_intr($%p) ($%p)", arg1, arg2)); 40431369Sdduvall 40441369Sdduvall /* 40451369Sdduvall * GLD v2 checks that s/w setup is complete before passing 40461369Sdduvall * interrupts to this routine, thus eliminating the old 40471369Sdduvall * (and well-known) race condition around ddi_add_intr() 40481369Sdduvall */ 40491369Sdduvall ASSERT(bgep->progress & PROGRESS_HWINT); 40501369Sdduvall 40511369Sdduvall result = DDI_INTR_UNCLAIMED; 40521369Sdduvall mutex_enter(bgep->genlock); 40531369Sdduvall 40543907Szh199473 if (bgep->intr_type == DDI_INTR_TYPE_FIXED) { 40551369Sdduvall /* 40563907Szh199473 * Check whether chip's says it's asserting #INTA; 40573907Szh199473 * if not, don't process or claim the interrupt. 40583907Szh199473 * 40593907Szh199473 * Note that the PCI signal is active low, so the 40603907Szh199473 * bit is *zero* when the interrupt is asserted. 40611369Sdduvall */ 40623907Szh199473 regval = bge_reg_get32(bgep, MISC_LOCAL_CONTROL_REG); 40633907Szh199473 if (regval & MLCR_INTA_STATE) { 40643907Szh199473 if (bge_check_acc_handle(bgep, bgep->io_handle) 40653907Szh199473 != DDI_FM_OK) 40661865Sdilpreet goto chip_stop; 40673907Szh199473 mutex_exit(bgep->genlock); 40683907Szh199473 return (result); 40691865Sdilpreet } 40701369Sdduvall 40711369Sdduvall /* 40723907Szh199473 * Block further PCI interrupts ... 40733907Szh199473 */ 40743907Szh199473 bge_reg_set32(bgep, PCI_CONF_BGE_MHCR, 40753907Szh199473 MHCR_MASK_PCI_INT_OUTPUT); 40763907Szh199473 40773907Szh199473 } else { 40783907Szh199473 /* 40793907Szh199473 * Check MSI status 40801369Sdduvall */ 40813907Szh199473 regval = bge_reg_get32(bgep, MSI_STATUS_REG); 40823907Szh199473 if (regval & MSI_ERROR_ATTENTION) { 40833907Szh199473 BGE_REPORT((bgep, "msi error attention," 40843907Szh199473 " status=0x%x", regval)); 40853907Szh199473 bge_reg_put32(bgep, MSI_STATUS_REG, regval); 40863907Szh199473 } 40873907Szh199473 } 40883907Szh199473 40893907Szh199473 result = DDI_INTR_CLAIMED; 40903907Szh199473 40913907Szh199473 BGE_DEBUG(("bge_intr($%p) ($%p) regval 0x%08x", arg1, arg2, regval)); 40923907Szh199473 40933907Szh199473 /* 40943907Szh199473 * Sync the status block and grab the flags-n-tag from it. 40953907Szh199473 * We count the number of interrupts where there doesn't 40963907Szh199473 * seem to have been a DMA update of the status block; if 40973907Szh199473 * it *has* been updated, the counter will be cleared in 40983907Szh199473 * the while() loop below ... 40993907Szh199473 */ 41003907Szh199473 bgep->missed_dmas += 1; 41013907Szh199473 bsp = DMA_VPTR(bgep->status_block); 41023918Sml149210 for (loop_cnt = 0; loop_cnt < bge_intr_max_loop; loop_cnt++) { 41033907Szh199473 if (bgep->bge_chip_state != BGE_CHIP_RUNNING) { 41041369Sdduvall /* 41053907Szh199473 * bge_chip_stop() may have freed dma area etc 41063907Szh199473 * while we were in this interrupt handler - 41073907Szh199473 * better not call bge_status_sync() 41081369Sdduvall */ 41093907Szh199473 (void) bge_check_acc_handle(bgep, 41103907Szh199473 bgep->io_handle); 41111369Sdduvall mutex_exit(bgep->genlock); 41123907Szh199473 return (DDI_INTR_CLAIMED); 41133907Szh199473 } 41143907Szh199473 retval = bge_status_sync(bgep, STATUS_FLAG_UPDATED, 41153907Szh199473 &flags); 41163907Szh199473 if (retval != DDI_FM_OK) { 41173907Szh199473 bgep->bge_dma_error = B_TRUE; 41183907Szh199473 goto chip_stop; 41191369Sdduvall } 41201369Sdduvall 41213907Szh199473 if (!(flags & STATUS_FLAG_UPDATED)) 41223907Szh199473 break; 41233907Szh199473 41243907Szh199473 /* 41253907Szh199473 * Tell the chip that we're processing the interrupt 41263907Szh199473 */ 41273907Szh199473 bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG, 41283907Szh199473 INTERRUPT_MBOX_DISABLE(flags)); 41293907Szh199473 if (bge_check_acc_handle(bgep, bgep->io_handle) != 41303907Szh199473 DDI_FM_OK) 41313907Szh199473 goto chip_stop; 41323907Szh199473 41331369Sdduvall /* 41343907Szh199473 * Drop the mutex while we: 41353907Szh199473 * Receive any newly-arrived packets 41363907Szh199473 * Recycle any newly-finished send buffers 41371369Sdduvall */ 41383907Szh199473 bgep->bge_intr_running = B_TRUE; 41393907Szh199473 mutex_exit(bgep->genlock); 41403907Szh199473 bge_receive(bgep, bsp); 41413907Szh199473 bge_recycle(bgep, bsp); 41423907Szh199473 mutex_enter(bgep->genlock); 41433907Szh199473 bgep->bge_intr_running = B_FALSE; 41441369Sdduvall 41451369Sdduvall /* 41463907Szh199473 * Tell the chip we've finished processing, and 41473907Szh199473 * give it the tag that we got from the status 41483907Szh199473 * block earlier, so that it knows just how far 41493907Szh199473 * we've gone. If it's got more for us to do, 41503907Szh199473 * it will now update the status block and try 41513907Szh199473 * to assert an interrupt (but we've got the 41523907Szh199473 * #INTA blocked at present). If we see the 41533907Szh199473 * update, we'll loop around to do some more. 41543907Szh199473 * Eventually we'll get out of here ... 41553907Szh199473 */ 41563907Szh199473 bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG, 41573907Szh199473 INTERRUPT_MBOX_ENABLE(flags)); 41586546Sgh162552 if (bgep->chipid.pci_type == BGE_PCI_E) 41596546Sgh162552 (void) bge_mbx_get(bgep, INTERRUPT_MBOX_0_REG); 41603907Szh199473 bgep->missed_dmas = 0; 41613907Szh199473 } 41623907Szh199473 41633907Szh199473 /* 41643907Szh199473 * Check for exceptional conditions that we need to handle 41653907Szh199473 * 41663907Szh199473 * Link status changed 41673907Szh199473 * Status block not updated 41683907Szh199473 */ 41693907Szh199473 if (flags & STATUS_FLAG_LINK_CHANGED) 41703907Szh199473 bge_wake_factotum(bgep); 41713907Szh199473 41723907Szh199473 if (bgep->missed_dmas) { 41733907Szh199473 /* 41743907Szh199473 * Probably due to the internal status tag not 41753907Szh199473 * being reset. Force a status block update now; 41763907Szh199473 * this should ensure that we get an update and 41773907Szh199473 * a new interrupt. After that, we should be in 41783907Szh199473 * sync again ... 41791369Sdduvall */ 41803907Szh199473 BGE_REPORT((bgep, "interrupt: flags 0x%llx - " 41813907Szh199473 "not updated?", flags)); 41823907Szh199473 bgep->missed_updates++; 41833907Szh199473 bge_reg_set32(bgep, HOST_COALESCE_MODE_REG, 41843907Szh199473 COALESCE_NOW); 41853907Szh199473 41863907Szh199473 if (bgep->missed_dmas >= bge_dma_miss_limit) { 41873907Szh199473 /* 41883907Szh199473 * If this happens multiple times in a row, 41893907Szh199473 * it means DMA is just not working. Maybe 41903907Szh199473 * the chip's failed, or maybe there's a 41913907Szh199473 * problem on the PCI bus or in the host-PCI 41923907Szh199473 * bridge (Tomatillo). 41933907Szh199473 * 41943907Szh199473 * At all events, we want to stop further 41953907Szh199473 * interrupts and let the recovery code take 41963907Szh199473 * over to see whether anything can be done 41973907Szh199473 * about it ... 41983907Szh199473 */ 41993907Szh199473 bge_fm_ereport(bgep, 42003907Szh199473 DDI_FM_DEVICE_BADINT_LIMIT); 42013907Szh199473 goto chip_stop; 42021369Sdduvall } 42031369Sdduvall } 42041369Sdduvall 42053907Szh199473 /* 42063907Szh199473 * Reenable assertion of #INTA, unless there's a DMA fault 42073907Szh199473 */ 42083907Szh199473 if (bgep->intr_type == DDI_INTR_TYPE_FIXED) { 42093907Szh199473 bge_reg_clr32(bgep, PCI_CONF_BGE_MHCR, 42103907Szh199473 MHCR_MASK_PCI_INT_OUTPUT); 42113907Szh199473 if (bge_check_acc_handle(bgep, bgep->cfg_handle) != 42123907Szh199473 DDI_FM_OK) 42133907Szh199473 goto chip_stop; 42143907Szh199473 } 42153907Szh199473 42161865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 42171865Sdilpreet goto chip_stop; 42181865Sdilpreet 42191865Sdilpreet mutex_exit(bgep->genlock); 42201865Sdilpreet return (result); 42211865Sdilpreet 42221865Sdilpreet chip_stop: 42231865Sdilpreet #ifdef BGE_IPMI_ASF 42241865Sdilpreet if (bgep->asf_enabled && bgep->asf_status == ASF_STAT_RUN) { 42251865Sdilpreet /* 42261865Sdilpreet * We must stop ASF heart beat before 42271865Sdilpreet * bge_chip_stop(), otherwise some 42281865Sdilpreet * computers (ex. IBM HS20 blade 42291865Sdilpreet * server) may crash. 42301865Sdilpreet */ 42311865Sdilpreet bge_asf_update_status(bgep); 42321865Sdilpreet bge_asf_stop_timer(bgep); 42331865Sdilpreet bgep->asf_status = ASF_STAT_STOP; 42341865Sdilpreet 42351865Sdilpreet bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 42361865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 42371865Sdilpreet } 42381865Sdilpreet #endif 42391865Sdilpreet bge_chip_stop(bgep, B_TRUE); 42401865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 42411369Sdduvall mutex_exit(bgep->genlock); 42421369Sdduvall return (result); 42431369Sdduvall } 42441369Sdduvall 42451369Sdduvall /* 42461369Sdduvall * ========== Factotum, implemented as a softint handler ========== 42471369Sdduvall */ 42481369Sdduvall 42491369Sdduvall #undef BGE_DBG 42501369Sdduvall #define BGE_DBG BGE_DBG_FACT /* debug flag for this code */ 42511369Sdduvall 42521369Sdduvall static void bge_factotum_error_handler(bge_t *bgep); 42531369Sdduvall #pragma no_inline(bge_factotum_error_handler) 42541369Sdduvall 42551369Sdduvall static void 42561369Sdduvall bge_factotum_error_handler(bge_t *bgep) 42571369Sdduvall { 42581369Sdduvall uint32_t flow; 42591369Sdduvall uint32_t rdma; 42601369Sdduvall uint32_t wdma; 42611369Sdduvall uint32_t tmac; 42621369Sdduvall uint32_t rmac; 42631369Sdduvall uint32_t rxrs; 42641369Sdduvall uint32_t txrs = 0; 42651369Sdduvall 42661369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 42671369Sdduvall 42681369Sdduvall /* 42691369Sdduvall * Read all the registers that show the possible 42701369Sdduvall * reasons for the ERROR bit to be asserted 42711369Sdduvall */ 42721369Sdduvall flow = bge_reg_get32(bgep, FLOW_ATTN_REG); 42731369Sdduvall rdma = bge_reg_get32(bgep, READ_DMA_STATUS_REG); 42741369Sdduvall wdma = bge_reg_get32(bgep, WRITE_DMA_STATUS_REG); 42751369Sdduvall tmac = bge_reg_get32(bgep, TRANSMIT_MAC_STATUS_REG); 42761369Sdduvall rmac = bge_reg_get32(bgep, RECEIVE_MAC_STATUS_REG); 42771369Sdduvall rxrs = bge_reg_get32(bgep, RX_RISC_STATE_REG); 42781369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 42791369Sdduvall txrs = bge_reg_get32(bgep, TX_RISC_STATE_REG); 42801369Sdduvall 42811369Sdduvall BGE_DEBUG(("factotum($%p) flow 0x%x rdma 0x%x wdma 0x%x", 42824588Sml149210 (void *)bgep, flow, rdma, wdma)); 42831369Sdduvall BGE_DEBUG(("factotum($%p) tmac 0x%x rmac 0x%x rxrs 0x%08x txrs 0x%08x", 42844588Sml149210 (void *)bgep, tmac, rmac, rxrs, txrs)); 42851369Sdduvall 42861369Sdduvall /* 42871369Sdduvall * For now, just clear all the errors ... 42881369Sdduvall */ 42891369Sdduvall if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 42901369Sdduvall bge_reg_put32(bgep, TX_RISC_STATE_REG, ~0); 42911369Sdduvall bge_reg_put32(bgep, RX_RISC_STATE_REG, ~0); 42921369Sdduvall bge_reg_put32(bgep, RECEIVE_MAC_STATUS_REG, ~0); 42931369Sdduvall bge_reg_put32(bgep, WRITE_DMA_STATUS_REG, ~0); 42941369Sdduvall bge_reg_put32(bgep, READ_DMA_STATUS_REG, ~0); 42951369Sdduvall bge_reg_put32(bgep, FLOW_ATTN_REG, ~0); 42961369Sdduvall } 42971369Sdduvall 42981369Sdduvall /* 42991369Sdduvall * Handler for hardware link state change. 43001369Sdduvall * 43011369Sdduvall * When this routine is called, the hardware link state has changed 43021369Sdduvall * and the new state is reflected in the param_* variables. Here 43034403Sgd78059 * we must update the softstate and reprogram the MAC to match. 43041369Sdduvall */ 43051369Sdduvall static void bge_factotum_link_handler(bge_t *bgep); 43061369Sdduvall #pragma no_inline(bge_factotum_link_handler) 43071369Sdduvall 43081369Sdduvall static void 43091369Sdduvall bge_factotum_link_handler(bge_t *bgep) 43101369Sdduvall { 43111369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 43121369Sdduvall 43131369Sdduvall /* 43141369Sdduvall * Update the s/w link_state 43151369Sdduvall */ 43161369Sdduvall if (bgep->param_link_up) 43171369Sdduvall bgep->link_state = LINK_STATE_UP; 43181369Sdduvall else 43191369Sdduvall bgep->link_state = LINK_STATE_DOWN; 43201369Sdduvall 43211369Sdduvall /* 43221369Sdduvall * Reprogram the MAC modes to match 43231369Sdduvall */ 43241369Sdduvall bge_sync_mac_modes(bgep); 43251369Sdduvall } 43261369Sdduvall 43271865Sdilpreet static boolean_t bge_factotum_link_check(bge_t *bgep, int *dma_state); 43281369Sdduvall #pragma no_inline(bge_factotum_link_check) 43291369Sdduvall 43301369Sdduvall static boolean_t 43311865Sdilpreet bge_factotum_link_check(bge_t *bgep, int *dma_state) 43321369Sdduvall { 43331369Sdduvall boolean_t check; 43341369Sdduvall uint64_t flags; 43351369Sdduvall uint32_t tmac_status; 43361369Sdduvall 43371369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 43381369Sdduvall 43391369Sdduvall /* 43401369Sdduvall * Get & clear the writable status bits in the Tx status register 43411369Sdduvall * (some bits are write-1-to-clear, others are just readonly). 43421369Sdduvall */ 43431369Sdduvall tmac_status = bge_reg_get32(bgep, TRANSMIT_MAC_STATUS_REG); 43441369Sdduvall bge_reg_put32(bgep, TRANSMIT_MAC_STATUS_REG, tmac_status); 43451369Sdduvall 43461369Sdduvall /* 43471369Sdduvall * Get & clear the ERROR and LINK_CHANGED bits from the status block 43481369Sdduvall */ 43491865Sdilpreet *dma_state = bge_status_sync(bgep, STATUS_FLAG_ERROR | 43501865Sdilpreet STATUS_FLAG_LINK_CHANGED, &flags); 43511865Sdilpreet if (*dma_state != DDI_FM_OK) 43521865Sdilpreet return (B_FALSE); 43531369Sdduvall 43541369Sdduvall /* 43551369Sdduvall * Clear any errors flagged in the status block ... 43561369Sdduvall */ 43571369Sdduvall if (flags & STATUS_FLAG_ERROR) 43581369Sdduvall bge_factotum_error_handler(bgep); 43591369Sdduvall 43601369Sdduvall /* 43611369Sdduvall * We need to check the link status if: 43621369Sdduvall * the status block says there's been a link change 43631369Sdduvall * or there's any discrepancy between the various 43641369Sdduvall * flags indicating the link state (link_state, 43651369Sdduvall * param_link_up, and the LINK STATE bit in the 43661369Sdduvall * Transmit MAC status register). 43671369Sdduvall */ 43681369Sdduvall check = (flags & STATUS_FLAG_LINK_CHANGED) != 0; 43691369Sdduvall switch (bgep->link_state) { 43701369Sdduvall case LINK_STATE_UP: 43711369Sdduvall check |= (bgep->param_link_up == B_FALSE); 43721369Sdduvall check |= ((tmac_status & TRANSMIT_STATUS_LINK_UP) == 0); 43731369Sdduvall break; 43741369Sdduvall 43751369Sdduvall case LINK_STATE_DOWN: 43761369Sdduvall check |= (bgep->param_link_up != B_FALSE); 43771369Sdduvall check |= ((tmac_status & TRANSMIT_STATUS_LINK_UP) != 0); 43781369Sdduvall break; 43791369Sdduvall 43801369Sdduvall default: 43811369Sdduvall check = B_TRUE; 43821369Sdduvall break; 43831369Sdduvall } 43841369Sdduvall 43851369Sdduvall /* 43861369Sdduvall * If <check> is false, we're sure the link hasn't changed. 43871369Sdduvall * If true, however, it's not yet definitive; we have to call 43881369Sdduvall * bge_phys_check() to determine whether the link has settled 43891369Sdduvall * into a new state yet ... and if it has, then call the link 43901369Sdduvall * state change handler.But when the chip is 5700 in Dell 6650 43911369Sdduvall * ,even if check is false, the link may have changed.So we 43921369Sdduvall * have to call bge_phys_check() to determine the link state. 43931369Sdduvall */ 43941369Sdduvall if (check || bgep->chipid.device == DEVICE_ID_5700) { 43951369Sdduvall check = bge_phys_check(bgep); 43961369Sdduvall if (check) 43971369Sdduvall bge_factotum_link_handler(bgep); 43981369Sdduvall } 43991369Sdduvall 44001369Sdduvall return (check); 44011369Sdduvall } 44021369Sdduvall 44031369Sdduvall /* 44041369Sdduvall * Factotum routine to check for Tx stall, using the 'watchdog' counter 44051369Sdduvall */ 44061369Sdduvall static boolean_t bge_factotum_stall_check(bge_t *bgep); 44071369Sdduvall #pragma no_inline(bge_factotum_stall_check) 44081369Sdduvall 44091369Sdduvall static boolean_t 44101369Sdduvall bge_factotum_stall_check(bge_t *bgep) 44111369Sdduvall { 44121369Sdduvall uint32_t dogval; 44131369Sdduvall 44141369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 44151369Sdduvall 44161369Sdduvall /* 44171369Sdduvall * Specific check for Tx stall ... 44181369Sdduvall * 44191369Sdduvall * The 'watchdog' counter is incremented whenever a packet 44201369Sdduvall * is queued, reset to 1 when some (but not all) buffers 44211369Sdduvall * are reclaimed, reset to 0 (disabled) when all buffers 44221369Sdduvall * are reclaimed, and shifted left here. If it exceeds the 44231369Sdduvall * threshold value, the chip is assumed to have stalled and 44241369Sdduvall * is put into the ERROR state. The factotum will then reset 44251369Sdduvall * it on the next pass. 44261369Sdduvall * 44271369Sdduvall * All of which should ensure that we don't get into a state 44281369Sdduvall * where packets are left pending indefinitely! 44291369Sdduvall */ 44301369Sdduvall dogval = bge_atomic_shl32(&bgep->watchdog, 1); 44311369Sdduvall if (dogval < bge_watchdog_count) 44321369Sdduvall return (B_FALSE); 44331369Sdduvall 44343918Sml149210 #if !defined(BGE_NETCONSOLE) 44351369Sdduvall BGE_REPORT((bgep, "Tx stall detected, watchdog code 0x%x", dogval)); 44363918Sml149210 #endif 44371865Sdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_STALL); 44381369Sdduvall return (B_TRUE); 44391369Sdduvall } 44401369Sdduvall 44411369Sdduvall /* 44421369Sdduvall * The factotum is woken up when there's something to do that we'd rather 44431369Sdduvall * not do from inside a hardware interrupt handler or high-level cyclic. 44441369Sdduvall * Its two main tasks are: 44451369Sdduvall * reset & restart the chip after an error 44461369Sdduvall * check the link status whenever necessary 44471369Sdduvall */ 44481369Sdduvall uint_t bge_chip_factotum(caddr_t arg); 44491369Sdduvall #pragma no_inline(bge_chip_factotum) 44501369Sdduvall 44511369Sdduvall uint_t 44521369Sdduvall bge_chip_factotum(caddr_t arg) 44531369Sdduvall { 44541369Sdduvall bge_t *bgep; 44551369Sdduvall uint_t result; 44561369Sdduvall boolean_t error; 44571369Sdduvall boolean_t linkchg; 44581865Sdilpreet int dma_state; 44591369Sdduvall 44607099Syt223700 bgep = (void *)arg; 44611369Sdduvall 44621369Sdduvall BGE_TRACE(("bge_chip_factotum($%p)", (void *)bgep)); 44631369Sdduvall 44641369Sdduvall mutex_enter(bgep->softintrlock); 44651369Sdduvall if (bgep->factotum_flag == 0) { 44661369Sdduvall mutex_exit(bgep->softintrlock); 44671369Sdduvall return (DDI_INTR_UNCLAIMED); 44681369Sdduvall } 44691504Sly149593 bgep->factotum_flag = 0; 44701369Sdduvall mutex_exit(bgep->softintrlock); 44711369Sdduvall 44721369Sdduvall result = DDI_INTR_CLAIMED; 44731369Sdduvall error = B_FALSE; 44741369Sdduvall linkchg = B_FALSE; 44751369Sdduvall 44761369Sdduvall mutex_enter(bgep->genlock); 44771369Sdduvall switch (bgep->bge_chip_state) { 44781369Sdduvall default: 44791369Sdduvall break; 44801369Sdduvall 44811369Sdduvall case BGE_CHIP_RUNNING: 44821865Sdilpreet linkchg = bge_factotum_link_check(bgep, &dma_state); 44831369Sdduvall error = bge_factotum_stall_check(bgep); 44841865Sdilpreet if (dma_state != DDI_FM_OK) { 44851865Sdilpreet bgep->bge_dma_error = B_TRUE; 44861865Sdilpreet error = B_TRUE; 44871865Sdilpreet } 44881865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 44891865Sdilpreet error = B_TRUE; 44901865Sdilpreet if (error) 44911865Sdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 44921369Sdduvall break; 44931369Sdduvall 44941369Sdduvall case BGE_CHIP_ERROR: 44951369Sdduvall error = B_TRUE; 44961369Sdduvall break; 44971369Sdduvall 44981369Sdduvall case BGE_CHIP_FAULT: 44991369Sdduvall /* 45001369Sdduvall * Fault detected, time to reset ... 45011369Sdduvall */ 45021369Sdduvall if (bge_autorecover) { 45031865Sdilpreet if (!(bgep->progress & PROGRESS_BUFS)) { 45041865Sdilpreet /* 45051865Sdilpreet * if we can't allocate the ring buffers, 45061865Sdilpreet * try later 45071865Sdilpreet */ 45081865Sdilpreet if (bge_alloc_bufs(bgep) != DDI_SUCCESS) { 45091865Sdilpreet mutex_exit(bgep->genlock); 45101865Sdilpreet return (result); 45111865Sdilpreet } 45121865Sdilpreet bgep->progress |= PROGRESS_BUFS; 45131865Sdilpreet } 45141865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 45151865Sdilpreet bge_init_rings(bgep); 45161865Sdilpreet bge_intr_enable(bgep); 45171865Sdilpreet bgep->progress |= PROGRESS_INTR; 45181865Sdilpreet } 45191865Sdilpreet if (!(bgep->progress & PROGRESS_KSTATS)) { 45201865Sdilpreet bge_init_kstats(bgep, 45211865Sdilpreet ddi_get_instance(bgep->devinfo)); 45221865Sdilpreet bgep->progress |= PROGRESS_KSTATS; 45231865Sdilpreet } 45241865Sdilpreet 45251369Sdduvall BGE_REPORT((bgep, "automatic recovery activated")); 45261865Sdilpreet 45271865Sdilpreet if (bge_restart(bgep, B_FALSE) != DDI_SUCCESS) { 45281865Sdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 45291865Sdilpreet error = B_TRUE; 45301865Sdilpreet } 45311865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != 45321865Sdilpreet DDI_FM_OK) { 45331865Sdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 45341865Sdilpreet error = B_TRUE; 45351865Sdilpreet } 45361865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != 45371865Sdilpreet DDI_FM_OK) { 45381865Sdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 45391865Sdilpreet error = B_TRUE; 45401865Sdilpreet } 45411865Sdilpreet if (error == B_FALSE) { 45421408Srandyf #ifdef BGE_IPMI_ASF 45431865Sdilpreet if (bgep->asf_enabled && 45441865Sdilpreet bgep->asf_status != ASF_STAT_RUN) { 45451408Srandyf bgep->asf_timeout_id = timeout( 45461865Sdilpreet bge_asf_heartbeat, (void *)bgep, 45471865Sdilpreet drv_usectohz( 45481865Sdilpreet BGE_ASF_HEARTBEAT_INTERVAL)); 45491408Srandyf bgep->asf_status = ASF_STAT_RUN; 45501408Srandyf } 45511865Sdilpreet #endif 45525903Ssowmini if (!bgep->manual_reset) { 45535903Ssowmini ddi_fm_service_impact(bgep->devinfo, 45545903Ssowmini DDI_SERVICE_RESTORED); 45555903Ssowmini } 45561408Srandyf } 45571369Sdduvall } 45581369Sdduvall break; 45591369Sdduvall } 45601369Sdduvall 45611865Sdilpreet 45621369Sdduvall /* 45631369Sdduvall * If an error is detected, stop the chip now, marking it as 45641369Sdduvall * faulty, so that it will be reset next time through ... 45651865Sdilpreet * 45661865Sdilpreet * Note that if intr_running is set, then bge_intr() has dropped 45671865Sdilpreet * genlock to call bge_receive/bge_recycle. Can't stop the chip at 45681865Sdilpreet * this point so have to wait until the next time the factotum runs. 45691369Sdduvall */ 45701865Sdilpreet if (error && !bgep->bge_intr_running) { 45711408Srandyf #ifdef BGE_IPMI_ASF 45721408Srandyf if (bgep->asf_enabled && (bgep->asf_status == ASF_STAT_RUN)) { 45731408Srandyf /* 45741408Srandyf * We must stop ASF heart beat before bge_chip_stop(), 45751408Srandyf * otherwise some computers (ex. IBM HS20 blade server) 45761408Srandyf * may crash. 45771408Srandyf */ 45781408Srandyf bge_asf_update_status(bgep); 45791408Srandyf bge_asf_stop_timer(bgep); 45801408Srandyf bgep->asf_status = ASF_STAT_STOP; 45811408Srandyf 45821408Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 45831865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 45841408Srandyf } 45851408Srandyf #endif 45861369Sdduvall bge_chip_stop(bgep, B_TRUE); 45871865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 45881408Srandyf } 45891369Sdduvall mutex_exit(bgep->genlock); 45901369Sdduvall 45911369Sdduvall /* 45921369Sdduvall * If the link state changed, tell the world about it. 45931369Sdduvall * Note: can't do this while still holding the mutex. 45941369Sdduvall */ 45956546Sgh162552 if (bgep->link_update_timer == BGE_LINK_UPDATE_TIMEOUT && 45966546Sgh162552 bgep->link_state != LINK_STATE_UNKNOWN) 45976546Sgh162552 linkchg = B_TRUE; 45986546Sgh162552 else if (bgep->link_update_timer < BGE_LINK_UPDATE_TIMEOUT && 45996546Sgh162552 bgep->link_state == LINK_STATE_DOWN) 46006546Sgh162552 linkchg = B_FALSE; 46016546Sgh162552 46026546Sgh162552 if (linkchg) { 46032311Sseb mac_link_update(bgep->mh, bgep->link_state); 46046546Sgh162552 bgep->link_update_timer = BGE_LINK_UPDATE_DONE; 46056546Sgh162552 } 46065903Ssowmini if (bgep->manual_reset) { 46075903Ssowmini bgep->manual_reset = B_FALSE; 46085903Ssowmini } 46091369Sdduvall 46101369Sdduvall return (result); 46111369Sdduvall } 46121369Sdduvall 46131369Sdduvall /* 46141369Sdduvall * High-level cyclic handler 46151369Sdduvall * 46161369Sdduvall * This routine schedules a (low-level) softint callback to the 46171369Sdduvall * factotum, and prods the chip to update the status block (which 46181369Sdduvall * will cause a hardware interrupt when complete). 46191369Sdduvall */ 46201369Sdduvall void bge_chip_cyclic(void *arg); 46211369Sdduvall #pragma no_inline(bge_chip_cyclic) 46221369Sdduvall 46231369Sdduvall void 46241369Sdduvall bge_chip_cyclic(void *arg) 46251369Sdduvall { 46261369Sdduvall bge_t *bgep; 46271369Sdduvall 46281369Sdduvall bgep = arg; 46291369Sdduvall 46301369Sdduvall switch (bgep->bge_chip_state) { 46311369Sdduvall default: 46321369Sdduvall return; 46331369Sdduvall 46341369Sdduvall case BGE_CHIP_RUNNING: 46351369Sdduvall bge_reg_set32(bgep, HOST_COALESCE_MODE_REG, COALESCE_NOW); 46361865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 46371865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 46381865Sdilpreet DDI_SERVICE_UNAFFECTED); 46396546Sgh162552 46406546Sgh162552 if (bgep->link_update_timer < BGE_LINK_UPDATE_TIMEOUT) 46416546Sgh162552 bgep->link_update_timer++; 46426546Sgh162552 46431369Sdduvall break; 46441369Sdduvall 46451369Sdduvall case BGE_CHIP_FAULT: 46461369Sdduvall case BGE_CHIP_ERROR: 46471369Sdduvall break; 46481369Sdduvall } 46491369Sdduvall 46501369Sdduvall bge_wake_factotum(bgep); 46511369Sdduvall } 46521369Sdduvall 46531369Sdduvall 46541369Sdduvall /* 46551369Sdduvall * ========== Ioctl subfunctions ========== 46561369Sdduvall */ 46571369Sdduvall 46581369Sdduvall #undef BGE_DBG 46591369Sdduvall #define BGE_DBG BGE_DBG_PPIO /* debug flag for this code */ 46601369Sdduvall 46611369Sdduvall #if BGE_DEBUGGING || BGE_DO_PPIO 46621369Sdduvall 46631369Sdduvall static void bge_chip_peek_cfg(bge_t *bgep, bge_peekpoke_t *ppd); 46641369Sdduvall #pragma no_inline(bge_chip_peek_cfg) 46651369Sdduvall 46661369Sdduvall static void 46671369Sdduvall bge_chip_peek_cfg(bge_t *bgep, bge_peekpoke_t *ppd) 46681369Sdduvall { 46691369Sdduvall uint64_t regval; 46701369Sdduvall uint64_t regno; 46711369Sdduvall 46721369Sdduvall BGE_TRACE(("bge_chip_peek_cfg($%p, $%p)", 46734588Sml149210 (void *)bgep, (void *)ppd)); 46741369Sdduvall 46751369Sdduvall regno = ppd->pp_acc_offset; 46761369Sdduvall 46771369Sdduvall switch (ppd->pp_acc_size) { 46781369Sdduvall case 1: 46791369Sdduvall regval = pci_config_get8(bgep->cfg_handle, regno); 46801369Sdduvall break; 46811369Sdduvall 46821369Sdduvall case 2: 46831369Sdduvall regval = pci_config_get16(bgep->cfg_handle, regno); 46841369Sdduvall break; 46851369Sdduvall 46861369Sdduvall case 4: 46871369Sdduvall regval = pci_config_get32(bgep->cfg_handle, regno); 46881369Sdduvall break; 46891369Sdduvall 46901369Sdduvall case 8: 46911369Sdduvall regval = pci_config_get64(bgep->cfg_handle, regno); 46921369Sdduvall break; 46931369Sdduvall } 46941369Sdduvall 46951369Sdduvall ppd->pp_acc_data = regval; 46961369Sdduvall } 46971369Sdduvall 46981369Sdduvall static void bge_chip_poke_cfg(bge_t *bgep, bge_peekpoke_t *ppd); 46991369Sdduvall #pragma no_inline(bge_chip_poke_cfg) 47001369Sdduvall 47011369Sdduvall static void 47021369Sdduvall bge_chip_poke_cfg(bge_t *bgep, bge_peekpoke_t *ppd) 47031369Sdduvall { 47041369Sdduvall uint64_t regval; 47051369Sdduvall uint64_t regno; 47061369Sdduvall 47071369Sdduvall BGE_TRACE(("bge_chip_poke_cfg($%p, $%p)", 47084588Sml149210 (void *)bgep, (void *)ppd)); 47091369Sdduvall 47101369Sdduvall regno = ppd->pp_acc_offset; 47111369Sdduvall regval = ppd->pp_acc_data; 47121369Sdduvall 47131369Sdduvall switch (ppd->pp_acc_size) { 47141369Sdduvall case 1: 47151369Sdduvall pci_config_put8(bgep->cfg_handle, regno, regval); 47161369Sdduvall break; 47171369Sdduvall 47181369Sdduvall case 2: 47191369Sdduvall pci_config_put16(bgep->cfg_handle, regno, regval); 47201369Sdduvall break; 47211369Sdduvall 47221369Sdduvall case 4: 47231369Sdduvall pci_config_put32(bgep->cfg_handle, regno, regval); 47241369Sdduvall break; 47251369Sdduvall 47261369Sdduvall case 8: 47271369Sdduvall pci_config_put64(bgep->cfg_handle, regno, regval); 47281369Sdduvall break; 47291369Sdduvall } 47301369Sdduvall } 47311369Sdduvall 47321369Sdduvall static void bge_chip_peek_reg(bge_t *bgep, bge_peekpoke_t *ppd); 47331369Sdduvall #pragma no_inline(bge_chip_peek_reg) 47341369Sdduvall 47351369Sdduvall static void 47361369Sdduvall bge_chip_peek_reg(bge_t *bgep, bge_peekpoke_t *ppd) 47371369Sdduvall { 47381369Sdduvall uint64_t regval; 47391369Sdduvall void *regaddr; 47401369Sdduvall 47411369Sdduvall BGE_TRACE(("bge_chip_peek_reg($%p, $%p)", 47424588Sml149210 (void *)bgep, (void *)ppd)); 47431369Sdduvall 47441369Sdduvall regaddr = PIO_ADDR(bgep, ppd->pp_acc_offset); 47451369Sdduvall 47461369Sdduvall switch (ppd->pp_acc_size) { 47471369Sdduvall case 1: 47481369Sdduvall regval = ddi_get8(bgep->io_handle, regaddr); 47491369Sdduvall break; 47501369Sdduvall 47511369Sdduvall case 2: 47521369Sdduvall regval = ddi_get16(bgep->io_handle, regaddr); 47531369Sdduvall break; 47541369Sdduvall 47551369Sdduvall case 4: 47561369Sdduvall regval = ddi_get32(bgep->io_handle, regaddr); 47571369Sdduvall break; 47581369Sdduvall 47591369Sdduvall case 8: 47601369Sdduvall regval = ddi_get64(bgep->io_handle, regaddr); 47611369Sdduvall break; 47621369Sdduvall } 47631369Sdduvall 47641369Sdduvall ppd->pp_acc_data = regval; 47651369Sdduvall } 47661369Sdduvall 47671369Sdduvall static void bge_chip_poke_reg(bge_t *bgep, bge_peekpoke_t *ppd); 47681369Sdduvall #pragma no_inline(bge_chip_peek_reg) 47691369Sdduvall 47701369Sdduvall static void 47711369Sdduvall bge_chip_poke_reg(bge_t *bgep, bge_peekpoke_t *ppd) 47721369Sdduvall { 47731369Sdduvall uint64_t regval; 47741369Sdduvall void *regaddr; 47751369Sdduvall 47761369Sdduvall BGE_TRACE(("bge_chip_poke_reg($%p, $%p)", 47774588Sml149210 (void *)bgep, (void *)ppd)); 47781369Sdduvall 47791369Sdduvall regaddr = PIO_ADDR(bgep, ppd->pp_acc_offset); 47801369Sdduvall regval = ppd->pp_acc_data; 47811369Sdduvall 47821369Sdduvall switch (ppd->pp_acc_size) { 47831369Sdduvall case 1: 47841369Sdduvall ddi_put8(bgep->io_handle, regaddr, regval); 47851369Sdduvall break; 47861369Sdduvall 47871369Sdduvall case 2: 47881369Sdduvall ddi_put16(bgep->io_handle, regaddr, regval); 47891369Sdduvall break; 47901369Sdduvall 47911369Sdduvall case 4: 47921369Sdduvall ddi_put32(bgep->io_handle, regaddr, regval); 47931369Sdduvall break; 47941369Sdduvall 47951369Sdduvall case 8: 47961369Sdduvall ddi_put64(bgep->io_handle, regaddr, regval); 47971369Sdduvall break; 47981369Sdduvall } 47991369Sdduvall BGE_PCICHK(bgep); 48001369Sdduvall } 48011369Sdduvall 48021369Sdduvall static void bge_chip_peek_nic(bge_t *bgep, bge_peekpoke_t *ppd); 48031369Sdduvall #pragma no_inline(bge_chip_peek_nic) 48041369Sdduvall 48051369Sdduvall static void 48061369Sdduvall bge_chip_peek_nic(bge_t *bgep, bge_peekpoke_t *ppd) 48071369Sdduvall { 48081369Sdduvall uint64_t regoff; 48091369Sdduvall uint64_t regval; 48101369Sdduvall void *regaddr; 48111369Sdduvall 48121369Sdduvall BGE_TRACE(("bge_chip_peek_nic($%p, $%p)", 48134588Sml149210 (void *)bgep, (void *)ppd)); 48141369Sdduvall 48151369Sdduvall regoff = ppd->pp_acc_offset; 48161369Sdduvall bge_nic_setwin(bgep, regoff & ~MWBAR_GRANULE_MASK); 48171369Sdduvall regoff &= MWBAR_GRANULE_MASK; 48181369Sdduvall regoff += NIC_MEM_WINDOW_OFFSET; 48191369Sdduvall regaddr = PIO_ADDR(bgep, regoff); 48201369Sdduvall 48211369Sdduvall switch (ppd->pp_acc_size) { 48221369Sdduvall case 1: 48231369Sdduvall regval = ddi_get8(bgep->io_handle, regaddr); 48241369Sdduvall break; 48251369Sdduvall 48261369Sdduvall case 2: 48271369Sdduvall regval = ddi_get16(bgep->io_handle, regaddr); 48281369Sdduvall break; 48291369Sdduvall 48301369Sdduvall case 4: 48311369Sdduvall regval = ddi_get32(bgep->io_handle, regaddr); 48321369Sdduvall break; 48331369Sdduvall 48341369Sdduvall case 8: 48351369Sdduvall regval = ddi_get64(bgep->io_handle, regaddr); 48361369Sdduvall break; 48371369Sdduvall } 48381369Sdduvall 48391369Sdduvall ppd->pp_acc_data = regval; 48401369Sdduvall } 48411369Sdduvall 48421369Sdduvall static void bge_chip_poke_nic(bge_t *bgep, bge_peekpoke_t *ppd); 48431369Sdduvall #pragma no_inline(bge_chip_poke_nic) 48441369Sdduvall 48451369Sdduvall static void 48461369Sdduvall bge_chip_poke_nic(bge_t *bgep, bge_peekpoke_t *ppd) 48471369Sdduvall { 48481369Sdduvall uint64_t regoff; 48491369Sdduvall uint64_t regval; 48501369Sdduvall void *regaddr; 48511369Sdduvall 48521369Sdduvall BGE_TRACE(("bge_chip_poke_nic($%p, $%p)", 48534588Sml149210 (void *)bgep, (void *)ppd)); 48541369Sdduvall 48551369Sdduvall regoff = ppd->pp_acc_offset; 48561369Sdduvall bge_nic_setwin(bgep, regoff & ~MWBAR_GRANULE_MASK); 48571369Sdduvall regoff &= MWBAR_GRANULE_MASK; 48581369Sdduvall regoff += NIC_MEM_WINDOW_OFFSET; 48591369Sdduvall regaddr = PIO_ADDR(bgep, regoff); 48601369Sdduvall regval = ppd->pp_acc_data; 48611369Sdduvall 48621369Sdduvall switch (ppd->pp_acc_size) { 48631369Sdduvall case 1: 48641369Sdduvall ddi_put8(bgep->io_handle, regaddr, regval); 48651369Sdduvall break; 48661369Sdduvall 48671369Sdduvall case 2: 48681369Sdduvall ddi_put16(bgep->io_handle, regaddr, regval); 48691369Sdduvall break; 48701369Sdduvall 48711369Sdduvall case 4: 48721369Sdduvall ddi_put32(bgep->io_handle, regaddr, regval); 48731369Sdduvall break; 48741369Sdduvall 48751369Sdduvall case 8: 48761369Sdduvall ddi_put64(bgep->io_handle, regaddr, regval); 48771369Sdduvall break; 48781369Sdduvall } 48791369Sdduvall BGE_PCICHK(bgep); 48801369Sdduvall } 48811369Sdduvall 48821369Sdduvall static void bge_chip_peek_mii(bge_t *bgep, bge_peekpoke_t *ppd); 48831369Sdduvall #pragma no_inline(bge_chip_peek_mii) 48841369Sdduvall 48851369Sdduvall static void 48861369Sdduvall bge_chip_peek_mii(bge_t *bgep, bge_peekpoke_t *ppd) 48871369Sdduvall { 48881369Sdduvall BGE_TRACE(("bge_chip_peek_mii($%p, $%p)", 48894588Sml149210 (void *)bgep, (void *)ppd)); 48901369Sdduvall 48911369Sdduvall ppd->pp_acc_data = bge_mii_get16(bgep, ppd->pp_acc_offset/2); 48921369Sdduvall } 48931369Sdduvall 48941369Sdduvall static void bge_chip_poke_mii(bge_t *bgep, bge_peekpoke_t *ppd); 48951369Sdduvall #pragma no_inline(bge_chip_poke_mii) 48961369Sdduvall 48971369Sdduvall static void 48981369Sdduvall bge_chip_poke_mii(bge_t *bgep, bge_peekpoke_t *ppd) 48991369Sdduvall { 49001369Sdduvall BGE_TRACE(("bge_chip_poke_mii($%p, $%p)", 49014588Sml149210 (void *)bgep, (void *)ppd)); 49021369Sdduvall 49031369Sdduvall bge_mii_put16(bgep, ppd->pp_acc_offset/2, ppd->pp_acc_data); 49041369Sdduvall } 49051369Sdduvall 49061369Sdduvall #if BGE_SEE_IO32 49071369Sdduvall 49081369Sdduvall static void bge_chip_peek_seeprom(bge_t *bgep, bge_peekpoke_t *ppd); 49091369Sdduvall #pragma no_inline(bge_chip_peek_seeprom) 49101369Sdduvall 49111369Sdduvall static void 49121369Sdduvall bge_chip_peek_seeprom(bge_t *bgep, bge_peekpoke_t *ppd) 49131369Sdduvall { 49141369Sdduvall uint32_t data; 49151369Sdduvall int err; 49161369Sdduvall 49171369Sdduvall BGE_TRACE(("bge_chip_peek_seeprom($%p, $%p)", 49184588Sml149210 (void *)bgep, (void *)ppd)); 49191369Sdduvall 49201369Sdduvall err = bge_nvmem_rw32(bgep, BGE_SEE_READ, ppd->pp_acc_offset, &data); 49211369Sdduvall ppd->pp_acc_data = err ? ~0ull : data; 49221369Sdduvall } 49231369Sdduvall 49241369Sdduvall static void bge_chip_poke_seeprom(bge_t *bgep, bge_peekpoke_t *ppd); 49251369Sdduvall #pragma no_inline(bge_chip_poke_seeprom) 49261369Sdduvall 49271369Sdduvall static void 49281369Sdduvall bge_chip_poke_seeprom(bge_t *bgep, bge_peekpoke_t *ppd) 49291369Sdduvall { 49301369Sdduvall uint32_t data; 49311369Sdduvall 49321369Sdduvall BGE_TRACE(("bge_chip_poke_seeprom($%p, $%p)", 49334588Sml149210 (void *)bgep, (void *)ppd)); 49341369Sdduvall 49351369Sdduvall data = ppd->pp_acc_data; 49361369Sdduvall (void) bge_nvmem_rw32(bgep, BGE_SEE_WRITE, ppd->pp_acc_offset, &data); 49371369Sdduvall } 49381369Sdduvall #endif /* BGE_SEE_IO32 */ 49391369Sdduvall 49401369Sdduvall #if BGE_FLASH_IO32 49411369Sdduvall 49421369Sdduvall static void bge_chip_peek_flash(bge_t *bgep, bge_peekpoke_t *ppd); 49431369Sdduvall #pragma no_inline(bge_chip_peek_flash) 49441369Sdduvall 49451369Sdduvall static void 49461369Sdduvall bge_chip_peek_flash(bge_t *bgep, bge_peekpoke_t *ppd) 49471369Sdduvall { 49481369Sdduvall uint32_t data; 49491369Sdduvall int err; 49501369Sdduvall 49511369Sdduvall BGE_TRACE(("bge_chip_peek_flash($%p, $%p)", 49524588Sml149210 (void *)bgep, (void *)ppd)); 49531369Sdduvall 49541369Sdduvall err = bge_nvmem_rw32(bgep, BGE_FLASH_READ, ppd->pp_acc_offset, &data); 49551369Sdduvall ppd->pp_acc_data = err ? ~0ull : data; 49561369Sdduvall } 49571369Sdduvall 49581369Sdduvall static void bge_chip_poke_flash(bge_t *bgep, bge_peekpoke_t *ppd); 49591369Sdduvall #pragma no_inline(bge_chip_poke_flash) 49601369Sdduvall 49611369Sdduvall static void 49621369Sdduvall bge_chip_poke_flash(bge_t *bgep, bge_peekpoke_t *ppd) 49631369Sdduvall { 49641369Sdduvall uint32_t data; 49651369Sdduvall 49661369Sdduvall BGE_TRACE(("bge_chip_poke_flash($%p, $%p)", 49674588Sml149210 (void *)bgep, (void *)ppd)); 49681369Sdduvall 49691369Sdduvall data = ppd->pp_acc_data; 49701369Sdduvall (void) bge_nvmem_rw32(bgep, BGE_FLASH_WRITE, 49711369Sdduvall ppd->pp_acc_offset, &data); 49721369Sdduvall } 49731369Sdduvall #endif /* BGE_FLASH_IO32 */ 49741369Sdduvall 49751369Sdduvall static void bge_chip_peek_mem(bge_t *bgep, bge_peekpoke_t *ppd); 49761369Sdduvall #pragma no_inline(bge_chip_peek_mem) 49771369Sdduvall 49781369Sdduvall static void 49791369Sdduvall bge_chip_peek_mem(bge_t *bgep, bge_peekpoke_t *ppd) 49801369Sdduvall { 49811369Sdduvall uint64_t regval; 49821369Sdduvall void *vaddr; 49831369Sdduvall 49841369Sdduvall BGE_TRACE(("bge_chip_peek_bge($%p, $%p)", 49854588Sml149210 (void *)bgep, (void *)ppd)); 49861369Sdduvall 49871369Sdduvall vaddr = (void *)(uintptr_t)ppd->pp_acc_offset; 49881369Sdduvall 49891369Sdduvall switch (ppd->pp_acc_size) { 49901369Sdduvall case 1: 49911369Sdduvall regval = *(uint8_t *)vaddr; 49921369Sdduvall break; 49931369Sdduvall 49941369Sdduvall case 2: 49951369Sdduvall regval = *(uint16_t *)vaddr; 49961369Sdduvall break; 49971369Sdduvall 49981369Sdduvall case 4: 49991369Sdduvall regval = *(uint32_t *)vaddr; 50001369Sdduvall break; 50011369Sdduvall 50021369Sdduvall case 8: 50031369Sdduvall regval = *(uint64_t *)vaddr; 50041369Sdduvall break; 50051369Sdduvall } 50061369Sdduvall 50071369Sdduvall BGE_DEBUG(("bge_chip_peek_mem($%p, $%p) peeked 0x%llx from $%p", 50084588Sml149210 (void *)bgep, (void *)ppd, regval, vaddr)); 50091369Sdduvall 50101369Sdduvall ppd->pp_acc_data = regval; 50111369Sdduvall } 50121369Sdduvall 50131369Sdduvall static void bge_chip_poke_mem(bge_t *bgep, bge_peekpoke_t *ppd); 50141369Sdduvall #pragma no_inline(bge_chip_poke_mem) 50151369Sdduvall 50161369Sdduvall static void 50171369Sdduvall bge_chip_poke_mem(bge_t *bgep, bge_peekpoke_t *ppd) 50181369Sdduvall { 50191369Sdduvall uint64_t regval; 50201369Sdduvall void *vaddr; 50211369Sdduvall 50221369Sdduvall BGE_TRACE(("bge_chip_poke_mem($%p, $%p)", 50234588Sml149210 (void *)bgep, (void *)ppd)); 50241369Sdduvall 50251369Sdduvall vaddr = (void *)(uintptr_t)ppd->pp_acc_offset; 50261369Sdduvall regval = ppd->pp_acc_data; 50271369Sdduvall 50281369Sdduvall BGE_DEBUG(("bge_chip_poke_mem($%p, $%p) poking 0x%llx at $%p", 50294588Sml149210 (void *)bgep, (void *)ppd, regval, vaddr)); 50301369Sdduvall 50311369Sdduvall switch (ppd->pp_acc_size) { 50321369Sdduvall case 1: 50331369Sdduvall *(uint8_t *)vaddr = (uint8_t)regval; 50341369Sdduvall break; 50351369Sdduvall 50361369Sdduvall case 2: 50371369Sdduvall *(uint16_t *)vaddr = (uint16_t)regval; 50381369Sdduvall break; 50391369Sdduvall 50401369Sdduvall case 4: 50411369Sdduvall *(uint32_t *)vaddr = (uint32_t)regval; 50421369Sdduvall break; 50431369Sdduvall 50441369Sdduvall case 8: 50451369Sdduvall *(uint64_t *)vaddr = (uint64_t)regval; 50461369Sdduvall break; 50471369Sdduvall } 50481369Sdduvall } 50491369Sdduvall 50501369Sdduvall static enum ioc_reply bge_pp_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 50511369Sdduvall struct iocblk *iocp); 50521369Sdduvall #pragma no_inline(bge_pp_ioctl) 50531369Sdduvall 50541369Sdduvall static enum ioc_reply 50551369Sdduvall bge_pp_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 50561369Sdduvall { 50571369Sdduvall void (*ppfn)(bge_t *bgep, bge_peekpoke_t *ppd); 50581369Sdduvall bge_peekpoke_t *ppd; 50591369Sdduvall dma_area_t *areap; 50601369Sdduvall uint64_t sizemask; 50611369Sdduvall uint64_t mem_va; 50621369Sdduvall uint64_t maxoff; 50631369Sdduvall boolean_t peek; 50641369Sdduvall 50651369Sdduvall switch (cmd) { 50661369Sdduvall default: 50671369Sdduvall /* NOTREACHED */ 50681369Sdduvall bge_error(bgep, "bge_pp_ioctl: invalid cmd 0x%x", cmd); 50691369Sdduvall return (IOC_INVAL); 50701369Sdduvall 50711369Sdduvall case BGE_PEEK: 50721369Sdduvall peek = B_TRUE; 50731369Sdduvall break; 50741369Sdduvall 50751369Sdduvall case BGE_POKE: 50761369Sdduvall peek = B_FALSE; 50771369Sdduvall break; 50781369Sdduvall } 50791369Sdduvall 50801369Sdduvall /* 50811369Sdduvall * Validate format of ioctl 50821369Sdduvall */ 50831369Sdduvall if (iocp->ioc_count != sizeof (bge_peekpoke_t)) 50841369Sdduvall return (IOC_INVAL); 50851369Sdduvall if (mp->b_cont == NULL) 50861369Sdduvall return (IOC_INVAL); 50877099Syt223700 ppd = (void *)mp->b_cont->b_rptr; 50881369Sdduvall 50891369Sdduvall /* 50901369Sdduvall * Validate request parameters 50911369Sdduvall */ 50921369Sdduvall switch (ppd->pp_acc_space) { 50931369Sdduvall default: 50941369Sdduvall return (IOC_INVAL); 50951369Sdduvall 50961369Sdduvall case BGE_PP_SPACE_CFG: 50971369Sdduvall /* 50981369Sdduvall * Config space 50991369Sdduvall */ 51001369Sdduvall sizemask = 8|4|2|1; 51011369Sdduvall mem_va = 0; 51021369Sdduvall maxoff = PCI_CONF_HDR_SIZE; 51031369Sdduvall ppfn = peek ? bge_chip_peek_cfg : bge_chip_poke_cfg; 51041369Sdduvall break; 51051369Sdduvall 51061369Sdduvall case BGE_PP_SPACE_REG: 51071369Sdduvall /* 51081369Sdduvall * Memory-mapped I/O space 51091369Sdduvall */ 51101369Sdduvall sizemask = 8|4|2|1; 51111369Sdduvall mem_va = 0; 51121369Sdduvall maxoff = RIAAR_REGISTER_MAX; 51131369Sdduvall ppfn = peek ? bge_chip_peek_reg : bge_chip_poke_reg; 51141369Sdduvall break; 51151369Sdduvall 51161369Sdduvall case BGE_PP_SPACE_NIC: 51171369Sdduvall /* 51181369Sdduvall * NIC on-chip memory 51191369Sdduvall */ 51201369Sdduvall sizemask = 8|4|2|1; 51211369Sdduvall mem_va = 0; 51221369Sdduvall maxoff = MWBAR_ONCHIP_MAX; 51231369Sdduvall ppfn = peek ? bge_chip_peek_nic : bge_chip_poke_nic; 51241369Sdduvall break; 51251369Sdduvall 51261369Sdduvall case BGE_PP_SPACE_MII: 51271369Sdduvall /* 51281369Sdduvall * PHY's MII registers 51291369Sdduvall * NB: all PHY registers are two bytes, but the 51301369Sdduvall * addresses increment in ones (word addressing). 51311369Sdduvall * So we scale the address here, then undo the 51321369Sdduvall * transformation inside the peek/poke functions. 51331369Sdduvall */ 51341369Sdduvall ppd->pp_acc_offset *= 2; 51351369Sdduvall sizemask = 2; 51361369Sdduvall mem_va = 0; 51371369Sdduvall maxoff = (MII_MAXREG+1)*2; 51381369Sdduvall ppfn = peek ? bge_chip_peek_mii : bge_chip_poke_mii; 51391369Sdduvall break; 51401369Sdduvall 51411369Sdduvall #if BGE_SEE_IO32 51421369Sdduvall case BGE_PP_SPACE_SEEPROM: 51431369Sdduvall /* 51441369Sdduvall * Attached SEEPROM(s), if any. 51451369Sdduvall * NB: we use the high-order bits of the 'address' as 51461369Sdduvall * a device select to accommodate multiple SEEPROMS, 51471369Sdduvall * If each one is the maximum size (64kbytes), this 51481369Sdduvall * makes them appear contiguous. Otherwise, there may 51491369Sdduvall * be holes in the mapping. ENxS doesn't have any 51501369Sdduvall * SEEPROMs anyway ... 51511369Sdduvall */ 51521369Sdduvall sizemask = 4; 51531369Sdduvall mem_va = 0; 51541369Sdduvall maxoff = SEEPROM_DEV_AND_ADDR_MASK; 51551369Sdduvall ppfn = peek ? bge_chip_peek_seeprom : bge_chip_poke_seeprom; 51561369Sdduvall break; 51571369Sdduvall #endif /* BGE_SEE_IO32 */ 51581369Sdduvall 51591369Sdduvall #if BGE_FLASH_IO32 51601369Sdduvall case BGE_PP_SPACE_FLASH: 51611369Sdduvall /* 51621369Sdduvall * Attached Flash device (if any); a maximum of one device 51631369Sdduvall * is currently supported. But it can be up to 1MB (unlike 51641369Sdduvall * the 64k limit on SEEPROMs) so why would you need more ;-) 51651369Sdduvall */ 51661369Sdduvall sizemask = 4; 51671369Sdduvall mem_va = 0; 51681369Sdduvall maxoff = NVM_FLASH_ADDR_MASK; 51691369Sdduvall ppfn = peek ? bge_chip_peek_flash : bge_chip_poke_flash; 51701369Sdduvall break; 51711369Sdduvall #endif /* BGE_FLASH_IO32 */ 51721369Sdduvall 51731369Sdduvall case BGE_PP_SPACE_BGE: 51741369Sdduvall /* 51751369Sdduvall * BGE data structure! 51761369Sdduvall */ 51771369Sdduvall sizemask = 8|4|2|1; 51781369Sdduvall mem_va = (uintptr_t)bgep; 51791369Sdduvall maxoff = sizeof (*bgep); 51801369Sdduvall ppfn = peek ? bge_chip_peek_mem : bge_chip_poke_mem; 51811369Sdduvall break; 51821369Sdduvall 51831369Sdduvall case BGE_PP_SPACE_STATUS: 51841369Sdduvall case BGE_PP_SPACE_STATISTICS: 51851369Sdduvall case BGE_PP_SPACE_TXDESC: 51861369Sdduvall case BGE_PP_SPACE_TXBUFF: 51871369Sdduvall case BGE_PP_SPACE_RXDESC: 51881369Sdduvall case BGE_PP_SPACE_RXBUFF: 51891369Sdduvall /* 51901369Sdduvall * Various DMA_AREAs 51911369Sdduvall */ 51921369Sdduvall switch (ppd->pp_acc_space) { 51931369Sdduvall case BGE_PP_SPACE_TXDESC: 51941369Sdduvall areap = &bgep->tx_desc; 51951369Sdduvall break; 51961369Sdduvall case BGE_PP_SPACE_TXBUFF: 51971369Sdduvall areap = &bgep->tx_buff[0]; 51981369Sdduvall break; 51991369Sdduvall case BGE_PP_SPACE_RXDESC: 52001369Sdduvall areap = &bgep->rx_desc[0]; 52011369Sdduvall break; 52021369Sdduvall case BGE_PP_SPACE_RXBUFF: 52031369Sdduvall areap = &bgep->rx_buff[0]; 52041369Sdduvall break; 52051369Sdduvall case BGE_PP_SPACE_STATUS: 52061369Sdduvall areap = &bgep->status_block; 52071369Sdduvall break; 52081369Sdduvall case BGE_PP_SPACE_STATISTICS: 52091369Sdduvall if (bgep->chipid.statistic_type == BGE_STAT_BLK) 52101369Sdduvall areap = &bgep->statistics; 52111369Sdduvall break; 52121369Sdduvall } 52131369Sdduvall 52141369Sdduvall sizemask = 8|4|2|1; 52151369Sdduvall mem_va = (uintptr_t)areap->mem_va; 52161369Sdduvall maxoff = areap->alength; 52171369Sdduvall ppfn = peek ? bge_chip_peek_mem : bge_chip_poke_mem; 52181369Sdduvall break; 52191369Sdduvall } 52201369Sdduvall 52211369Sdduvall switch (ppd->pp_acc_size) { 52221369Sdduvall default: 52231369Sdduvall return (IOC_INVAL); 52241369Sdduvall 52251369Sdduvall case 8: 52261369Sdduvall case 4: 52271369Sdduvall case 2: 52281369Sdduvall case 1: 52291369Sdduvall if ((ppd->pp_acc_size & sizemask) == 0) 52301369Sdduvall return (IOC_INVAL); 52311369Sdduvall break; 52321369Sdduvall } 52331369Sdduvall 52341369Sdduvall if ((ppd->pp_acc_offset % ppd->pp_acc_size) != 0) 52351369Sdduvall return (IOC_INVAL); 52361369Sdduvall 52371369Sdduvall if (ppd->pp_acc_offset >= maxoff) 52381369Sdduvall return (IOC_INVAL); 52391369Sdduvall 52401369Sdduvall if (ppd->pp_acc_offset+ppd->pp_acc_size > maxoff) 52411369Sdduvall return (IOC_INVAL); 52421369Sdduvall 52431369Sdduvall /* 52441369Sdduvall * All OK - go do it! 52451369Sdduvall */ 52461369Sdduvall ppd->pp_acc_offset += mem_va; 52471369Sdduvall (*ppfn)(bgep, ppd); 52481369Sdduvall return (peek ? IOC_REPLY : IOC_ACK); 52491369Sdduvall } 52501369Sdduvall 52511369Sdduvall static enum ioc_reply bge_diag_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 52521369Sdduvall struct iocblk *iocp); 52531369Sdduvall #pragma no_inline(bge_diag_ioctl) 52541369Sdduvall 52551369Sdduvall static enum ioc_reply 52561369Sdduvall bge_diag_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 52571369Sdduvall { 52581369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 52591369Sdduvall 52601369Sdduvall switch (cmd) { 52611369Sdduvall default: 52621369Sdduvall /* NOTREACHED */ 52631369Sdduvall bge_error(bgep, "bge_diag_ioctl: invalid cmd 0x%x", cmd); 52641369Sdduvall return (IOC_INVAL); 52651369Sdduvall 52661369Sdduvall case BGE_DIAG: 52671369Sdduvall /* 52681369Sdduvall * Currently a no-op 52691369Sdduvall */ 52701369Sdduvall return (IOC_ACK); 52711369Sdduvall 52721369Sdduvall case BGE_PEEK: 52731369Sdduvall case BGE_POKE: 52741369Sdduvall return (bge_pp_ioctl(bgep, cmd, mp, iocp)); 52751369Sdduvall 52761369Sdduvall case BGE_PHY_RESET: 52771369Sdduvall return (IOC_RESTART_ACK); 52781369Sdduvall 52791369Sdduvall case BGE_SOFT_RESET: 52801369Sdduvall case BGE_HARD_RESET: 52811369Sdduvall /* 52821369Sdduvall * Reset and reinitialise the 570x hardware 52831369Sdduvall */ 52843918Sml149210 bgep->bge_chip_state = BGE_CHIP_FAULT; 52853918Sml149210 ddi_trigger_softintr(bgep->factotum_id); 52861865Sdilpreet (void) bge_restart(bgep, cmd == BGE_HARD_RESET); 52871369Sdduvall return (IOC_ACK); 52881369Sdduvall } 52891369Sdduvall 52901369Sdduvall /* NOTREACHED */ 52911369Sdduvall } 52921369Sdduvall 52931369Sdduvall #endif /* BGE_DEBUGGING || BGE_DO_PPIO */ 52941369Sdduvall 52951369Sdduvall static enum ioc_reply bge_mii_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 52961369Sdduvall struct iocblk *iocp); 52971369Sdduvall #pragma no_inline(bge_mii_ioctl) 52981369Sdduvall 52991369Sdduvall static enum ioc_reply 53001369Sdduvall bge_mii_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 53011369Sdduvall { 53021369Sdduvall struct bge_mii_rw *miirwp; 53031369Sdduvall 53041369Sdduvall /* 53051369Sdduvall * Validate format of ioctl 53061369Sdduvall */ 53071369Sdduvall if (iocp->ioc_count != sizeof (struct bge_mii_rw)) 53081369Sdduvall return (IOC_INVAL); 53091369Sdduvall if (mp->b_cont == NULL) 53101369Sdduvall return (IOC_INVAL); 53117099Syt223700 miirwp = (void *)mp->b_cont->b_rptr; 53121369Sdduvall 53131369Sdduvall /* 53141369Sdduvall * Validate request parameters ... 53151369Sdduvall */ 53161369Sdduvall if (miirwp->mii_reg > MII_MAXREG) 53171369Sdduvall return (IOC_INVAL); 53181369Sdduvall 53191369Sdduvall switch (cmd) { 53201369Sdduvall default: 53211369Sdduvall /* NOTREACHED */ 53221369Sdduvall bge_error(bgep, "bge_mii_ioctl: invalid cmd 0x%x", cmd); 53231369Sdduvall return (IOC_INVAL); 53241369Sdduvall 53251369Sdduvall case BGE_MII_READ: 53261369Sdduvall miirwp->mii_data = bge_mii_get16(bgep, miirwp->mii_reg); 53271369Sdduvall return (IOC_REPLY); 53281369Sdduvall 53291369Sdduvall case BGE_MII_WRITE: 53301369Sdduvall bge_mii_put16(bgep, miirwp->mii_reg, miirwp->mii_data); 53311369Sdduvall return (IOC_ACK); 53321369Sdduvall } 53331369Sdduvall 53341369Sdduvall /* NOTREACHED */ 53351369Sdduvall } 53361369Sdduvall 53371369Sdduvall #if BGE_SEE_IO32 53381369Sdduvall 53391369Sdduvall static enum ioc_reply bge_see_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 53401369Sdduvall struct iocblk *iocp); 53411369Sdduvall #pragma no_inline(bge_see_ioctl) 53421369Sdduvall 53431369Sdduvall static enum ioc_reply 53441369Sdduvall bge_see_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 53451369Sdduvall { 53461369Sdduvall struct bge_see_rw *seerwp; 53471369Sdduvall 53481369Sdduvall /* 53491369Sdduvall * Validate format of ioctl 53501369Sdduvall */ 53511369Sdduvall if (iocp->ioc_count != sizeof (struct bge_see_rw)) 53521369Sdduvall return (IOC_INVAL); 53531369Sdduvall if (mp->b_cont == NULL) 53541369Sdduvall return (IOC_INVAL); 53557099Syt223700 seerwp = (void *)mp->b_cont->b_rptr; 53561369Sdduvall 53571369Sdduvall /* 53581369Sdduvall * Validate request parameters ... 53591369Sdduvall */ 53601369Sdduvall if (seerwp->see_addr & ~SEEPROM_DEV_AND_ADDR_MASK) 53611369Sdduvall return (IOC_INVAL); 53621369Sdduvall 53631369Sdduvall switch (cmd) { 53641369Sdduvall default: 53651369Sdduvall /* NOTREACHED */ 53661369Sdduvall bge_error(bgep, "bge_see_ioctl: invalid cmd 0x%x", cmd); 53671369Sdduvall return (IOC_INVAL); 53681369Sdduvall 53691369Sdduvall case BGE_SEE_READ: 53701369Sdduvall case BGE_SEE_WRITE: 53711369Sdduvall iocp->ioc_error = bge_nvmem_rw32(bgep, cmd, 53721369Sdduvall seerwp->see_addr, &seerwp->see_data); 53731369Sdduvall return (IOC_REPLY); 53741369Sdduvall } 53751369Sdduvall 53761369Sdduvall /* NOTREACHED */ 53771369Sdduvall } 53781369Sdduvall 53791369Sdduvall #endif /* BGE_SEE_IO32 */ 53801369Sdduvall 53811369Sdduvall #if BGE_FLASH_IO32 53821369Sdduvall 53831369Sdduvall static enum ioc_reply bge_flash_ioctl(bge_t *bgep, int cmd, mblk_t *mp, 53841369Sdduvall struct iocblk *iocp); 53851369Sdduvall #pragma no_inline(bge_flash_ioctl) 53861369Sdduvall 53871369Sdduvall static enum ioc_reply 53881369Sdduvall bge_flash_ioctl(bge_t *bgep, int cmd, mblk_t *mp, struct iocblk *iocp) 53891369Sdduvall { 53901369Sdduvall struct bge_flash_rw *flashrwp; 53911369Sdduvall 53921369Sdduvall /* 53931369Sdduvall * Validate format of ioctl 53941369Sdduvall */ 53951369Sdduvall if (iocp->ioc_count != sizeof (struct bge_flash_rw)) 53961369Sdduvall return (IOC_INVAL); 53971369Sdduvall if (mp->b_cont == NULL) 53981369Sdduvall return (IOC_INVAL); 53997099Syt223700 flashrwp = (void *)mp->b_cont->b_rptr; 54001369Sdduvall 54011369Sdduvall /* 54021369Sdduvall * Validate request parameters ... 54031369Sdduvall */ 54041369Sdduvall if (flashrwp->flash_addr & ~NVM_FLASH_ADDR_MASK) 54051369Sdduvall return (IOC_INVAL); 54061369Sdduvall 54071369Sdduvall switch (cmd) { 54081369Sdduvall default: 54091369Sdduvall /* NOTREACHED */ 54101369Sdduvall bge_error(bgep, "bge_flash_ioctl: invalid cmd 0x%x", cmd); 54111369Sdduvall return (IOC_INVAL); 54121369Sdduvall 54131369Sdduvall case BGE_FLASH_READ: 54141369Sdduvall case BGE_FLASH_WRITE: 54151369Sdduvall iocp->ioc_error = bge_nvmem_rw32(bgep, cmd, 54161369Sdduvall flashrwp->flash_addr, &flashrwp->flash_data); 54171369Sdduvall return (IOC_REPLY); 54181369Sdduvall } 54191369Sdduvall 54201369Sdduvall /* NOTREACHED */ 54211369Sdduvall } 54221369Sdduvall 54231369Sdduvall #endif /* BGE_FLASH_IO32 */ 54241369Sdduvall 54251369Sdduvall enum ioc_reply bge_chip_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, 54261369Sdduvall struct iocblk *iocp); 54271369Sdduvall #pragma no_inline(bge_chip_ioctl) 54281369Sdduvall 54291369Sdduvall enum ioc_reply 54301369Sdduvall bge_chip_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 54311369Sdduvall { 54321369Sdduvall int cmd; 54331369Sdduvall 54341369Sdduvall BGE_TRACE(("bge_chip_ioctl($%p, $%p, $%p, $%p)", 54354588Sml149210 (void *)bgep, (void *)wq, (void *)mp, (void *)iocp)); 54361369Sdduvall 54371369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 54381369Sdduvall 54391369Sdduvall cmd = iocp->ioc_cmd; 54401369Sdduvall switch (cmd) { 54411369Sdduvall default: 54421369Sdduvall /* NOTREACHED */ 54431369Sdduvall bge_error(bgep, "bge_chip_ioctl: invalid cmd 0x%x", cmd); 54441369Sdduvall return (IOC_INVAL); 54451369Sdduvall 54461369Sdduvall case BGE_DIAG: 54471369Sdduvall case BGE_PEEK: 54481369Sdduvall case BGE_POKE: 54491369Sdduvall case BGE_PHY_RESET: 54501369Sdduvall case BGE_SOFT_RESET: 54511369Sdduvall case BGE_HARD_RESET: 54521369Sdduvall #if BGE_DEBUGGING || BGE_DO_PPIO 54531369Sdduvall return (bge_diag_ioctl(bgep, cmd, mp, iocp)); 54541369Sdduvall #else 54551369Sdduvall return (IOC_INVAL); 54561369Sdduvall #endif /* BGE_DEBUGGING || BGE_DO_PPIO */ 54571369Sdduvall 54581369Sdduvall case BGE_MII_READ: 54591369Sdduvall case BGE_MII_WRITE: 54601369Sdduvall return (bge_mii_ioctl(bgep, cmd, mp, iocp)); 54611369Sdduvall 54621369Sdduvall #if BGE_SEE_IO32 54631369Sdduvall case BGE_SEE_READ: 54641369Sdduvall case BGE_SEE_WRITE: 54651369Sdduvall return (bge_see_ioctl(bgep, cmd, mp, iocp)); 54661369Sdduvall #endif /* BGE_SEE_IO32 */ 54671369Sdduvall 54681369Sdduvall #if BGE_FLASH_IO32 54691369Sdduvall case BGE_FLASH_READ: 54701369Sdduvall case BGE_FLASH_WRITE: 54711369Sdduvall return (bge_flash_ioctl(bgep, cmd, mp, iocp)); 54721369Sdduvall #endif /* BGE_FLASH_IO32 */ 54731369Sdduvall } 54741369Sdduvall 54751369Sdduvall /* NOTREACHED */ 54761369Sdduvall } 54771369Sdduvall 54781369Sdduvall void 54791369Sdduvall bge_chip_blank(void *arg, time_t ticks, uint_t count) 54801369Sdduvall { 54811369Sdduvall bge_t *bgep = arg; 54821369Sdduvall 54831865Sdilpreet mutex_enter(bgep->genlock); 54841369Sdduvall bge_reg_put32(bgep, RCV_COALESCE_TICKS_REG, ticks); 54851369Sdduvall bge_reg_put32(bgep, RCV_COALESCE_MAX_BD_REG, count); 54861865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 54871865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 54881865Sdilpreet mutex_exit(bgep->genlock); 54891369Sdduvall } 54901408Srandyf 54911408Srandyf #ifdef BGE_IPMI_ASF 54921408Srandyf 54931408Srandyf uint32_t 54941408Srandyf bge_nic_read32(bge_t *bgep, bge_regno_t addr) 54951408Srandyf { 54961408Srandyf uint32_t data; 54971408Srandyf 54983918Sml149210 #ifndef __sparc 54991408Srandyf if (!bgep->asf_wordswapped) { 55001408Srandyf /* a workaround word swap error */ 55011408Srandyf if (addr & 4) 55021408Srandyf addr = addr - 4; 55031408Srandyf else 55041408Srandyf addr = addr + 4; 55051408Srandyf } 55063918Sml149210 #endif 55071408Srandyf 55081408Srandyf pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, addr); 55091408Srandyf data = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MWDAR); 55101408Srandyf pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MWBAR, 0); 55111408Srandyf 55123918Sml149210 data = LE_32(data); 55131408Srandyf return (data); 55141408Srandyf } 55151408Srandyf 55161408Srandyf void 55171408Srandyf bge_asf_update_status(bge_t *bgep) 55181408Srandyf { 55191408Srandyf uint32_t event; 55201408Srandyf 55211408Srandyf bge_nic_put32(bgep, BGE_CMD_MAILBOX, BGE_CMD_NICDRV_ALIVE); 55221408Srandyf bge_nic_put32(bgep, BGE_CMD_LENGTH_MAILBOX, 4); 55231408Srandyf bge_nic_put32(bgep, BGE_CMD_DATA_MAILBOX, 3); 55241408Srandyf 55251408Srandyf event = bge_reg_get32(bgep, RX_RISC_EVENT_REG); 55261408Srandyf bge_reg_put32(bgep, RX_RISC_EVENT_REG, event | RRER_ASF_EVENT); 55271408Srandyf } 55281408Srandyf 55291408Srandyf 55301408Srandyf /* 55311408Srandyf * The driver is supposed to notify ASF that the OS is still running 55321408Srandyf * every three seconds, otherwise the management server may attempt 55331408Srandyf * to reboot the machine. If it hasn't actually failed, this is 55342135Szh199473 * not a desirable result. However, this isn't running as a real-time 55351408Srandyf * thread, and even if it were, it might not be able to generate the 55361408Srandyf * heartbeat in a timely manner due to system load. As it isn't a 55371408Srandyf * significant strain on the machine, we will set the interval to half 55381408Srandyf * of the required value. 55391408Srandyf */ 55401408Srandyf void 55411865Sdilpreet bge_asf_heartbeat(void *arg) 55421408Srandyf { 55431865Sdilpreet bge_t *bgep = (bge_t *)arg; 55441865Sdilpreet 55451865Sdilpreet mutex_enter(bgep->genlock); 55461408Srandyf bge_asf_update_status((bge_t *)bgep); 55471865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 55481865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 55491865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 55501865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 55511865Sdilpreet mutex_exit(bgep->genlock); 55521408Srandyf ((bge_t *)bgep)->asf_timeout_id = timeout(bge_asf_heartbeat, bgep, 55534588Sml149210 drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 55541408Srandyf } 55551408Srandyf 55561408Srandyf 55571408Srandyf void 55581408Srandyf bge_asf_stop_timer(bge_t *bgep) 55591408Srandyf { 55601408Srandyf timeout_id_t tmp_id = 0; 55611408Srandyf 55621408Srandyf while ((bgep->asf_timeout_id != 0) && 55634588Sml149210 (tmp_id != bgep->asf_timeout_id)) { 55641408Srandyf tmp_id = bgep->asf_timeout_id; 55651408Srandyf (void) untimeout(tmp_id); 55661408Srandyf } 55671408Srandyf bgep->asf_timeout_id = 0; 55681408Srandyf } 55691408Srandyf 55701408Srandyf 55711408Srandyf 55721408Srandyf /* 55732135Szh199473 * This function should be placed at the earliest position of bge_attach(). 55741408Srandyf */ 55751408Srandyf void 55761408Srandyf bge_asf_get_config(bge_t *bgep) 55771408Srandyf { 55781408Srandyf uint32_t nicsig; 55791408Srandyf uint32_t niccfg; 55801408Srandyf 55813918Sml149210 bgep->asf_enabled = B_FALSE; 55821408Srandyf nicsig = bge_nic_read32(bgep, BGE_NIC_DATA_SIG_ADDR); 55831408Srandyf if (nicsig == BGE_NIC_DATA_SIG) { 55841408Srandyf niccfg = bge_nic_read32(bgep, BGE_NIC_DATA_NIC_CFG_ADDR); 55851408Srandyf if (niccfg & BGE_NIC_CFG_ENABLE_ASF) 55861408Srandyf /* 55871408Srandyf * Here, we don't consider BAXTER, because BGE haven't 55881408Srandyf * supported BAXTER (that is 5752). Also, as I know, 55891408Srandyf * BAXTER doesn't support ASF feature. 55901408Srandyf */ 55911408Srandyf bgep->asf_enabled = B_TRUE; 55921408Srandyf else 55931408Srandyf bgep->asf_enabled = B_FALSE; 55941408Srandyf } else 55951408Srandyf bgep->asf_enabled = B_FALSE; 55961408Srandyf } 55971408Srandyf 55981408Srandyf 55991408Srandyf void 56001408Srandyf bge_asf_pre_reset_operations(bge_t *bgep, uint32_t mode) 56011408Srandyf { 56021408Srandyf uint32_t tries; 56031408Srandyf uint32_t event; 56041408Srandyf 56051408Srandyf ASSERT(bgep->asf_enabled); 56061408Srandyf 56071408Srandyf /* Issues "pause firmware" command and wait for ACK */ 56081408Srandyf bge_nic_put32(bgep, BGE_CMD_MAILBOX, BGE_CMD_NICDRV_PAUSE_FW); 56091408Srandyf event = bge_reg_get32(bgep, RX_RISC_EVENT_REG); 56101408Srandyf bge_reg_put32(bgep, RX_RISC_EVENT_REG, event | RRER_ASF_EVENT); 56111408Srandyf 56121408Srandyf event = bge_reg_get32(bgep, RX_RISC_EVENT_REG); 56131408Srandyf tries = 0; 56141408Srandyf while ((event & RRER_ASF_EVENT) && (tries < 100)) { 56151408Srandyf drv_usecwait(1); 56161408Srandyf tries ++; 56171408Srandyf event = bge_reg_get32(bgep, RX_RISC_EVENT_REG); 56181408Srandyf } 56191408Srandyf 56201408Srandyf bge_nic_put32(bgep, BGE_FIRMWARE_MAILBOX, 56214588Sml149210 BGE_MAGIC_NUM_FIRMWARE_INIT_DONE); 56221408Srandyf 56231408Srandyf if (bgep->asf_newhandshake) { 56241408Srandyf switch (mode) { 56251408Srandyf case BGE_INIT_RESET: 56261408Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 56274588Sml149210 BGE_DRV_STATE_START); 56281408Srandyf break; 56291408Srandyf case BGE_SHUTDOWN_RESET: 56301408Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 56314588Sml149210 BGE_DRV_STATE_UNLOAD); 56321408Srandyf break; 56331408Srandyf case BGE_SUSPEND_RESET: 56341408Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 56354588Sml149210 BGE_DRV_STATE_SUSPEND); 56361408Srandyf break; 56371408Srandyf default: 56381408Srandyf break; 56391408Srandyf } 56401408Srandyf } 56411408Srandyf } 56421408Srandyf 56431408Srandyf 56441408Srandyf void 56451408Srandyf bge_asf_post_reset_old_mode(bge_t *bgep, uint32_t mode) 56461408Srandyf { 56471408Srandyf switch (mode) { 56481408Srandyf case BGE_INIT_RESET: 56491408Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 56504588Sml149210 BGE_DRV_STATE_START); 56511408Srandyf break; 56521408Srandyf case BGE_SHUTDOWN_RESET: 56531408Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 56544588Sml149210 BGE_DRV_STATE_UNLOAD); 56551408Srandyf break; 56561408Srandyf case BGE_SUSPEND_RESET: 56571408Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 56584588Sml149210 BGE_DRV_STATE_SUSPEND); 56591408Srandyf break; 56601408Srandyf default: 56611408Srandyf break; 56621408Srandyf } 56631408Srandyf } 56641408Srandyf 56651408Srandyf 56661408Srandyf void 56671408Srandyf bge_asf_post_reset_new_mode(bge_t *bgep, uint32_t mode) 56681408Srandyf { 56691408Srandyf switch (mode) { 56701408Srandyf case BGE_INIT_RESET: 56711408Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 56724588Sml149210 BGE_DRV_STATE_START_DONE); 56731408Srandyf break; 56741408Srandyf case BGE_SHUTDOWN_RESET: 56751408Srandyf bge_nic_put32(bgep, BGE_DRV_STATE_MAILBOX, 56764588Sml149210 BGE_DRV_STATE_UNLOAD_DONE); 56771408Srandyf break; 56781408Srandyf default: 56791408Srandyf break; 56801408Srandyf } 56811408Srandyf } 56821408Srandyf 56831408Srandyf #endif /* BGE_IPMI_ASF */ 5684