16833Sgd78059 /* 26833Sgd78059 * CDDL HEADER START 36833Sgd78059 * 46833Sgd78059 * The contents of this file are subject to the terms of the 56833Sgd78059 * Common Development and Distribution License (the "License"). 66833Sgd78059 * You may not use this file except in compliance with the License. 76833Sgd78059 * 86833Sgd78059 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96833Sgd78059 * or http://www.opensolaris.org/os/licensing. 106833Sgd78059 * See the License for the specific language governing permissions 116833Sgd78059 * and limitations under the License. 126833Sgd78059 * 136833Sgd78059 * When distributing Covered Code, include this CDDL HEADER in each 146833Sgd78059 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156833Sgd78059 * If applicable, add the following below this CDDL HEADER, with the 166833Sgd78059 * fields enclosed by brackets "[]" replaced with your own identifying 176833Sgd78059 * information: Portions Copyright [yyyy] [name of copyright owner] 186833Sgd78059 * 196833Sgd78059 * CDDL HEADER END 206833Sgd78059 */ 216833Sgd78059 /* 22*10306SVitezslav.Batrla@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 236833Sgd78059 * Use is subject to license terms. 246833Sgd78059 */ 256833Sgd78059 266833Sgd78059 /* 276833Sgd78059 * SunOS MT STREAMS ERI(PCI) 10/100 Mb Ethernet Device Driver 286833Sgd78059 */ 296833Sgd78059 306833Sgd78059 #include <sys/types.h> 316833Sgd78059 #include <sys/debug.h> 326833Sgd78059 #include <sys/stropts.h> 336833Sgd78059 #include <sys/stream.h> 346833Sgd78059 #include <sys/strsubr.h> 356833Sgd78059 #include <sys/kmem.h> 366833Sgd78059 #include <sys/crc32.h> 376833Sgd78059 #include <sys/ddi.h> 386833Sgd78059 #include <sys/sunddi.h> 396833Sgd78059 #include <sys/strsun.h> 406833Sgd78059 #include <sys/stat.h> 416833Sgd78059 #include <sys/cpu.h> 426833Sgd78059 #include <sys/kstat.h> 436833Sgd78059 #include <inet/common.h> 446833Sgd78059 #include <sys/pattr.h> 456833Sgd78059 #include <inet/mi.h> 466833Sgd78059 #include <inet/nd.h> 476833Sgd78059 #include <sys/ethernet.h> 486833Sgd78059 #include <sys/vlan.h> 496833Sgd78059 #include <sys/policy.h> 508275SEric Cheng #include <sys/mac_provider.h> 516833Sgd78059 #include <sys/mac_ether.h> 526833Sgd78059 #include <sys/dlpi.h> 536833Sgd78059 546833Sgd78059 #include <sys/pci.h> 556833Sgd78059 566833Sgd78059 #include "eri_phy.h" 576833Sgd78059 #include "eri_mac.h" 586833Sgd78059 #include "eri.h" 596833Sgd78059 #include "eri_common.h" 606833Sgd78059 616833Sgd78059 #include "eri_msg.h" 626833Sgd78059 636833Sgd78059 /* 646833Sgd78059 * **** Function Prototypes ***** 656833Sgd78059 */ 666833Sgd78059 /* 676833Sgd78059 * Entry points (man9e) 686833Sgd78059 */ 696833Sgd78059 static int eri_attach(dev_info_t *, ddi_attach_cmd_t); 706833Sgd78059 static int eri_detach(dev_info_t *, ddi_detach_cmd_t); 716833Sgd78059 static uint_t eri_intr(caddr_t); 726833Sgd78059 736833Sgd78059 /* 746833Sgd78059 * I/O (Input/Output) Functions 756833Sgd78059 */ 766833Sgd78059 static boolean_t eri_send_msg(struct eri *, mblk_t *); 776833Sgd78059 static mblk_t *eri_read_dma(struct eri *, volatile struct rmd *, 786833Sgd78059 volatile int, uint64_t flags); 796833Sgd78059 806833Sgd78059 /* 816833Sgd78059 * Initialization Functions 826833Sgd78059 */ 836833Sgd78059 static boolean_t eri_init(struct eri *); 846833Sgd78059 static int eri_allocthings(struct eri *); 856833Sgd78059 static int eri_init_xfer_params(struct eri *); 866833Sgd78059 static void eri_statinit(struct eri *); 876833Sgd78059 static int eri_burstsize(struct eri *); 886833Sgd78059 896833Sgd78059 static void eri_setup_mac_address(struct eri *, dev_info_t *); 906833Sgd78059 916833Sgd78059 static uint32_t eri_init_rx_channel(struct eri *); 926833Sgd78059 static void eri_init_rx(struct eri *); 936833Sgd78059 static void eri_init_txmac(struct eri *); 946833Sgd78059 956833Sgd78059 /* 966833Sgd78059 * Un-init Functions 976833Sgd78059 */ 986833Sgd78059 static uint32_t eri_txmac_disable(struct eri *); 996833Sgd78059 static uint32_t eri_rxmac_disable(struct eri *); 1006833Sgd78059 static int eri_stop(struct eri *); 1016833Sgd78059 static void eri_uninit(struct eri *erip); 1026833Sgd78059 static int eri_freebufs(struct eri *); 1036833Sgd78059 static boolean_t eri_reclaim(struct eri *, uint32_t); 1046833Sgd78059 1056833Sgd78059 /* 1066833Sgd78059 * Transceiver (xcvr) Functions 1076833Sgd78059 */ 1086833Sgd78059 static int eri_new_xcvr(struct eri *); /* Initializes & detects xcvrs */ 1096833Sgd78059 static int eri_reset_xcvr(struct eri *); 1106833Sgd78059 1116833Sgd78059 #ifdef ERI_10_10_FORCE_SPEED_WORKAROUND 1126833Sgd78059 static void eri_xcvr_force_mode(struct eri *, uint32_t *); 1136833Sgd78059 #endif 1146833Sgd78059 1156833Sgd78059 static void eri_mif_poll(struct eri *, soft_mif_enable_t); 1166833Sgd78059 static void eri_check_link(struct eri *); 1176833Sgd78059 static uint32_t eri_check_link_noind(struct eri *); 1186833Sgd78059 static link_state_t eri_mif_check(struct eri *, uint16_t, uint16_t); 1196833Sgd78059 static void eri_mii_write(struct eri *, uint8_t, uint16_t); 1206833Sgd78059 static uint32_t eri_mii_read(struct eri *, uint8_t, uint16_t *); 1216833Sgd78059 1226833Sgd78059 /* 1236833Sgd78059 * Reset Functions 1246833Sgd78059 */ 1256833Sgd78059 static uint32_t eri_etx_reset(struct eri *); 1266833Sgd78059 static uint32_t eri_erx_reset(struct eri *); 1276833Sgd78059 1286833Sgd78059 /* 1296833Sgd78059 * Error Functions 1306833Sgd78059 */ 1316833Sgd78059 static void eri_fatal_err(struct eri *, uint32_t); 1326833Sgd78059 static void eri_nonfatal_err(struct eri *, uint32_t); 1336833Sgd78059 1346833Sgd78059 #ifdef ERI_TX_HUNG 1356833Sgd78059 static int eri_check_txhung(struct eri *); 1366833Sgd78059 #endif 1376833Sgd78059 1386833Sgd78059 /* 1396833Sgd78059 * Hardening Functions 1406833Sgd78059 */ 1416833Sgd78059 static void eri_fault_msg(struct eri *, uint_t, msg_t, const char *, ...); 1426833Sgd78059 1436833Sgd78059 /* 1446833Sgd78059 * Misc Functions 1456833Sgd78059 */ 1466833Sgd78059 static void eri_savecntrs(struct eri *); 1476833Sgd78059 1486833Sgd78059 static void eri_stop_timer(struct eri *erip); 1496833Sgd78059 static void eri_start_timer(struct eri *erip, fptrv_t func, clock_t msec); 1506833Sgd78059 1516833Sgd78059 static void eri_bb_force_idle(struct eri *); 1526833Sgd78059 1536833Sgd78059 /* 1546833Sgd78059 * Utility Functions 1556833Sgd78059 */ 1566833Sgd78059 static mblk_t *eri_allocb(size_t size); 1576833Sgd78059 static mblk_t *eri_allocb_sp(size_t size); 1586833Sgd78059 static int eri_param_get(queue_t *q, mblk_t *mp, caddr_t cp); 1596833Sgd78059 static int eri_param_set(queue_t *, mblk_t *, char *, caddr_t); 1606833Sgd78059 1616833Sgd78059 /* 1626833Sgd78059 * Functions to support ndd 1636833Sgd78059 */ 1646833Sgd78059 static void eri_nd_free(caddr_t *nd_pparam); 1656833Sgd78059 1666833Sgd78059 static boolean_t eri_nd_load(caddr_t *nd_pparam, char *name, 1676833Sgd78059 pfi_t get_pfi, pfi_t set_pfi, caddr_t data); 1686833Sgd78059 1696833Sgd78059 static int eri_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp); 1706833Sgd78059 static void eri_param_cleanup(struct eri *); 1716833Sgd78059 static int eri_param_register(struct eri *, param_t *, int); 1726833Sgd78059 static void eri_process_ndd_ioctl(struct eri *, queue_t *, mblk_t *, int); 1736833Sgd78059 static int eri_mk_mblk_tail_space(mblk_t *, mblk_t **, size_t); 1746833Sgd78059 1756833Sgd78059 1766833Sgd78059 static void eri_loopback(struct eri *, queue_t *, mblk_t *); 1776833Sgd78059 1786833Sgd78059 static uint32_t eri_ladrf_bit(const uint8_t *); 1796833Sgd78059 1806833Sgd78059 1816833Sgd78059 /* 1826833Sgd78059 * Nemo (GLDv3) Functions. 1836833Sgd78059 */ 1846833Sgd78059 static int eri_m_stat(void *, uint_t, uint64_t *); 1856833Sgd78059 static int eri_m_start(void *); 1866833Sgd78059 static void eri_m_stop(void *); 1876833Sgd78059 static int eri_m_promisc(void *, boolean_t); 1886833Sgd78059 static int eri_m_multicst(void *, boolean_t, const uint8_t *); 1896833Sgd78059 static int eri_m_unicst(void *, const uint8_t *); 1906833Sgd78059 static void eri_m_ioctl(void *, queue_t *, mblk_t *); 1916833Sgd78059 static boolean_t eri_m_getcapab(void *, mac_capab_t, void *); 1926833Sgd78059 static mblk_t *eri_m_tx(void *, mblk_t *); 1936833Sgd78059 1946833Sgd78059 static mac_callbacks_t eri_m_callbacks = { 1956833Sgd78059 MC_IOCTL | MC_GETCAPAB, 1966833Sgd78059 eri_m_stat, 1976833Sgd78059 eri_m_start, 1986833Sgd78059 eri_m_stop, 1996833Sgd78059 eri_m_promisc, 2006833Sgd78059 eri_m_multicst, 2016833Sgd78059 eri_m_unicst, 2026833Sgd78059 eri_m_tx, 2036833Sgd78059 eri_m_ioctl, 2046833Sgd78059 eri_m_getcapab 2056833Sgd78059 }; 2066833Sgd78059 2076833Sgd78059 /* 2086833Sgd78059 * Define PHY Vendors: Matches to IEEE 2096833Sgd78059 * Organizationally Unique Identifier (OUI) 2106833Sgd78059 */ 2116833Sgd78059 /* 2126833Sgd78059 * The first two are supported as Internal XCVRs 2136833Sgd78059 */ 2146833Sgd78059 #define PHY_VENDOR_LUCENT 0x601d 2156833Sgd78059 2166833Sgd78059 #define PHY_LINK_NONE 0 /* Not attempted yet or retry */ 2176833Sgd78059 #define PHY_LINK_DOWN 1 /* Not being used */ 2186833Sgd78059 #define PHY_LINK_UP 2 /* Not being used */ 2196833Sgd78059 2206833Sgd78059 #define AUTO_SPEED 0 2216833Sgd78059 #define FORCE_SPEED 1 2226833Sgd78059 2236833Sgd78059 /* 2246833Sgd78059 * MIB II broadcast/multicast packets 2256833Sgd78059 */ 2266833Sgd78059 2276833Sgd78059 #define IS_BROADCAST(pkt) (bcmp(pkt, ðerbroadcastaddr, ETHERADDRL) == 0) 2286833Sgd78059 #define IS_MULTICAST(pkt) ((pkt[0] & 01) == 1) 2296833Sgd78059 2306833Sgd78059 #define BUMP_InNUcast(erip, pkt) \ 2316833Sgd78059 if (IS_BROADCAST(pkt)) { \ 2326833Sgd78059 HSTAT(erip, brdcstrcv); \ 2336833Sgd78059 } else if (IS_MULTICAST(pkt)) { \ 2346833Sgd78059 HSTAT(erip, multircv); \ 2356833Sgd78059 } 2366833Sgd78059 2376833Sgd78059 #define BUMP_OutNUcast(erip, pkt) \ 2386833Sgd78059 if (IS_BROADCAST(pkt)) { \ 2396833Sgd78059 HSTAT(erip, brdcstxmt); \ 2406833Sgd78059 } else if (IS_MULTICAST(pkt)) { \ 2416833Sgd78059 HSTAT(erip, multixmt); \ 2426833Sgd78059 } 2436833Sgd78059 2446833Sgd78059 #define NEXTTMDP(tbasep, tmdlimp, tmdp) (((tmdp) + 1) == tmdlimp \ 2456833Sgd78059 ? tbasep : ((tmdp) + 1)) 2466833Sgd78059 2476833Sgd78059 #define ETHERHEADER_SIZE (sizeof (struct ether_header)) 2486833Sgd78059 2496833Sgd78059 #ifdef ERI_RCV_CKSUM 2506833Sgd78059 #define ERI_PROCESS_READ(erip, bp, sum) \ 2516833Sgd78059 { \ 2526833Sgd78059 t_uscalar_t type; \ 2536833Sgd78059 uint_t start_offset, end_offset; \ 2546833Sgd78059 \ 2556833Sgd78059 *(bp->b_wptr) = 0; /* pad byte */ \ 2566833Sgd78059 \ 2576833Sgd78059 /* \ 2586833Sgd78059 * update MIB II statistics \ 2596833Sgd78059 */ \ 2606833Sgd78059 HSTAT(erip, ipackets64); \ 2616833Sgd78059 HSTATN(erip, rbytes64, len); \ 2626833Sgd78059 BUMP_InNUcast(erip, bp->b_rptr); \ 2636833Sgd78059 type = get_ether_type(bp->b_rptr); \ 2646833Sgd78059 if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) { \ 2656833Sgd78059 start_offset = 0; \ 2666990Sgd78059 end_offset = MBLKL(bp) - ETHERHEADER_SIZE; \ 2676833Sgd78059 (void) hcksum_assoc(bp, NULL, NULL, \ 2686833Sgd78059 start_offset, 0, end_offset, sum, \ 2696833Sgd78059 HCK_PARTIALCKSUM, 0); \ 2706833Sgd78059 } else { \ 2716833Sgd78059 /* \ 2726833Sgd78059 * Strip the PADS for 802.3 \ 2736833Sgd78059 */ \ 2746833Sgd78059 if (type <= ETHERMTU) \ 2756833Sgd78059 bp->b_wptr = bp->b_rptr + \ 2766833Sgd78059 ETHERHEADER_SIZE + type; \ 2776833Sgd78059 } \ 2786833Sgd78059 } 2796833Sgd78059 #else 2806833Sgd78059 2816833Sgd78059 #define ERI_PROCESS_READ(erip, bp) \ 2826833Sgd78059 { \ 2836833Sgd78059 t_uscalar_t type; \ 2846833Sgd78059 type = get_ether_type(bp->b_rptr); \ 2856833Sgd78059 \ 2866833Sgd78059 /* \ 2876833Sgd78059 * update MIB II statistics \ 2886833Sgd78059 */ \ 2896833Sgd78059 HSTAT(erip, ipackets64); \ 2906833Sgd78059 HSTATN(erip, rbytes64, len); \ 2916833Sgd78059 BUMP_InNUcast(erip, bp->b_rptr); \ 2926833Sgd78059 /* \ 2936833Sgd78059 * Strip the PADS for 802.3 \ 2946833Sgd78059 */ \ 2956833Sgd78059 if (type <= ETHERMTU) \ 2966833Sgd78059 bp->b_wptr = bp->b_rptr + ETHERHEADER_SIZE + \ 2976833Sgd78059 type; \ 2986833Sgd78059 } 2996833Sgd78059 #endif /* ERI_RCV_CKSUM */ 3006833Sgd78059 3016833Sgd78059 /* 3026833Sgd78059 * TX Interrupt Rate 3036833Sgd78059 */ 3046833Sgd78059 static int tx_interrupt_rate = 16; 3056833Sgd78059 3066833Sgd78059 /* 3076833Sgd78059 * Ethernet broadcast address definition. 3086833Sgd78059 */ 3096833Sgd78059 static uint8_t etherbroadcastaddr[] = { 3106833Sgd78059 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 3116833Sgd78059 }; 3126833Sgd78059 3136833Sgd78059 /* 3146833Sgd78059 * The following variables are used for configuring various features 3156833Sgd78059 */ 3166833Sgd78059 #define ERI_DESC_HANDLE_ALLOC 0x0001 3176833Sgd78059 #define ERI_DESC_MEM_ALLOC 0x0002 3186833Sgd78059 #define ERI_DESC_MEM_MAP 0x0004 3196833Sgd78059 #define ERI_RCV_HANDLE_ALLOC 0x0020 3206833Sgd78059 #define ERI_RCV_HANDLE_BIND 0x0040 3216833Sgd78059 #define ERI_XMIT_DVMA_ALLOC 0x0100 3226833Sgd78059 #define ERI_RCV_DVMA_ALLOC 0x0200 3236833Sgd78059 #define ERI_XBUFS_HANDLE_ALLOC 0x0400 3246833Sgd78059 #define ERI_XBUFS_KMEM_ALLOC 0x0800 3256833Sgd78059 #define ERI_XBUFS_KMEM_DMABIND 0x1000 3266833Sgd78059 3276833Sgd78059 3286833Sgd78059 #define ERI_DONT_STRIP_CRC 3296833Sgd78059 /* 3306833Sgd78059 * Translate a kernel virtual address to i/o address. 3316833Sgd78059 */ 3326833Sgd78059 #define ERI_IOPBIOADDR(erip, a) \ 3336833Sgd78059 ((erip)->iopbiobase + ((uintptr_t)a - (erip)->iopbkbase)) 3346833Sgd78059 3356833Sgd78059 /* 3366833Sgd78059 * ERI Configuration Register Value 3376833Sgd78059 * Used to configure parameters that define DMA burst 3386833Sgd78059 * and internal arbitration behavior. 3396833Sgd78059 * for equal TX and RX bursts, set the following in global 3406833Sgd78059 * configuration register. 3416833Sgd78059 * static int global_config = 0x42; 3426833Sgd78059 */ 3436833Sgd78059 3446833Sgd78059 /* 3456833Sgd78059 * ERI ERX Interrupt Blanking Time 3466833Sgd78059 * Each count is about 16 us (2048 clocks) for 66 MHz PCI. 3476833Sgd78059 */ 3486833Sgd78059 static int intr_blank_time = 6; /* for about 96 us */ 3496833Sgd78059 static int intr_blank_packets = 8; /* */ 3506833Sgd78059 3516833Sgd78059 /* 3526833Sgd78059 * ERX PAUSE Threshold Register value 3536833Sgd78059 * The following value is for an OFF Threshold of about 15.5 Kbytes 3546833Sgd78059 * and an ON Threshold of 4K bytes. 3556833Sgd78059 */ 3566833Sgd78059 static int rx_pause_threshold = 0xf8 | (0x40 << 12); 3576833Sgd78059 static int eri_reinit_fatal = 0; 3586833Sgd78059 #ifdef DEBUG 3596833Sgd78059 static int noteri = 0; 3606833Sgd78059 #endif 3616833Sgd78059 3626833Sgd78059 #ifdef ERI_TX_HUNG 3636833Sgd78059 static int eri_reinit_txhung = 0; 3646833Sgd78059 #endif 3656833Sgd78059 3666833Sgd78059 #ifdef ERI_HDX_BUG_WORKAROUND 3676833Sgd78059 /* 3686833Sgd78059 * By default enable padding in hdx mode to 97 bytes. 3696833Sgd78059 * To disabled, in /etc/system: 3706833Sgd78059 * set eri:eri_hdx_pad_enable=0 3716833Sgd78059 */ 3726833Sgd78059 static uchar_t eri_hdx_pad_enable = 1; 3736833Sgd78059 #endif 3746833Sgd78059 3756833Sgd78059 /* 3766833Sgd78059 * Default values to initialize the cache line size and latency timer 3776833Sgd78059 * registers in the PCI configuration space. 3786833Sgd78059 * ERI_G_CACHE_LINE_SIZE_16 is defined as 16 since RIO expects in units 3796833Sgd78059 * of 4 bytes. 3806833Sgd78059 */ 3816833Sgd78059 #ifdef ERI_PM_WORKAROUND_PCI 3826833Sgd78059 static int eri_pci_cache_line = ERI_G_CACHE_LINE_SIZE_32; /* 128 bytes */ 3836833Sgd78059 static int eri_pci_latency_timer = 0xff; /* 255 PCI cycles */ 3846833Sgd78059 #else 3856833Sgd78059 static int eri_pci_cache_line = ERI_G_CACHE_LINE_SIZE_16; /* 64 bytes */ 3866833Sgd78059 static int eri_pci_latency_timer = 0x40; /* 64 PCI cycles */ 3876833Sgd78059 #endif 3886833Sgd78059 #define ERI_CACHE_LINE_SIZE (eri_pci_cache_line << ERI_G_CACHE_BIT) 3896833Sgd78059 3906833Sgd78059 /* 3916833Sgd78059 * Claim the device is ultra-capable of burst in the beginning. Use 3926833Sgd78059 * the value returned by ddi_dma_burstsizes() to actually set the ERI 3936833Sgd78059 * global configuration register later. 3946833Sgd78059 * 3956833Sgd78059 * PCI_ERI supports Infinite burst or 64-byte-multiple bursts. 3966833Sgd78059 */ 3976833Sgd78059 #define ERI_LIMADDRLO ((uint64_t)0x00000000) 3986833Sgd78059 #define ERI_LIMADDRHI ((uint64_t)0xffffffff) 3996833Sgd78059 4006833Sgd78059 static ddi_dma_attr_t dma_attr = { 4016833Sgd78059 DMA_ATTR_V0, /* version number. */ 4026833Sgd78059 (uint64_t)ERI_LIMADDRLO, /* low address */ 4036833Sgd78059 (uint64_t)ERI_LIMADDRHI, /* high address */ 4046833Sgd78059 (uint64_t)0x00ffffff, /* address counter max */ 4056833Sgd78059 (uint64_t)1, /* alignment */ 4066833Sgd78059 (uint_t)0xe000e0, /* dlim_burstsizes for 32 4 bit xfers */ 4076833Sgd78059 (uint32_t)0x1, /* minimum transfer size */ 4086833Sgd78059 (uint64_t)0x7fffffff, /* maximum transfer size */ 4096833Sgd78059 (uint64_t)0x00ffffff, /* maximum segment size */ 4106833Sgd78059 1, /* scatter/gather list length */ 4116833Sgd78059 (uint32_t)1, /* granularity */ 4126833Sgd78059 (uint_t)0 /* attribute flags */ 4136833Sgd78059 }; 4146833Sgd78059 4156833Sgd78059 static ddi_dma_attr_t desc_dma_attr = { 4166833Sgd78059 DMA_ATTR_V0, /* version number. */ 4176833Sgd78059 (uint64_t)ERI_LIMADDRLO, /* low address */ 4186833Sgd78059 (uint64_t)ERI_LIMADDRHI, /* high address */ 4196833Sgd78059 (uint64_t)0x00ffffff, /* address counter max */ 4206833Sgd78059 (uint64_t)8, /* alignment */ 4216833Sgd78059 (uint_t)0xe000e0, /* dlim_burstsizes for 32 4 bit xfers */ 4226833Sgd78059 (uint32_t)0x1, /* minimum transfer size */ 4236833Sgd78059 (uint64_t)0x7fffffff, /* maximum transfer size */ 4246833Sgd78059 (uint64_t)0x00ffffff, /* maximum segment size */ 4256833Sgd78059 1, /* scatter/gather list length */ 4266833Sgd78059 16, /* granularity */ 4276833Sgd78059 0 /* attribute flags */ 4286833Sgd78059 }; 4296833Sgd78059 4307394Sgdamore@opensolaris.org static ddi_device_acc_attr_t buf_attr = { 4317394Sgdamore@opensolaris.org DDI_DEVICE_ATTR_V0, /* devacc_attr_version */ 4327394Sgdamore@opensolaris.org DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */ 4337394Sgdamore@opensolaris.org DDI_STRICTORDER_ACC, /* devacc_attr_dataorder */ 4347394Sgdamore@opensolaris.org DDI_DEFAULT_ACC, /* devacc_attr_access */ 4357394Sgdamore@opensolaris.org }; 4367394Sgdamore@opensolaris.org 4376833Sgd78059 ddi_dma_lim_t eri_dma_limits = { 4386833Sgd78059 (uint64_t)ERI_LIMADDRLO, /* dlim_addr_lo */ 4396833Sgd78059 (uint64_t)ERI_LIMADDRHI, /* dlim_addr_hi */ 4406833Sgd78059 (uint64_t)ERI_LIMADDRHI, /* dlim_cntr_max */ 4416833Sgd78059 (uint_t)0x00e000e0, /* dlim_burstsizes for 32 and 64 bit xfers */ 4426833Sgd78059 (uint32_t)0x1, /* dlim_minxfer */ 4436833Sgd78059 1024 /* dlim_speed */ 4446833Sgd78059 }; 4456833Sgd78059 4466833Sgd78059 /* 4476833Sgd78059 * Link Configuration variables 4486833Sgd78059 * 4496833Sgd78059 * On Motherboard implementations, 10/100 Mbps speeds may be supported 4506833Sgd78059 * by using both the Serial Link and the MII on Non-serial-link interface. 4516833Sgd78059 * When both links are present, the driver automatically tries to bring up 4526833Sgd78059 * both. If both are up, the Gigabit Serial Link is selected for use, by 4536833Sgd78059 * default. The following configuration variable is used to force the selection 4546833Sgd78059 * of one of the links when both are up. 4556833Sgd78059 * To change the default selection to the MII link when both the Serial 4566833Sgd78059 * Link and the MII link are up, change eri_default_link to 1. 4576833Sgd78059 * 4586833Sgd78059 * Once a link is in use, the driver will continue to use that link till it 4596833Sgd78059 * goes down. When it goes down, the driver will look at the status of both the 4606833Sgd78059 * links again for link selection. 4616833Sgd78059 * 4626833Sgd78059 * Currently the standard is not stable w.r.t. gigabit link configuration 4636833Sgd78059 * using auto-negotiation procedures. Meanwhile, the link may be configured 4646833Sgd78059 * in "forced" mode using the "autonegotiation enable" bit (bit-12) in the 4656833Sgd78059 * PCS MII Command Register. In this mode the PCS sends "idles" until sees 4666833Sgd78059 * "idles" as initialization instead of the Link Configuration protocol 4676833Sgd78059 * where a Config register is exchanged. In this mode, the ERI is programmed 4686833Sgd78059 * for full-duplex operation with both pauseTX and pauseRX (for flow control) 4696833Sgd78059 * enabled. 4706833Sgd78059 */ 4716833Sgd78059 4726833Sgd78059 static int select_link = 0; /* automatic selection */ 4736833Sgd78059 static int default_link = 0; /* Select Serial link if both are up */ 4746833Sgd78059 4756833Sgd78059 /* 4766833Sgd78059 * The following variables are used for configuring link-operation 4776833Sgd78059 * for all the "eri" interfaces in the system. 4786833Sgd78059 * Later these parameters may be changed per interface using "ndd" command 4796833Sgd78059 * These parameters may also be specified as properties using the .conf 4806833Sgd78059 * file mechanism for each interface. 4816833Sgd78059 */ 4826833Sgd78059 4836833Sgd78059 /* 4846833Sgd78059 * The following variable value will be overridden by "link-pulse-disabled" 4856833Sgd78059 * property which may be created by OBP or eri.conf file. This property is 4866833Sgd78059 * applicable only for 10 Mbps links. 4876833Sgd78059 */ 4886833Sgd78059 static int link_pulse_disabled = 0; /* link pulse disabled */ 4896833Sgd78059 4906833Sgd78059 /* For MII-based FastEthernet links */ 4916833Sgd78059 static int adv_autoneg_cap = 1; 4926833Sgd78059 static int adv_100T4_cap = 0; 4936833Sgd78059 static int adv_100fdx_cap = 1; 4946833Sgd78059 static int adv_100hdx_cap = 1; 4956833Sgd78059 static int adv_10fdx_cap = 1; 4966833Sgd78059 static int adv_10hdx_cap = 1; 4976833Sgd78059 static int adv_pauseTX_cap = 0; 4986833Sgd78059 static int adv_pauseRX_cap = 0; 4996833Sgd78059 5006833Sgd78059 /* 5016833Sgd78059 * The following gap parameters are in terms of byte times. 5026833Sgd78059 */ 5036833Sgd78059 static int ipg0 = 8; 5046833Sgd78059 static int ipg1 = 8; 5056833Sgd78059 static int ipg2 = 4; 5066833Sgd78059 5076833Sgd78059 static int lance_mode = 1; /* to enable LANCE mode */ 5086833Sgd78059 static int mifpoll_enable = 0; /* to enable mif poll */ 5096833Sgd78059 static int ngu_enable = 0; /* to enable Never Give Up mode */ 5106833Sgd78059 5116833Sgd78059 static int eri_force_mlf = 0; /* to enable mif poll */ 5126833Sgd78059 static int eri_phy_mintrans = 1; /* Lu3X31T mintrans algorithm */ 5136833Sgd78059 /* 5146833Sgd78059 * For the MII interface, the External Transceiver is selected when present. 5156833Sgd78059 * The following variable is used to select the Internal Transceiver even 5166833Sgd78059 * when the External Transceiver is present. 5176833Sgd78059 */ 5186833Sgd78059 static int use_int_xcvr = 0; 5196833Sgd78059 static int pace_size = 0; /* Do not use pacing for now */ 5206833Sgd78059 5216833Sgd78059 static int eri_use_dvma_rx = 0; /* =1:use dvma */ 5226833Sgd78059 static int eri_rx_bcopy_max = RX_BCOPY_MAX; /* =1:use bcopy() */ 5236833Sgd78059 static int eri_overflow_reset = 1; /* global reset if rx_fifo_overflow */ 5246833Sgd78059 static int eri_tx_ring_size = 2048; /* number of entries in tx ring */ 5256833Sgd78059 static int eri_rx_ring_size = 1024; /* number of entries in rx ring */ 5266833Sgd78059 /* 5276833Sgd78059 * The following parameters may be configured by the user. If they are not 5286833Sgd78059 * configured by the user, the values will be based on the capabilities of 5296833Sgd78059 * the transceiver. 5306833Sgd78059 * The value "ERI_NOTUSR" is ORed with the parameter value to indicate values 5316833Sgd78059 * which are NOT configured by the user. 5326833Sgd78059 */ 5336833Sgd78059 5346833Sgd78059 #define ERI_NOTUSR 0x0f000000 5356833Sgd78059 #define ERI_MASK_1BIT 0x1 5366833Sgd78059 #define ERI_MASK_2BIT 0x3 5376833Sgd78059 #define ERI_MASK_8BIT 0xff 5386833Sgd78059 5396833Sgd78059 5406833Sgd78059 /* 5416833Sgd78059 * Note: 5426833Sgd78059 * ERI has all of the above capabilities. 5436833Sgd78059 * Only when an External Transceiver is selected for MII-based FastEthernet 5446833Sgd78059 * link operation, the capabilities depend upon the capabilities of the 5456833Sgd78059 * External Transceiver. 5466833Sgd78059 */ 5476833Sgd78059 5486833Sgd78059 /* ------------------------------------------------------------------------- */ 5496833Sgd78059 5506833Sgd78059 static param_t param_arr[] = { 5516833Sgd78059 /* min max value r/w/hidden+name */ 5526833Sgd78059 { 0, 2, 2, "-transceiver_inuse"}, 5536833Sgd78059 { 0, 1, 0, "-link_status"}, 5546833Sgd78059 { 0, 1, 0, "-link_speed"}, 5556833Sgd78059 { 0, 1, 0, "-link_mode"}, 5566833Sgd78059 { 0, 255, 8, "+ipg1"}, 5576833Sgd78059 { 0, 255, 4, "+ipg2"}, 5586833Sgd78059 { 0, 1, 0, "+use_int_xcvr"}, 5596833Sgd78059 { 0, 255, 0, "+pace_size"}, 5606833Sgd78059 { 0, 1, 1, "+adv_autoneg_cap"}, 5616833Sgd78059 { 0, 1, 1, "+adv_100T4_cap"}, 5626833Sgd78059 { 0, 1, 1, "+adv_100fdx_cap"}, 5636833Sgd78059 { 0, 1, 1, "+adv_100hdx_cap"}, 5646833Sgd78059 { 0, 1, 1, "+adv_10fdx_cap"}, 5656833Sgd78059 { 0, 1, 1, "+adv_10hdx_cap"}, 5666833Sgd78059 { 0, 1, 1, "-autoneg_cap"}, 5676833Sgd78059 { 0, 1, 1, "-100T4_cap"}, 5686833Sgd78059 { 0, 1, 1, "-100fdx_cap"}, 5696833Sgd78059 { 0, 1, 1, "-100hdx_cap"}, 5706833Sgd78059 { 0, 1, 1, "-10fdx_cap"}, 5716833Sgd78059 { 0, 1, 1, "-10hdx_cap"}, 5726833Sgd78059 { 0, 1, 0, "-lp_autoneg_cap"}, 5736833Sgd78059 { 0, 1, 0, "-lp_100T4_cap"}, 5746833Sgd78059 { 0, 1, 0, "-lp_100fdx_cap"}, 5756833Sgd78059 { 0, 1, 0, "-lp_100hdx_cap"}, 5766833Sgd78059 { 0, 1, 0, "-lp_10fdx_cap"}, 5776833Sgd78059 { 0, 1, 0, "-lp_10hdx_cap"}, 5786833Sgd78059 { 0, 1, 1, "+lance_mode"}, 5796833Sgd78059 { 0, 31, 8, "+ipg0"}, 5806833Sgd78059 { 0, 127, 6, "+intr_blank_time"}, 5816833Sgd78059 { 0, 255, 8, "+intr_blank_packets"}, 5826833Sgd78059 { 0, 1, 1, "!serial-link"}, 5836833Sgd78059 { 0, 2, 1, "!non-serial-link"}, 5846833Sgd78059 { 0, 1, 0, "%select-link"}, 5856833Sgd78059 { 0, 1, 0, "%default-link"}, 5866833Sgd78059 { 0, 2, 0, "!link-in-use"}, 5876833Sgd78059 { 0, 1, 1, "%adv_asm_dir_cap"}, 5886833Sgd78059 { 0, 1, 1, "%adv_pause_cap"}, 5896833Sgd78059 { 0, 1, 0, "!asm_dir_cap"}, 5906833Sgd78059 { 0, 1, 0, "!pause_cap"}, 5916833Sgd78059 { 0, 1, 0, "!lp_asm_dir_cap"}, 5926833Sgd78059 { 0, 1, 0, "!lp_pause_cap"}, 5936833Sgd78059 }; 5946833Sgd78059 5956833Sgd78059 DDI_DEFINE_STREAM_OPS(eri_dev_ops, nulldev, nulldev, eri_attach, eri_detach, 5967656SSherry.Moore@Sun.COM nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported); 5976833Sgd78059 5986833Sgd78059 /* 5996833Sgd78059 * This is the loadable module wrapper. 6006833Sgd78059 */ 6016833Sgd78059 #include <sys/modctl.h> 6026833Sgd78059 6036833Sgd78059 /* 6046833Sgd78059 * Module linkage information for the kernel. 6056833Sgd78059 */ 6066833Sgd78059 static struct modldrv modldrv = { 6076833Sgd78059 &mod_driverops, /* Type of module. This one is a driver */ 6086833Sgd78059 "Sun RIO 10/100 Mb Ethernet", 6096833Sgd78059 &eri_dev_ops, /* driver ops */ 6106833Sgd78059 }; 6116833Sgd78059 6126833Sgd78059 static struct modlinkage modlinkage = { 6136833Sgd78059 MODREV_1, &modldrv, NULL 6146833Sgd78059 }; 6156833Sgd78059 6166833Sgd78059 /* 6176833Sgd78059 * Hardware Independent Functions 6186833Sgd78059 * New Section 6196833Sgd78059 */ 6206833Sgd78059 6216833Sgd78059 int 6226833Sgd78059 _init(void) 6236833Sgd78059 { 6246833Sgd78059 int status; 6256833Sgd78059 6266833Sgd78059 mac_init_ops(&eri_dev_ops, "eri"); 6276833Sgd78059 if ((status = mod_install(&modlinkage)) != 0) { 6286833Sgd78059 mac_fini_ops(&eri_dev_ops); 6296833Sgd78059 } 6306833Sgd78059 return (status); 6316833Sgd78059 } 6326833Sgd78059 6336833Sgd78059 int 6346833Sgd78059 _fini(void) 6356833Sgd78059 { 6366833Sgd78059 int status; 6376833Sgd78059 6386833Sgd78059 status = mod_remove(&modlinkage); 6396833Sgd78059 if (status == 0) { 6406833Sgd78059 mac_fini_ops(&eri_dev_ops); 6416833Sgd78059 } 6426833Sgd78059 return (status); 6436833Sgd78059 } 6446833Sgd78059 6456833Sgd78059 int 6466833Sgd78059 _info(struct modinfo *modinfop) 6476833Sgd78059 { 6486833Sgd78059 return (mod_info(&modlinkage, modinfop)); 6496833Sgd78059 } 6506833Sgd78059 6516833Sgd78059 6526833Sgd78059 /* 6536833Sgd78059 * Interface exists: make available by filling in network interface 6546833Sgd78059 * record. System will initialize the interface when it is ready 6556833Sgd78059 * to accept packets. 6566833Sgd78059 */ 6576833Sgd78059 static int 6586833Sgd78059 eri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6596833Sgd78059 { 6606833Sgd78059 struct eri *erip = NULL; 6616833Sgd78059 mac_register_t *macp = NULL; 6626833Sgd78059 int regno; 6636833Sgd78059 boolean_t doinit; 6646833Sgd78059 boolean_t mutex_inited = B_FALSE; 6656833Sgd78059 boolean_t intr_add = B_FALSE; 6666833Sgd78059 6676833Sgd78059 switch (cmd) { 6686833Sgd78059 case DDI_ATTACH: 6696833Sgd78059 break; 6706833Sgd78059 6716833Sgd78059 case DDI_RESUME: 6726833Sgd78059 if ((erip = ddi_get_driver_private(dip)) == NULL) 6736833Sgd78059 return (DDI_FAILURE); 6746833Sgd78059 6756833Sgd78059 mutex_enter(&erip->intrlock); 6766833Sgd78059 erip->flags &= ~ERI_SUSPENDED; 6776833Sgd78059 erip->init_macregs = 1; 6786833Sgd78059 param_linkup = 0; 6796833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 6806833Sgd78059 erip->linkcheck = 0; 6816833Sgd78059 6826833Sgd78059 doinit = (erip->flags & ERI_STARTED) ? B_TRUE : B_FALSE; 6836833Sgd78059 mutex_exit(&erip->intrlock); 6846833Sgd78059 6856833Sgd78059 if (doinit && !eri_init(erip)) { 6866833Sgd78059 return (DDI_FAILURE); 6876833Sgd78059 } 6886833Sgd78059 return (DDI_SUCCESS); 6896833Sgd78059 6906833Sgd78059 default: 6916833Sgd78059 return (DDI_FAILURE); 6926833Sgd78059 } 6936833Sgd78059 6946833Sgd78059 /* 6956833Sgd78059 * Allocate soft device data structure 6966833Sgd78059 */ 6976833Sgd78059 erip = kmem_zalloc(sizeof (struct eri), KM_SLEEP); 6986833Sgd78059 6996833Sgd78059 /* 7006833Sgd78059 * Initialize as many elements as possible. 7016833Sgd78059 */ 7026833Sgd78059 ddi_set_driver_private(dip, erip); 7036833Sgd78059 erip->dip = dip; /* dip */ 7046833Sgd78059 erip->instance = ddi_get_instance(dip); /* instance */ 7056833Sgd78059 erip->flags = 0; 7066833Sgd78059 erip->multi_refcnt = 0; 7076833Sgd78059 erip->promisc = B_FALSE; 7086833Sgd78059 7096833Sgd78059 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 7106833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG, 7116833Sgd78059 "mac_alloc failed"); 7126833Sgd78059 goto attach_fail; 7136833Sgd78059 } 7146833Sgd78059 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7156833Sgd78059 macp->m_driver = erip; 7166833Sgd78059 macp->m_dip = dip; 7176833Sgd78059 macp->m_src_addr = erip->ouraddr; 7186833Sgd78059 macp->m_callbacks = &eri_m_callbacks; 7196833Sgd78059 macp->m_min_sdu = 0; 7206833Sgd78059 macp->m_max_sdu = ETHERMTU; 7216833Sgd78059 macp->m_margin = VLAN_TAGSZ; 7226833Sgd78059 7236833Sgd78059 /* 7246833Sgd78059 * Map in the device registers. 7256833Sgd78059 * Separate pointers will be set up for the following 7266833Sgd78059 * register groups within the GEM Register Space: 7276833Sgd78059 * Global register set 7286833Sgd78059 * ETX register set 7296833Sgd78059 * ERX register set 7306833Sgd78059 * BigMAC register set. 7316833Sgd78059 * MIF register set 7326833Sgd78059 */ 7336833Sgd78059 7346833Sgd78059 if (ddi_dev_nregs(dip, ®no) != (DDI_SUCCESS)) { 7356833Sgd78059 ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG, 7366833Sgd78059 "ddi_dev_nregs failed, returned %d", regno); 7376833Sgd78059 goto attach_fail; 7386833Sgd78059 } 7396833Sgd78059 7406833Sgd78059 /* 7416833Sgd78059 * Map the PCI config space 7426833Sgd78059 */ 7436833Sgd78059 if (pci_config_setup(dip, &erip->pci_config_handle) != DDI_SUCCESS) { 7446833Sgd78059 ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG, 7456833Sgd78059 "%s pci_config_setup()", config_space_fatal_msg); 7466833Sgd78059 goto attach_fail; 7476833Sgd78059 } 7486833Sgd78059 7496833Sgd78059 /* 7506833Sgd78059 * Initialize device attributes structure 7516833Sgd78059 */ 7526833Sgd78059 erip->dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 7536833Sgd78059 erip->dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 7546833Sgd78059 erip->dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 7556833Sgd78059 7566833Sgd78059 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&(erip->globregp), 0, 0, 7576833Sgd78059 &erip->dev_attr, &erip->globregh)) { 7586833Sgd78059 goto attach_fail; 7596833Sgd78059 } 7606833Sgd78059 erip->etxregh = erip->globregh; 7616833Sgd78059 erip->erxregh = erip->globregh; 7626833Sgd78059 erip->bmacregh = erip->globregh; 7636833Sgd78059 erip->mifregh = erip->globregh; 7646833Sgd78059 7656833Sgd78059 erip->etxregp = (void *)(((caddr_t)erip->globregp) + 0x2000); 7666833Sgd78059 erip->erxregp = (void *)(((caddr_t)erip->globregp) + 0x4000); 7676833Sgd78059 erip->bmacregp = (void *)(((caddr_t)erip->globregp) + 0x6000); 7686833Sgd78059 erip->mifregp = (void *)(((caddr_t)erip->globregp) + 0x6200); 7696833Sgd78059 7706833Sgd78059 /* 7716833Sgd78059 * Map the software reset register. 7726833Sgd78059 */ 7736833Sgd78059 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&(erip->sw_reset_reg), 7746833Sgd78059 0x1010, 4, &erip->dev_attr, &erip->sw_reset_regh)) { 7756833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_MID, ERI_VERB_MSG, 7766833Sgd78059 mregs_4soft_reset_fail_msg); 7776833Sgd78059 goto attach_fail; 7786833Sgd78059 } 7796833Sgd78059 7806833Sgd78059 /* 7816833Sgd78059 * Try and stop the device. 7826833Sgd78059 * This is done until we want to handle interrupts. 7836833Sgd78059 */ 7846833Sgd78059 if (eri_stop(erip)) 7856833Sgd78059 goto attach_fail; 7866833Sgd78059 7876833Sgd78059 /* 7886833Sgd78059 * set PCI latency timer register. 7896833Sgd78059 */ 7906833Sgd78059 pci_config_put8(erip->pci_config_handle, PCI_CONF_LATENCY_TIMER, 7916833Sgd78059 (uchar_t)eri_pci_latency_timer); 7926833Sgd78059 7936833Sgd78059 if (ddi_intr_hilevel(dip, 0)) { 7946833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, 7956833Sgd78059 " high-level interrupts are not supported"); 7966833Sgd78059 goto attach_fail; 7976833Sgd78059 } 7986833Sgd78059 7996833Sgd78059 /* 8006833Sgd78059 * Get the interrupt cookie so the mutexes can be 8016833Sgd78059 * Initialized. 8026833Sgd78059 */ 8036833Sgd78059 if (ddi_get_iblock_cookie(dip, 0, &erip->cookie) != DDI_SUCCESS) 8046833Sgd78059 goto attach_fail; 8056833Sgd78059 8066833Sgd78059 /* 8076833Sgd78059 * Initialize mutex's for this device. 8086833Sgd78059 */ 8096833Sgd78059 mutex_init(&erip->xmitlock, NULL, MUTEX_DRIVER, (void *)erip->cookie); 8106833Sgd78059 mutex_init(&erip->intrlock, NULL, MUTEX_DRIVER, (void *)erip->cookie); 8116833Sgd78059 mutex_init(&erip->linklock, NULL, MUTEX_DRIVER, (void *)erip->cookie); 8126833Sgd78059 mutex_init(&erip->xcvrlock, NULL, MUTEX_DRIVER, (void *)erip->cookie); 8136833Sgd78059 8146833Sgd78059 mutex_inited = B_TRUE; 8156833Sgd78059 8166833Sgd78059 /* 8176833Sgd78059 * Add interrupt to system 8186833Sgd78059 */ 8196833Sgd78059 if (ddi_add_intr(dip, 0, &erip->cookie, 0, eri_intr, (caddr_t)erip) == 8206833Sgd78059 DDI_SUCCESS) 8216833Sgd78059 intr_add = B_TRUE; 8226833Sgd78059 else { 8236833Sgd78059 goto attach_fail; 8246833Sgd78059 } 8256833Sgd78059 8266833Sgd78059 /* 8276833Sgd78059 * Set up the ethernet mac address. 8286833Sgd78059 */ 8296833Sgd78059 (void) eri_setup_mac_address(erip, dip); 8306833Sgd78059 8316833Sgd78059 if (eri_init_xfer_params(erip)) 8326833Sgd78059 goto attach_fail; 8336833Sgd78059 8346833Sgd78059 if (eri_burstsize(erip) == DDI_FAILURE) { 8356833Sgd78059 goto attach_fail; 8366833Sgd78059 } 8376833Sgd78059 8386833Sgd78059 /* 8396833Sgd78059 * Setup fewer receive bufers. 8406833Sgd78059 */ 8416833Sgd78059 ERI_RPENDING = eri_rx_ring_size; 8426833Sgd78059 ERI_TPENDING = eri_tx_ring_size; 8436833Sgd78059 8446833Sgd78059 erip->rpending_mask = ERI_RPENDING - 1; 8456833Sgd78059 erip->rmdmax_mask = ERI_RPENDING - 1; 8466833Sgd78059 erip->mif_config = (ERI_PHY_BMSR << ERI_MIF_CFGPR_SHIFT); 8476833Sgd78059 8486833Sgd78059 erip->stats.pmcap = ERI_PMCAP_NONE; 8496833Sgd78059 if (pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000) == 8506833Sgd78059 DDI_SUCCESS) 8516833Sgd78059 erip->stats.pmcap = ERI_PMCAP_4MHZ; 8526833Sgd78059 8536833Sgd78059 if (mac_register(macp, &erip->mh) != 0) 8546833Sgd78059 goto attach_fail; 8556833Sgd78059 8566833Sgd78059 mac_free(macp); 8576833Sgd78059 8586833Sgd78059 return (DDI_SUCCESS); 8596833Sgd78059 8606833Sgd78059 attach_fail: 8616833Sgd78059 if (erip->pci_config_handle) 8626833Sgd78059 (void) pci_config_teardown(&erip->pci_config_handle); 8636833Sgd78059 8646833Sgd78059 if (mutex_inited) { 8656833Sgd78059 mutex_destroy(&erip->xmitlock); 8666833Sgd78059 mutex_destroy(&erip->intrlock); 8676833Sgd78059 mutex_destroy(&erip->linklock); 8686833Sgd78059 mutex_destroy(&erip->xcvrlock); 8696833Sgd78059 } 8706833Sgd78059 8716833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, attach_fail_msg); 8726833Sgd78059 8736833Sgd78059 if (intr_add) 8746833Sgd78059 ddi_remove_intr(dip, 0, erip->cookie); 8756833Sgd78059 8766833Sgd78059 if (erip->globregh) 8776833Sgd78059 ddi_regs_map_free(&erip->globregh); 8786833Sgd78059 8796833Sgd78059 if (macp != NULL) 8806833Sgd78059 mac_free(macp); 8816833Sgd78059 if (erip != NULL) 8826833Sgd78059 kmem_free(erip, sizeof (*erip)); 8836833Sgd78059 8846833Sgd78059 return (DDI_FAILURE); 8856833Sgd78059 } 8866833Sgd78059 8876833Sgd78059 static int 8886833Sgd78059 eri_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 8896833Sgd78059 { 8906833Sgd78059 struct eri *erip; 8916833Sgd78059 int i; 8926833Sgd78059 8936833Sgd78059 if ((erip = ddi_get_driver_private(dip)) == NULL) { 8946833Sgd78059 /* 8956833Sgd78059 * No resources allocated. 8966833Sgd78059 */ 8976833Sgd78059 return (DDI_FAILURE); 8986833Sgd78059 } 8996833Sgd78059 9006833Sgd78059 switch (cmd) { 9016833Sgd78059 case DDI_DETACH: 9026833Sgd78059 break; 9036833Sgd78059 9046833Sgd78059 case DDI_SUSPEND: 9056833Sgd78059 erip->flags |= ERI_SUSPENDED; 9066833Sgd78059 eri_uninit(erip); 9076833Sgd78059 return (DDI_SUCCESS); 9086833Sgd78059 9096833Sgd78059 default: 9106833Sgd78059 return (DDI_FAILURE); 9116833Sgd78059 } 9126833Sgd78059 9136833Sgd78059 if (erip->flags & (ERI_RUNNING | ERI_SUSPENDED)) { 9146833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, busy_msg); 9156833Sgd78059 return (DDI_FAILURE); 9166833Sgd78059 } 9176833Sgd78059 9186833Sgd78059 if (mac_unregister(erip->mh) != 0) { 9196833Sgd78059 return (DDI_FAILURE); 9206833Sgd78059 } 9216833Sgd78059 9226833Sgd78059 /* 9236833Sgd78059 * Make the device quiescent 9246833Sgd78059 */ 9256833Sgd78059 (void) eri_stop(erip); 9266833Sgd78059 9276833Sgd78059 /* 9286833Sgd78059 * Remove instance of the intr 9296833Sgd78059 */ 9306833Sgd78059 ddi_remove_intr(dip, 0, erip->cookie); 9316833Sgd78059 9326833Sgd78059 if (erip->pci_config_handle) 9336833Sgd78059 (void) pci_config_teardown(&erip->pci_config_handle); 9346833Sgd78059 9356833Sgd78059 /* 9366833Sgd78059 * Destroy all mutexes and data structures allocated during 9376833Sgd78059 * attach time. 9386833Sgd78059 */ 9396833Sgd78059 9406833Sgd78059 if (erip->globregh) 9416833Sgd78059 ddi_regs_map_free(&erip->globregh); 9426833Sgd78059 9436833Sgd78059 erip->etxregh = NULL; 9446833Sgd78059 erip->erxregh = NULL; 9456833Sgd78059 erip->bmacregh = NULL; 9466833Sgd78059 erip->mifregh = NULL; 9476833Sgd78059 erip->globregh = NULL; 9486833Sgd78059 9496833Sgd78059 if (erip->sw_reset_regh) 9506833Sgd78059 ddi_regs_map_free(&erip->sw_reset_regh); 9516833Sgd78059 9526833Sgd78059 if (erip->ksp) 9536833Sgd78059 kstat_delete(erip->ksp); 9546833Sgd78059 9556833Sgd78059 eri_stop_timer(erip); /* acquire linklock */ 9566833Sgd78059 eri_start_timer(erip, eri_check_link, 0); 9576833Sgd78059 mutex_destroy(&erip->xmitlock); 9586833Sgd78059 mutex_destroy(&erip->intrlock); 9596833Sgd78059 mutex_destroy(&erip->linklock); 9606833Sgd78059 mutex_destroy(&erip->xcvrlock); 9616833Sgd78059 9626833Sgd78059 if (erip->md_h) { 9636833Sgd78059 if (ddi_dma_unbind_handle(erip->md_h) == 9646833Sgd78059 DDI_FAILURE) 9656833Sgd78059 return (DDI_FAILURE); 9666833Sgd78059 ddi_dma_mem_free(&erip->mdm_h); 9676833Sgd78059 ddi_dma_free_handle(&erip->md_h); 9686833Sgd78059 } 9696833Sgd78059 9706833Sgd78059 if (eri_freebufs(erip)) 9716833Sgd78059 return (DDI_FAILURE); 9726833Sgd78059 9736833Sgd78059 /* dvma handle case */ 9746833Sgd78059 9756833Sgd78059 if (erip->eri_dvmarh) { 9766833Sgd78059 (void) dvma_release(erip->eri_dvmarh); 9776833Sgd78059 erip->eri_dvmarh = NULL; 9786833Sgd78059 } 9796833Sgd78059 /* 9806833Sgd78059 * xmit_dma_mode, erip->ndmaxh[i]=NULL for dvma 9816833Sgd78059 */ 9826833Sgd78059 else { 9836833Sgd78059 for (i = 0; i < ERI_RPENDING; i++) 9846833Sgd78059 if (erip->ndmarh[i]) 9856833Sgd78059 ddi_dma_free_handle(&erip->ndmarh[i]); 9866833Sgd78059 } 9876833Sgd78059 /* 9887394Sgdamore@opensolaris.org * Release TX buffer 9896833Sgd78059 */ 9906833Sgd78059 if (erip->tbuf_ioaddr != 0) { 9916833Sgd78059 (void) ddi_dma_unbind_handle(erip->tbuf_handle); 9926833Sgd78059 erip->tbuf_ioaddr = 0; 9936833Sgd78059 } 9946833Sgd78059 if (erip->tbuf_kaddr != NULL) { 9957394Sgdamore@opensolaris.org ddi_dma_mem_free(&erip->tbuf_acch); 9966833Sgd78059 erip->tbuf_kaddr = NULL; 9976833Sgd78059 } 9986833Sgd78059 if (erip->tbuf_handle != NULL) { 9996833Sgd78059 ddi_dma_free_handle(&erip->tbuf_handle); 10006833Sgd78059 erip->tbuf_handle = NULL; 10016833Sgd78059 } 10026833Sgd78059 10036833Sgd78059 eri_param_cleanup(erip); 10046833Sgd78059 10056833Sgd78059 ddi_set_driver_private(dip, NULL); 10066833Sgd78059 kmem_free((caddr_t)erip, sizeof (struct eri)); 10076833Sgd78059 10086833Sgd78059 return (DDI_SUCCESS); 10096833Sgd78059 } 10106833Sgd78059 10116833Sgd78059 /* 10126833Sgd78059 * To set up the mac address for the network interface: 10136833Sgd78059 * The adapter card may support a local mac address which is published 10146833Sgd78059 * in a device node property "local-mac-address". This mac address is 10156833Sgd78059 * treated as the factory-installed mac address for DLPI interface. 10166833Sgd78059 * If the adapter firmware has used the device for diskless boot 10176833Sgd78059 * operation it publishes a property called "mac-address" for use by 10186833Sgd78059 * inetboot and the device driver. 10196833Sgd78059 * If "mac-address" is not found, the system options property 10206833Sgd78059 * "local-mac-address" is used to select the mac-address. If this option 10216833Sgd78059 * is set to "true", and "local-mac-address" has been found, then 10226833Sgd78059 * local-mac-address is used; otherwise the system mac address is used 10236833Sgd78059 * by calling the "localetheraddr()" function. 10246833Sgd78059 */ 10256833Sgd78059 10266833Sgd78059 static void 10276833Sgd78059 eri_setup_mac_address(struct eri *erip, dev_info_t *dip) 10286833Sgd78059 { 10296833Sgd78059 uchar_t *prop; 10306833Sgd78059 char *uselocal; 10316833Sgd78059 unsigned prop_len; 10326833Sgd78059 uint32_t addrflags = 0; 10336833Sgd78059 struct ether_addr factaddr; 10346833Sgd78059 10356833Sgd78059 /* 10366833Sgd78059 * Check if it is an adapter with its own local mac address 10376833Sgd78059 * If it is present, save it as the "factory-address" 10386833Sgd78059 * for this adapter. 10396833Sgd78059 */ 10406833Sgd78059 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 10416833Sgd78059 "local-mac-address", &prop, &prop_len) == DDI_PROP_SUCCESS) { 10426833Sgd78059 if (prop_len == ETHERADDRL) { 10436833Sgd78059 addrflags = ERI_FACTADDR_PRESENT; 10446833Sgd78059 bcopy(prop, &factaddr, ETHERADDRL); 10456833Sgd78059 ERI_FAULT_MSG2(erip, SEVERITY_NONE, ERI_VERB_MSG, 10466833Sgd78059 lether_addr_msg, ether_sprintf(&factaddr)); 10476833Sgd78059 } 10486833Sgd78059 ddi_prop_free(prop); 10496833Sgd78059 } 10506833Sgd78059 /* 10516833Sgd78059 * Check if the adapter has published "mac-address" property. 10526833Sgd78059 * If it is present, use it as the mac address for this device. 10536833Sgd78059 */ 10546833Sgd78059 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 10556833Sgd78059 "mac-address", &prop, &prop_len) == DDI_PROP_SUCCESS) { 10566833Sgd78059 if (prop_len >= ETHERADDRL) { 10576833Sgd78059 bcopy(prop, erip->ouraddr, ETHERADDRL); 10586833Sgd78059 ddi_prop_free(prop); 10596833Sgd78059 return; 10606833Sgd78059 } 10616833Sgd78059 ddi_prop_free(prop); 10626833Sgd78059 } 10636833Sgd78059 10646833Sgd78059 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, "local-mac-address?", 10656833Sgd78059 &uselocal) == DDI_PROP_SUCCESS) { 10666833Sgd78059 if ((strcmp("true", uselocal) == 0) && 10676833Sgd78059 (addrflags & ERI_FACTADDR_PRESENT)) { 10686833Sgd78059 addrflags |= ERI_FACTADDR_USE; 10696833Sgd78059 bcopy(&factaddr, erip->ouraddr, ETHERADDRL); 10706833Sgd78059 ddi_prop_free(uselocal); 10716833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, 10726833Sgd78059 lmac_addr_msg); 10736833Sgd78059 return; 10746833Sgd78059 } 10756833Sgd78059 ddi_prop_free(uselocal); 10766833Sgd78059 } 10776833Sgd78059 10786833Sgd78059 /* 10796833Sgd78059 * Get the system ethernet address. 10806833Sgd78059 */ 10816833Sgd78059 (void) localetheraddr(NULL, &factaddr); 10826833Sgd78059 bcopy(&factaddr, erip->ouraddr, ETHERADDRL); 10836833Sgd78059 } 10846833Sgd78059 10856833Sgd78059 10866833Sgd78059 /* 10876833Sgd78059 * Calculate the bit in the multicast address filter that selects the given 10886833Sgd78059 * address. 10896833Sgd78059 * Note: For ERI, the last 8-bits are used. 10906833Sgd78059 */ 10916833Sgd78059 10926833Sgd78059 static uint32_t 10936833Sgd78059 eri_ladrf_bit(const uint8_t *addr) 10946833Sgd78059 { 10956833Sgd78059 uint32_t crc; 10966833Sgd78059 10976833Sgd78059 CRC32(crc, addr, ETHERADDRL, -1U, crc32_table); 10986833Sgd78059 10996833Sgd78059 /* 11006833Sgd78059 * Just want the 8 most significant bits. 11016833Sgd78059 */ 11026833Sgd78059 return ((~crc) >> 24); 11036833Sgd78059 } 11046833Sgd78059 11056833Sgd78059 static void 11066833Sgd78059 eri_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 11076833Sgd78059 { 11086833Sgd78059 struct eri *erip = arg; 11096833Sgd78059 struct iocblk *iocp = (void *)mp->b_rptr; 11106833Sgd78059 int err; 11116833Sgd78059 11126833Sgd78059 ASSERT(erip != NULL); 11136833Sgd78059 11146833Sgd78059 /* 11156833Sgd78059 * Privilege checks. 11166833Sgd78059 */ 11176833Sgd78059 switch (iocp->ioc_cmd) { 11186833Sgd78059 case ERI_SET_LOOP_MODE: 11196833Sgd78059 case ERI_ND_SET: 11206833Sgd78059 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 11216833Sgd78059 if (err != 0) { 11226833Sgd78059 miocnak(wq, mp, 0, err); 11236833Sgd78059 return; 11246833Sgd78059 } 11256833Sgd78059 break; 11266833Sgd78059 default: 11276833Sgd78059 break; 11286833Sgd78059 } 11296833Sgd78059 11306833Sgd78059 switch (iocp->ioc_cmd) { 11316833Sgd78059 case ERI_ND_GET: 11326833Sgd78059 case ERI_ND_SET: 11336833Sgd78059 eri_process_ndd_ioctl(erip, wq, mp, iocp->ioc_cmd); 11346833Sgd78059 break; 11356833Sgd78059 11366833Sgd78059 case ERI_SET_LOOP_MODE: 11376833Sgd78059 case ERI_GET_LOOP_MODE: 11386833Sgd78059 /* 11396833Sgd78059 * XXX: Consider updating this to the new netlb ioctls. 11406833Sgd78059 */ 11416833Sgd78059 eri_loopback(erip, wq, mp); 11426833Sgd78059 break; 11436833Sgd78059 11446833Sgd78059 default: 11456833Sgd78059 miocnak(wq, mp, 0, EINVAL); 11466833Sgd78059 break; 11476833Sgd78059 } 11486833Sgd78059 11496833Sgd78059 ASSERT(!MUTEX_HELD(&erip->linklock)); 11506833Sgd78059 } 11516833Sgd78059 11526833Sgd78059 static void 11536833Sgd78059 eri_loopback(struct eri *erip, queue_t *wq, mblk_t *mp) 11546833Sgd78059 { 11556833Sgd78059 struct iocblk *iocp = (void *)mp->b_rptr; 11566833Sgd78059 loopback_t *al; 11576833Sgd78059 11586833Sgd78059 if (mp->b_cont == NULL || MBLKL(mp->b_cont) < sizeof (loopback_t)) { 11596833Sgd78059 miocnak(wq, mp, 0, EINVAL); 11606833Sgd78059 return; 11616833Sgd78059 } 11626833Sgd78059 11636833Sgd78059 al = (void *)mp->b_cont->b_rptr; 11646833Sgd78059 11656833Sgd78059 switch (iocp->ioc_cmd) { 11666833Sgd78059 case ERI_SET_LOOP_MODE: 11676833Sgd78059 switch (al->loopback) { 11686833Sgd78059 case ERI_LOOPBACK_OFF: 11696833Sgd78059 erip->flags &= (~ERI_MACLOOPBACK & ~ERI_SERLOOPBACK); 11706833Sgd78059 /* force link status to go down */ 11716833Sgd78059 param_linkup = 0; 11726833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 11736833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 11746833Sgd78059 (void) eri_init(erip); 11756833Sgd78059 break; 11766833Sgd78059 11776833Sgd78059 case ERI_MAC_LOOPBACK_ON: 11786833Sgd78059 erip->flags |= ERI_MACLOOPBACK; 11796833Sgd78059 erip->flags &= ~ERI_SERLOOPBACK; 11806833Sgd78059 param_linkup = 0; 11816833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 11826833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 11836833Sgd78059 (void) eri_init(erip); 11846833Sgd78059 break; 11856833Sgd78059 11866833Sgd78059 case ERI_PCS_LOOPBACK_ON: 11876833Sgd78059 break; 11886833Sgd78059 11896833Sgd78059 case ERI_SER_LOOPBACK_ON: 11906833Sgd78059 erip->flags |= ERI_SERLOOPBACK; 11916833Sgd78059 erip->flags &= ~ERI_MACLOOPBACK; 11926833Sgd78059 /* force link status to go down */ 11936833Sgd78059 param_linkup = 0; 11946833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 11956833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 11966833Sgd78059 (void) eri_init(erip); 11976833Sgd78059 break; 11986833Sgd78059 11996833Sgd78059 default: 12006833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, 12016833Sgd78059 loopback_val_default); 12026833Sgd78059 miocnak(wq, mp, 0, EINVAL); 12036833Sgd78059 return; 12046833Sgd78059 } 12056833Sgd78059 miocnak(wq, mp, 0, 0); 12066833Sgd78059 break; 12076833Sgd78059 12086833Sgd78059 case ERI_GET_LOOP_MODE: 12096833Sgd78059 al->loopback = ERI_MAC_LOOPBACK_ON | ERI_PCS_LOOPBACK_ON | 12106833Sgd78059 ERI_SER_LOOPBACK_ON; 12116833Sgd78059 miocack(wq, mp, sizeof (loopback_t), 0); 12126833Sgd78059 break; 12136833Sgd78059 12146833Sgd78059 default: 12156833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG, 12166833Sgd78059 loopback_cmd_default); 12176833Sgd78059 } 12186833Sgd78059 } 12196833Sgd78059 12206833Sgd78059 static int 12216833Sgd78059 eri_m_promisc(void *arg, boolean_t on) 12226833Sgd78059 { 12236833Sgd78059 struct eri *erip = arg; 12246833Sgd78059 12256833Sgd78059 mutex_enter(&erip->intrlock); 12266833Sgd78059 erip->promisc = on; 12276833Sgd78059 eri_init_rx(erip); 12286833Sgd78059 mutex_exit(&erip->intrlock); 12296833Sgd78059 return (0); 12306833Sgd78059 } 12316833Sgd78059 12326833Sgd78059 /* 12336833Sgd78059 * This is to support unlimited number of members 12346833Sgd78059 * in Multicast. 12356833Sgd78059 */ 12366833Sgd78059 static int 12376833Sgd78059 eri_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 12386833Sgd78059 { 12396833Sgd78059 struct eri *erip = arg; 12406833Sgd78059 uint32_t ladrf_bit; 12416833Sgd78059 12426833Sgd78059 /* 12436833Sgd78059 * If this address's bit was not already set in the local address 12446833Sgd78059 * filter, add it and re-initialize the Hardware. 12456833Sgd78059 */ 12466833Sgd78059 ladrf_bit = eri_ladrf_bit(mca); 12476833Sgd78059 12486833Sgd78059 mutex_enter(&erip->intrlock); 12496833Sgd78059 if (add) { 12506833Sgd78059 erip->ladrf_refcnt[ladrf_bit]++; 12516833Sgd78059 if (erip->ladrf_refcnt[ladrf_bit] == 1) { 12526833Sgd78059 LADRF_SET(erip, ladrf_bit); 12536833Sgd78059 erip->multi_refcnt++; 12546833Sgd78059 eri_init_rx(erip); 12556833Sgd78059 } 12566833Sgd78059 } else { 12576833Sgd78059 erip->ladrf_refcnt[ladrf_bit]--; 12586833Sgd78059 if (erip->ladrf_refcnt[ladrf_bit] == 0) { 12596833Sgd78059 LADRF_CLR(erip, ladrf_bit); 12606833Sgd78059 erip->multi_refcnt--; 12616833Sgd78059 eri_init_rx(erip); 12626833Sgd78059 } 12636833Sgd78059 } 12646833Sgd78059 mutex_exit(&erip->intrlock); 12656833Sgd78059 return (0); 12666833Sgd78059 } 12676833Sgd78059 12686833Sgd78059 static int 12696833Sgd78059 eri_m_unicst(void *arg, const uint8_t *macaddr) 12706833Sgd78059 { 12716833Sgd78059 struct eri *erip = arg; 12726833Sgd78059 12736833Sgd78059 /* 12746833Sgd78059 * Set new interface local address and re-init device. 12756833Sgd78059 * This is destructive to any other streams attached 12766833Sgd78059 * to this device. 12776833Sgd78059 */ 12786833Sgd78059 mutex_enter(&erip->intrlock); 12796833Sgd78059 bcopy(macaddr, &erip->ouraddr, ETHERADDRL); 12806833Sgd78059 eri_init_rx(erip); 12816833Sgd78059 mutex_exit(&erip->intrlock); 12826833Sgd78059 return (0); 12836833Sgd78059 } 12846833Sgd78059 12856833Sgd78059 /*ARGSUSED*/ 12866833Sgd78059 static boolean_t 12876833Sgd78059 eri_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 12886833Sgd78059 { 12896833Sgd78059 switch (cap) { 12906833Sgd78059 case MAC_CAPAB_HCKSUM: { 12916833Sgd78059 uint32_t *hcksum_txflags = cap_data; 12926833Sgd78059 *hcksum_txflags = HCKSUM_INET_PARTIAL; 12936833Sgd78059 return (B_TRUE); 12946833Sgd78059 } 12956833Sgd78059 default: 12966833Sgd78059 return (B_FALSE); 12976833Sgd78059 } 12986833Sgd78059 } 12996833Sgd78059 13006833Sgd78059 static int 13016833Sgd78059 eri_m_start(void *arg) 13026833Sgd78059 { 13036833Sgd78059 struct eri *erip = arg; 13046833Sgd78059 13056833Sgd78059 mutex_enter(&erip->intrlock); 13066833Sgd78059 erip->flags |= ERI_STARTED; 13076833Sgd78059 mutex_exit(&erip->intrlock); 13086833Sgd78059 13096833Sgd78059 if (!eri_init(erip)) { 13106833Sgd78059 mutex_enter(&erip->intrlock); 13116833Sgd78059 erip->flags &= ~ERI_STARTED; 13126833Sgd78059 mutex_exit(&erip->intrlock); 13136833Sgd78059 return (EIO); 13146833Sgd78059 } 13156833Sgd78059 return (0); 13166833Sgd78059 } 13176833Sgd78059 13186833Sgd78059 static void 13196833Sgd78059 eri_m_stop(void *arg) 13206833Sgd78059 { 13216833Sgd78059 struct eri *erip = arg; 13226833Sgd78059 13236833Sgd78059 mutex_enter(&erip->intrlock); 13246833Sgd78059 erip->flags &= ~ERI_STARTED; 13256833Sgd78059 mutex_exit(&erip->intrlock); 13266833Sgd78059 eri_uninit(erip); 13276833Sgd78059 } 13286833Sgd78059 13296833Sgd78059 static int 13306833Sgd78059 eri_m_stat(void *arg, uint_t stat, uint64_t *val) 13316833Sgd78059 { 13326833Sgd78059 struct eri *erip = arg; 13336833Sgd78059 struct stats *esp; 13346833Sgd78059 boolean_t macupdate = B_FALSE; 13356833Sgd78059 13366833Sgd78059 esp = &erip->stats; 13376833Sgd78059 13386833Sgd78059 mutex_enter(&erip->xmitlock); 13396833Sgd78059 if ((erip->flags & ERI_RUNNING) && (erip->flags & ERI_TXINIT)) { 13406833Sgd78059 erip->tx_completion = 13416833Sgd78059 GET_ETXREG(tx_completion) & ETX_COMPLETION_MASK; 13426833Sgd78059 macupdate |= eri_reclaim(erip, erip->tx_completion); 13436833Sgd78059 } 13446833Sgd78059 mutex_exit(&erip->xmitlock); 13456833Sgd78059 if (macupdate) 13466833Sgd78059 mac_tx_update(erip->mh); 13476833Sgd78059 13486833Sgd78059 eri_savecntrs(erip); 13496833Sgd78059 13506833Sgd78059 switch (stat) { 13516833Sgd78059 case MAC_STAT_IFSPEED: 13526833Sgd78059 *val = esp->ifspeed * 1000000ULL; 13536833Sgd78059 break; 13546833Sgd78059 case MAC_STAT_MULTIRCV: 13556833Sgd78059 *val = esp->multircv; 13566833Sgd78059 break; 13576833Sgd78059 case MAC_STAT_BRDCSTRCV: 13586833Sgd78059 *val = esp->brdcstrcv; 13596833Sgd78059 break; 13606833Sgd78059 case MAC_STAT_IPACKETS: 13616833Sgd78059 *val = esp->ipackets64; 13626833Sgd78059 break; 13636833Sgd78059 case MAC_STAT_RBYTES: 13646833Sgd78059 *val = esp->rbytes64; 13656833Sgd78059 break; 13666833Sgd78059 case MAC_STAT_OBYTES: 13676833Sgd78059 *val = esp->obytes64; 13686833Sgd78059 break; 13696833Sgd78059 case MAC_STAT_OPACKETS: 13706833Sgd78059 *val = esp->opackets64; 13716833Sgd78059 break; 13726833Sgd78059 case MAC_STAT_IERRORS: 13736833Sgd78059 *val = esp->ierrors; 13746833Sgd78059 break; 13756833Sgd78059 case MAC_STAT_OERRORS: 13766833Sgd78059 *val = esp->oerrors; 13776833Sgd78059 break; 13786833Sgd78059 case MAC_STAT_MULTIXMT: 13796833Sgd78059 *val = esp->multixmt; 13806833Sgd78059 break; 13816833Sgd78059 case MAC_STAT_BRDCSTXMT: 13826833Sgd78059 *val = esp->brdcstxmt; 13836833Sgd78059 break; 13846833Sgd78059 case MAC_STAT_NORCVBUF: 13856833Sgd78059 *val = esp->norcvbuf; 13866833Sgd78059 break; 13876833Sgd78059 case MAC_STAT_NOXMTBUF: 13886833Sgd78059 *val = esp->noxmtbuf; 13896833Sgd78059 break; 13906833Sgd78059 case MAC_STAT_UNDERFLOWS: 13916833Sgd78059 *val = esp->txmac_urun; 13926833Sgd78059 break; 13936833Sgd78059 case MAC_STAT_OVERFLOWS: 13946833Sgd78059 *val = esp->rx_overflow; 13956833Sgd78059 break; 13966833Sgd78059 case MAC_STAT_COLLISIONS: 13976833Sgd78059 *val = esp->collisions; 13986833Sgd78059 break; 13996833Sgd78059 case ETHER_STAT_ALIGN_ERRORS: 14006833Sgd78059 *val = esp->rx_align_err; 14016833Sgd78059 break; 14026833Sgd78059 case ETHER_STAT_FCS_ERRORS: 14036833Sgd78059 *val = esp->rx_crc_err; 14046833Sgd78059 break; 14056833Sgd78059 case ETHER_STAT_EX_COLLISIONS: 14066833Sgd78059 *val = esp->excessive_coll; 14076833Sgd78059 break; 14086833Sgd78059 case ETHER_STAT_TX_LATE_COLLISIONS: 14096833Sgd78059 *val = esp->late_coll; 14106833Sgd78059 break; 14116833Sgd78059 case ETHER_STAT_FIRST_COLLISIONS: 14126833Sgd78059 *val = esp->first_coll; 14136833Sgd78059 break; 14146833Sgd78059 case ETHER_STAT_LINK_DUPLEX: 14156833Sgd78059 *val = esp->link_duplex; 14166833Sgd78059 break; 14176833Sgd78059 case ETHER_STAT_TOOLONG_ERRORS: 14186833Sgd78059 *val = esp->rx_toolong_pkts; 14196833Sgd78059 break; 14206833Sgd78059 case ETHER_STAT_TOOSHORT_ERRORS: 14216833Sgd78059 *val = esp->rx_runt; 14226833Sgd78059 break; 14236833Sgd78059 14246833Sgd78059 case ETHER_STAT_XCVR_ADDR: 14256833Sgd78059 *val = erip->phyad; 14266833Sgd78059 break; 14276833Sgd78059 14286833Sgd78059 case ETHER_STAT_XCVR_INUSE: 14296833Sgd78059 *val = XCVR_100X; /* should always be 100X for now */ 14306833Sgd78059 break; 14316833Sgd78059 14326833Sgd78059 case ETHER_STAT_CAP_100FDX: 14336833Sgd78059 *val = param_bmsr_100fdx; 14346833Sgd78059 break; 14356833Sgd78059 case ETHER_STAT_CAP_100HDX: 14366833Sgd78059 *val = param_bmsr_100hdx; 14376833Sgd78059 break; 14386833Sgd78059 case ETHER_STAT_CAP_10FDX: 14396833Sgd78059 *val = param_bmsr_10fdx; 14406833Sgd78059 break; 14416833Sgd78059 case ETHER_STAT_CAP_10HDX: 14426833Sgd78059 *val = param_bmsr_10hdx; 14436833Sgd78059 break; 14446833Sgd78059 case ETHER_STAT_CAP_AUTONEG: 14456833Sgd78059 *val = param_bmsr_ancap; 14466833Sgd78059 break; 14476833Sgd78059 case ETHER_STAT_CAP_ASMPAUSE: 14486833Sgd78059 *val = param_bmsr_asm_dir; 14496833Sgd78059 break; 14506833Sgd78059 case ETHER_STAT_CAP_PAUSE: 14516833Sgd78059 *val = param_bmsr_pause; 14526833Sgd78059 break; 14536833Sgd78059 case ETHER_STAT_ADV_CAP_100FDX: 14546833Sgd78059 *val = param_anar_100fdx; 14556833Sgd78059 break; 14566833Sgd78059 case ETHER_STAT_ADV_CAP_100HDX: 14576833Sgd78059 *val = param_anar_100hdx; 14586833Sgd78059 break; 14596833Sgd78059 case ETHER_STAT_ADV_CAP_10FDX: 14606833Sgd78059 *val = param_anar_10fdx; 14616833Sgd78059 break; 14626833Sgd78059 case ETHER_STAT_ADV_CAP_10HDX: 14636833Sgd78059 *val = param_anar_10hdx; 14646833Sgd78059 break; 14656833Sgd78059 case ETHER_STAT_ADV_CAP_AUTONEG: 14666833Sgd78059 *val = param_autoneg; 14676833Sgd78059 break; 14686833Sgd78059 case ETHER_STAT_ADV_CAP_ASMPAUSE: 14696833Sgd78059 *val = param_anar_asm_dir; 14706833Sgd78059 break; 14716833Sgd78059 case ETHER_STAT_ADV_CAP_PAUSE: 14726833Sgd78059 *val = param_anar_pause; 14736833Sgd78059 break; 14746833Sgd78059 case ETHER_STAT_LP_CAP_100FDX: 14756833Sgd78059 *val = param_anlpar_100fdx; 14766833Sgd78059 break; 14776833Sgd78059 case ETHER_STAT_LP_CAP_100HDX: 14786833Sgd78059 *val = param_anlpar_100hdx; 14796833Sgd78059 break; 14806833Sgd78059 case ETHER_STAT_LP_CAP_10FDX: 14816833Sgd78059 *val = param_anlpar_10fdx; 14826833Sgd78059 break; 14836833Sgd78059 case ETHER_STAT_LP_CAP_10HDX: 14846833Sgd78059 *val = param_anlpar_10hdx; 14856833Sgd78059 break; 14866833Sgd78059 case ETHER_STAT_LP_CAP_AUTONEG: 14876833Sgd78059 *val = param_aner_lpancap; 14886833Sgd78059 break; 14896833Sgd78059 case ETHER_STAT_LP_CAP_ASMPAUSE: 14906833Sgd78059 *val = param_anlpar_pauseTX; 14916833Sgd78059 break; 14926833Sgd78059 case ETHER_STAT_LP_CAP_PAUSE: 14936833Sgd78059 *val = param_anlpar_pauseRX; 14946833Sgd78059 break; 14956833Sgd78059 case ETHER_STAT_LINK_PAUSE: 14966833Sgd78059 *val = esp->pausing; 14976833Sgd78059 break; 14986833Sgd78059 case ETHER_STAT_LINK_ASMPAUSE: 14996833Sgd78059 *val = param_anar_asm_dir && 15006833Sgd78059 param_anlpar_pauseTX && 15016833Sgd78059 (param_anar_pause != param_anlpar_pauseRX); 15026833Sgd78059 break; 15036833Sgd78059 case ETHER_STAT_LINK_AUTONEG: 15046833Sgd78059 *val = param_autoneg && param_aner_lpancap; 15056833Sgd78059 break; 15066833Sgd78059 } 15076833Sgd78059 return (0); 15086833Sgd78059 } 15096833Sgd78059 15106833Sgd78059 /* 15116833Sgd78059 * Hardware Functions 15126833Sgd78059 * New Section 15136833Sgd78059 */ 15146833Sgd78059 15156833Sgd78059 /* 15166833Sgd78059 * Initialize the MAC registers. Some of of the MAC registers are initialized 15176833Sgd78059 * just once since Global Reset or MAC reset doesn't clear them. Others (like 15186833Sgd78059 * Host MAC Address Registers) are cleared on every reset and have to be 15196833Sgd78059 * reinitialized. 15206833Sgd78059 */ 15216833Sgd78059 static void 15226833Sgd78059 eri_init_macregs_generic(struct eri *erip) 15236833Sgd78059 { 15246833Sgd78059 /* 15256833Sgd78059 * set up the MAC parameter registers once 15266833Sgd78059 * after power cycle. SUSPEND/RESUME also requires 15276833Sgd78059 * setting these registers. 15286833Sgd78059 */ 15296833Sgd78059 if ((erip->stats.inits == 1) || (erip->init_macregs)) { 15306833Sgd78059 erip->init_macregs = 0; 15316833Sgd78059 PUT_MACREG(ipg0, param_ipg0); 15326833Sgd78059 PUT_MACREG(ipg1, param_ipg1); 15336833Sgd78059 PUT_MACREG(ipg2, param_ipg2); 15346833Sgd78059 PUT_MACREG(macmin, BMAC_MIN_FRAME_SIZE); 15356833Sgd78059 #ifdef ERI_RX_TAG_ERROR_WORKAROUND 15366833Sgd78059 PUT_MACREG(macmax, BMAC_MAX_FRAME_SIZE_TAG | BMAC_MAX_BURST); 15376833Sgd78059 #else 15386833Sgd78059 PUT_MACREG(macmax, BMAC_MAX_FRAME_SIZE | BMAC_MAX_BURST); 15396833Sgd78059 #endif 15406833Sgd78059 PUT_MACREG(palen, BMAC_PREAMBLE_SIZE); 15416833Sgd78059 PUT_MACREG(jam, BMAC_JAM_SIZE); 15426833Sgd78059 PUT_MACREG(alimit, BMAC_ATTEMPT_LIMIT); 15436833Sgd78059 PUT_MACREG(macctl_type, BMAC_CONTROL_TYPE); 15446833Sgd78059 PUT_MACREG(rseed, 15456833Sgd78059 ((erip->ouraddr[0] & 0x3) << 8) | erip->ouraddr[1]); 15466833Sgd78059 15476833Sgd78059 PUT_MACREG(madd3, BMAC_ADDRESS_3); 15486833Sgd78059 PUT_MACREG(madd4, BMAC_ADDRESS_4); 15496833Sgd78059 PUT_MACREG(madd5, BMAC_ADDRESS_5); 15506833Sgd78059 15516833Sgd78059 /* Program MAC Control address */ 15526833Sgd78059 PUT_MACREG(madd6, BMAC_ADDRESS_6); 15536833Sgd78059 PUT_MACREG(madd7, BMAC_ADDRESS_7); 15546833Sgd78059 PUT_MACREG(madd8, BMAC_ADDRESS_8); 15556833Sgd78059 15566833Sgd78059 PUT_MACREG(afr0, BMAC_AF_0); 15576833Sgd78059 PUT_MACREG(afr1, BMAC_AF_1); 15586833Sgd78059 PUT_MACREG(afr2, BMAC_AF_2); 15596833Sgd78059 PUT_MACREG(afmr1_2, BMAC_AF21_MASK); 15606833Sgd78059 PUT_MACREG(afmr0, BMAC_AF0_MASK); 15616833Sgd78059 } 15626833Sgd78059 15636833Sgd78059 /* The counters need to be zeroed */ 15646833Sgd78059 PUT_MACREG(nccnt, 0); 15656833Sgd78059 PUT_MACREG(fccnt, 0); 15666833Sgd78059 PUT_MACREG(excnt, 0); 15676833Sgd78059 PUT_MACREG(ltcnt, 0); 15686833Sgd78059 PUT_MACREG(dcnt, 0); 15696833Sgd78059 PUT_MACREG(frcnt, 0); 15706833Sgd78059 PUT_MACREG(lecnt, 0); 15716833Sgd78059 PUT_MACREG(aecnt, 0); 15726833Sgd78059 PUT_MACREG(fecnt, 0); 15736833Sgd78059 PUT_MACREG(rxcv, 0); 15746833Sgd78059 15756833Sgd78059 if (erip->pauseTX) 15766833Sgd78059 PUT_MACREG(spcmd, BMAC_SEND_PAUSE_CMD); 15776833Sgd78059 else 15786833Sgd78059 PUT_MACREG(spcmd, 0); 15796833Sgd78059 15806833Sgd78059 /* 15816833Sgd78059 * Program BigMAC with local individual ethernet address. 15826833Sgd78059 */ 15836833Sgd78059 15846833Sgd78059 PUT_MACREG(madd0, (erip->ouraddr[4] << 8) | erip->ouraddr[5]); 15856833Sgd78059 PUT_MACREG(madd1, (erip->ouraddr[2] << 8) | erip->ouraddr[3]); 15866833Sgd78059 PUT_MACREG(madd2, (erip->ouraddr[0] << 8) | erip->ouraddr[1]); 15876833Sgd78059 15886833Sgd78059 /* 15896833Sgd78059 * Install multicast address filter. 15906833Sgd78059 */ 15916833Sgd78059 15926833Sgd78059 PUT_MACREG(hash0, erip->ladrf[0]); 15936833Sgd78059 PUT_MACREG(hash1, erip->ladrf[1]); 15946833Sgd78059 PUT_MACREG(hash2, erip->ladrf[2]); 15956833Sgd78059 PUT_MACREG(hash3, erip->ladrf[3]); 15966833Sgd78059 PUT_MACREG(hash4, erip->ladrf[4]); 15976833Sgd78059 PUT_MACREG(hash5, erip->ladrf[5]); 15986833Sgd78059 PUT_MACREG(hash6, erip->ladrf[6]); 15996833Sgd78059 PUT_MACREG(hash7, erip->ladrf[7]); 16006833Sgd78059 PUT_MACREG(hash8, erip->ladrf[8]); 16016833Sgd78059 PUT_MACREG(hash9, erip->ladrf[9]); 16026833Sgd78059 PUT_MACREG(hash10, erip->ladrf[10]); 16036833Sgd78059 PUT_MACREG(hash11, erip->ladrf[11]); 16046833Sgd78059 PUT_MACREG(hash12, erip->ladrf[12]); 16056833Sgd78059 PUT_MACREG(hash13, erip->ladrf[13]); 16066833Sgd78059 PUT_MACREG(hash14, erip->ladrf[14]); 16076833Sgd78059 } 16086833Sgd78059 16096833Sgd78059 static int 16106833Sgd78059 eri_flush_rxbufs(struct eri *erip) 16116833Sgd78059 { 16126833Sgd78059 uint_t i; 16136833Sgd78059 int status = 0; 16146833Sgd78059 /* 16156833Sgd78059 * Free and dvma_unload pending recv buffers. 16166833Sgd78059 * Maintaining the 1-to-1 ordered sequence of 16176833Sgd78059 * dvma_load() followed by dvma_unload() is critical. 16186833Sgd78059 * Always unload anything before loading it again. 16196833Sgd78059 * Never unload anything twice. Always unload 16206833Sgd78059 * before freeing the buffer. We satisfy these 16216833Sgd78059 * requirements by unloading only those descriptors 16226833Sgd78059 * which currently have an mblk associated with them. 16236833Sgd78059 */ 16246833Sgd78059 for (i = 0; i < ERI_RPENDING; i++) { 16256833Sgd78059 if (erip->rmblkp[i]) { 16266833Sgd78059 if (erip->eri_dvmarh) 16276833Sgd78059 dvma_unload(erip->eri_dvmarh, 2 * i, 16286833Sgd78059 DDI_DMA_SYNC_FORCPU); 16296833Sgd78059 else if ((ddi_dma_unbind_handle(erip->ndmarh[i]) == 16306833Sgd78059 DDI_FAILURE)) 16316833Sgd78059 status = -1; 16326833Sgd78059 freeb(erip->rmblkp[i]); 16336833Sgd78059 erip->rmblkp[i] = NULL; 16346833Sgd78059 } 16356833Sgd78059 } 16366833Sgd78059 return (status); 16376833Sgd78059 } 16386833Sgd78059 16396833Sgd78059 static void 16406833Sgd78059 eri_init_txbufs(struct eri *erip) 16416833Sgd78059 { 16426833Sgd78059 /* 16436833Sgd78059 * Clear TX descriptors. 16446833Sgd78059 */ 16456833Sgd78059 bzero((caddr_t)erip->eri_tmdp, ERI_TPENDING * sizeof (struct eri_tmd)); 16466833Sgd78059 16476833Sgd78059 /* 16486833Sgd78059 * sync TXDMA descriptors. 16496833Sgd78059 */ 16506833Sgd78059 ERI_SYNCIOPB(erip, erip->eri_tmdp, 16516833Sgd78059 (ERI_TPENDING * sizeof (struct eri_tmd)), DDI_DMA_SYNC_FORDEV); 16526833Sgd78059 /* 16536833Sgd78059 * Reset TMD 'walking' pointers. 16546833Sgd78059 */ 16556833Sgd78059 erip->tcurp = erip->eri_tmdp; 16566833Sgd78059 erip->tnextp = erip->eri_tmdp; 16576833Sgd78059 erip->tx_cur_cnt = 0; 16586833Sgd78059 erip->tx_kick = 0; 16596833Sgd78059 erip->tx_completion = 0; 16606833Sgd78059 } 16616833Sgd78059 16626833Sgd78059 static int 16636833Sgd78059 eri_init_rxbufs(struct eri *erip) 16646833Sgd78059 { 16656833Sgd78059 16666833Sgd78059 ddi_dma_cookie_t dma_cookie; 16676833Sgd78059 mblk_t *bp; 16686833Sgd78059 int i, status = 0; 16696833Sgd78059 uint32_t ccnt; 16706833Sgd78059 16716833Sgd78059 /* 16726833Sgd78059 * clear rcv descriptors 16736833Sgd78059 */ 16746833Sgd78059 bzero((caddr_t)erip->rmdp, ERI_RPENDING * sizeof (struct rmd)); 16756833Sgd78059 16766833Sgd78059 for (i = 0; i < ERI_RPENDING; i++) { 16776833Sgd78059 if ((bp = eri_allocb(ERI_BUFSIZE)) == NULL) { 16786833Sgd78059 status = -1; 16796833Sgd78059 continue; 16806833Sgd78059 } 16816833Sgd78059 /* Load data buffer to DVMA space */ 16826833Sgd78059 if (erip->eri_dvmarh) 16836833Sgd78059 dvma_kaddr_load(erip->eri_dvmarh, 16846833Sgd78059 (caddr_t)bp->b_rptr, ERI_BUFSIZE, 16856833Sgd78059 2 * i, &dma_cookie); 16866833Sgd78059 /* 16876833Sgd78059 * Bind data buffer to DMA handle 16886833Sgd78059 */ 16896833Sgd78059 else if (ddi_dma_addr_bind_handle(erip->ndmarh[i], NULL, 16906833Sgd78059 (caddr_t)bp->b_rptr, ERI_BUFSIZE, 16916833Sgd78059 DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0, 16926833Sgd78059 &dma_cookie, &ccnt) != DDI_DMA_MAPPED) 16936833Sgd78059 status = -1; 16946833Sgd78059 16956833Sgd78059 PUT_RMD((&erip->rmdp[i]), dma_cookie); 16966833Sgd78059 erip->rmblkp[i] = bp; /* save for later use */ 16976833Sgd78059 } 16986833Sgd78059 16996833Sgd78059 /* 17006833Sgd78059 * sync RXDMA descriptors. 17016833Sgd78059 */ 17026833Sgd78059 ERI_SYNCIOPB(erip, erip->rmdp, (ERI_RPENDING * sizeof (struct rmd)), 17036833Sgd78059 DDI_DMA_SYNC_FORDEV); 17046833Sgd78059 /* 17056833Sgd78059 * Reset RMD 'walking' pointers. 17066833Sgd78059 */ 17076833Sgd78059 erip->rnextp = erip->rmdp; 17086833Sgd78059 erip->rx_completion = 0; 17096833Sgd78059 erip->rx_kick = ERI_RPENDING - 4; 17106833Sgd78059 return (status); 17116833Sgd78059 } 17126833Sgd78059 17136833Sgd78059 static uint32_t 17146833Sgd78059 eri_txmac_disable(struct eri *erip) 17156833Sgd78059 { 17166833Sgd78059 int n; 17176833Sgd78059 17186833Sgd78059 PUT_MACREG(txcfg, GET_MACREG(txcfg) & ~BMAC_TXCFG_ENAB); 17196833Sgd78059 n = (BMACTXRSTDELAY * 10) / ERI_WAITPERIOD; 17206833Sgd78059 17216833Sgd78059 while (--n > 0) { 17226833Sgd78059 drv_usecwait(ERI_WAITPERIOD); 17236833Sgd78059 if ((GET_MACREG(txcfg) & 1) == 0) 17246833Sgd78059 return (0); 17256833Sgd78059 } 17266833Sgd78059 return (1); 17276833Sgd78059 } 17286833Sgd78059 17296833Sgd78059 static uint32_t 17306833Sgd78059 eri_rxmac_disable(struct eri *erip) 17316833Sgd78059 { 17326833Sgd78059 int n; 17336833Sgd78059 PUT_MACREG(rxcfg, GET_MACREG(rxcfg) & ~BMAC_RXCFG_ENAB); 17346833Sgd78059 n = BMACRXRSTDELAY / ERI_WAITPERIOD; 17356833Sgd78059 17366833Sgd78059 while (--n > 0) { 17376833Sgd78059 drv_usecwait(ERI_WAITPERIOD); 17386833Sgd78059 if ((GET_MACREG(rxcfg) & 1) == 0) 17396833Sgd78059 return (0); 17406833Sgd78059 } 17416833Sgd78059 return (1); 17426833Sgd78059 } 17436833Sgd78059 17446833Sgd78059 /* 17456833Sgd78059 * Return 0 upon success, 1 on failure. 17466833Sgd78059 */ 17476833Sgd78059 static int 17486833Sgd78059 eri_stop(struct eri *erip) 17496833Sgd78059 { 17506833Sgd78059 (void) eri_erx_reset(erip); 17516833Sgd78059 (void) eri_etx_reset(erip); 17526833Sgd78059 17536833Sgd78059 /* 17546833Sgd78059 * set up cache line to 16 for 64 bytes of pci burst size 17556833Sgd78059 */ 17566833Sgd78059 PUT_SWRSTREG(reset, ERI_G_RESET_GLOBAL | ERI_CACHE_LINE_SIZE); 17576833Sgd78059 17586833Sgd78059 if (erip->linkcheck) { 17596833Sgd78059 erip->linkcheck = 0; 17606833Sgd78059 erip->global_reset_issued = 2; 17616833Sgd78059 } else { 17626833Sgd78059 param_linkup = 0; 17636833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 17646833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 17656833Sgd78059 erip->global_reset_issued = -1; 17666833Sgd78059 } 17676833Sgd78059 17686833Sgd78059 ERI_DELAY((GET_SWRSTREG(reset) == ERI_CACHE_LINE_SIZE), 17696833Sgd78059 ERI_MAX_RST_DELAY); 17706833Sgd78059 erip->rx_reset_issued = -1; 17716833Sgd78059 erip->tx_reset_issued = -1; 17726833Sgd78059 17736833Sgd78059 /* 17746833Sgd78059 * workaround for RIO not resetting the interrupt mask 17756833Sgd78059 * register to default value 0xffffffff. 17766833Sgd78059 */ 17776833Sgd78059 PUT_GLOBREG(intmask, ERI_G_MASK_ALL); 17786833Sgd78059 17796833Sgd78059 if (GET_SWRSTREG(reset) == ERI_CACHE_LINE_SIZE) { 17806833Sgd78059 return (0); 17816833Sgd78059 } else { 17826833Sgd78059 return (1); 17836833Sgd78059 } 17846833Sgd78059 } 17856833Sgd78059 17866833Sgd78059 /* 17876833Sgd78059 * Reset Just the RX Portion 17886833Sgd78059 * Return 0 upon success, 1 on failure. 17896833Sgd78059 * 17906833Sgd78059 * Resetting the rxdma while there is a rx dma transaction going on the 17916833Sgd78059 * bus, will cause bus hang or parity errors. To avoid this, we would first 17926833Sgd78059 * disable the rxdma by clearing the ENABLE bit (bit 0). To make sure it is 17936833Sgd78059 * disabled, we will poll it until it realy clears. Furthermore, to verify 17946833Sgd78059 * any RX DMA activity is subsided, we delay for 5 msec. 17956833Sgd78059 */ 17966833Sgd78059 static uint32_t 17976833Sgd78059 eri_erx_reset(struct eri *erip) 17986833Sgd78059 { 17996833Sgd78059 (void) eri_rxmac_disable(erip); /* Disable the RX MAC */ 18006833Sgd78059 18016833Sgd78059 /* Disable the RX DMA */ 18026833Sgd78059 PUT_ERXREG(config, GET_ERXREG(config) & ~GET_CONFIG_RXDMA_EN); 18036833Sgd78059 ERI_DELAY(((GET_ERXREG(config) & 1) == 0), ERI_MAX_RST_DELAY); 18046833Sgd78059 if ((GET_ERXREG(config) & 1) != 0) 18056833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG, 18066833Sgd78059 disable_erx_msg); 18076833Sgd78059 18086833Sgd78059 drv_usecwait(5000); /* Delay to insure no RX DMA activity */ 18096833Sgd78059 18106833Sgd78059 PUT_SWRSTREG(reset, ERI_G_RESET_ERX | ERI_CACHE_LINE_SIZE); 18116833Sgd78059 /* 18126833Sgd78059 * Wait until the reset is completed which is indicated by 18136833Sgd78059 * the reset bit cleared or time out.. 18146833Sgd78059 */ 18156833Sgd78059 ERI_DELAY(((GET_SWRSTREG(reset) & (ERI_G_RESET_ERX)) == 18166833Sgd78059 ERI_CACHE_LINE_SIZE), ERI_MAX_RST_DELAY); 18176833Sgd78059 erip->rx_reset_issued = -1; 18186833Sgd78059 18196833Sgd78059 return ((GET_SWRSTREG(reset) & (ERI_G_RESET_ERX)) ? 1 : 0); 18206833Sgd78059 } 18216833Sgd78059 18226833Sgd78059 /* 18236833Sgd78059 * Reset Just the TX Portion 18246833Sgd78059 * Return 0 upon success, 1 on failure. 18256833Sgd78059 * Resetting the txdma while there is a tx dma transaction on the bus, may cause 18266833Sgd78059 * bus hang or parity errors. To avoid this we would first disable the txdma by 18276833Sgd78059 * clearing the ENABLE bit (bit 0). To make sure it is disabled, we will poll 18286833Sgd78059 * it until it realy clears. Furthermore, to any TX DMA activity is subsided, 18296833Sgd78059 * we delay for 1 msec. 18306833Sgd78059 */ 18316833Sgd78059 static uint32_t 18326833Sgd78059 eri_etx_reset(struct eri *erip) 18336833Sgd78059 { 18346833Sgd78059 (void) eri_txmac_disable(erip); 18356833Sgd78059 18366833Sgd78059 /* Disable the TX DMA */ 18376833Sgd78059 PUT_ETXREG(config, GET_ETXREG(config) & ~GET_CONFIG_TXDMA_EN); 18386833Sgd78059 #ifdef ORIG 18396833Sgd78059 ERI_DELAY(((GET_ETXREG(config) & 1) == 0), ERI_MAX_RST_DELAY); 18406833Sgd78059 if ((GET_ETXREG(config) & 1) != 0) 18416833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG, 18426833Sgd78059 disable_etx_msg); 18436833Sgd78059 drv_usecwait(5000); /* Delay to ensure DMA completed (if any). */ 18446833Sgd78059 #endif 18456833Sgd78059 drv_usecwait(5000); /* Delay to ensure DMA completed (if any). */ 18466833Sgd78059 ERI_DELAY(((GET_ETXREG(config) & 1) == 0), ERI_MAX_RST_DELAY); 18476833Sgd78059 if ((GET_ETXREG(config) & 1) != 0) 18486833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG, 18496833Sgd78059 disable_etx_msg); 18506833Sgd78059 18516833Sgd78059 PUT_SWRSTREG(reset, ERI_G_RESET_ETX | ERI_CACHE_LINE_SIZE); 18526833Sgd78059 18536833Sgd78059 /* 18546833Sgd78059 * Wait until the reset is completed which is indicated by the reset bit 18556833Sgd78059 * cleared or time out.. 18566833Sgd78059 */ 18576833Sgd78059 ERI_DELAY(((GET_SWRSTREG(reset) & (ERI_G_RESET_ETX)) == 18586833Sgd78059 ERI_CACHE_LINE_SIZE), ERI_MAX_RST_DELAY); 18596833Sgd78059 erip->tx_reset_issued = -1; 18606833Sgd78059 18616833Sgd78059 if (GET_SWRSTREG(reset) & (ERI_G_RESET_ETX)) { 18626833Sgd78059 return (1); 18636833Sgd78059 } else 18646833Sgd78059 return (0); 18656833Sgd78059 } 18666833Sgd78059 18676833Sgd78059 18686833Sgd78059 /* 18696833Sgd78059 * Initialize the TX DMA registers and Enable the TX DMA. 18706833Sgd78059 */ 18716833Sgd78059 static uint32_t 18726833Sgd78059 eri_init_txregs(struct eri *erip) 18736833Sgd78059 { 18746833Sgd78059 18756833Sgd78059 uint32_t i; 18766833Sgd78059 uint64_t tx_ring; 18776833Sgd78059 18786833Sgd78059 /* 18796833Sgd78059 * Initialize ETX Registers: 18806833Sgd78059 * config, txring_lo, txring_hi 18816833Sgd78059 */ 18826833Sgd78059 tx_ring = ERI_IOPBIOADDR(erip, erip->eri_tmdp); 18836833Sgd78059 PUT_ETXREG(txring_lo, (uint32_t)(tx_ring)); 18846833Sgd78059 PUT_ETXREG(txring_hi, (uint32_t)(tx_ring >> 32)); 18856833Sgd78059 18866833Sgd78059 /* 18876833Sgd78059 * Get TX Ring Size Masks. 18886833Sgd78059 * The ring size ERI_TPENDING is defined in eri_mac.h. 18896833Sgd78059 */ 18906833Sgd78059 switch (ERI_TPENDING) { 18916833Sgd78059 case 32: i = ETX_RINGSZ_32; 18926833Sgd78059 break; 18936833Sgd78059 case 64: i = ETX_RINGSZ_64; 18946833Sgd78059 break; 18956833Sgd78059 case 128: i = ETX_RINGSZ_128; 18966833Sgd78059 break; 18976833Sgd78059 case 256: i = ETX_RINGSZ_256; 18986833Sgd78059 break; 18996833Sgd78059 case 512: i = ETX_RINGSZ_512; 19006833Sgd78059 break; 19016833Sgd78059 case 1024: i = ETX_RINGSZ_1024; 19026833Sgd78059 break; 19036833Sgd78059 case 2048: i = ETX_RINGSZ_2048; 19046833Sgd78059 break; 19056833Sgd78059 case 4096: i = ETX_RINGSZ_4096; 19066833Sgd78059 break; 19076833Sgd78059 default: 19086833Sgd78059 ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG, 19096833Sgd78059 unk_tx_descr_sze_msg, ERI_TPENDING); 19106833Sgd78059 return (1); 19116833Sgd78059 } 19126833Sgd78059 19136833Sgd78059 i <<= ERI_TX_RINGSZ_SHIFT; 19146833Sgd78059 PUT_ETXREG(config, ETX_CONFIG_THRESHOLD | i); 19156833Sgd78059 ENABLE_TXDMA(erip); 19166833Sgd78059 ENABLE_MAC(erip); 19176833Sgd78059 return (0); 19186833Sgd78059 } 19196833Sgd78059 19206833Sgd78059 19216833Sgd78059 /* 19226833Sgd78059 * Initialize the RX DMA registers and Enable the RX DMA. 19236833Sgd78059 */ 19246833Sgd78059 static uint32_t 19256833Sgd78059 eri_init_rxregs(struct eri *erip) 19266833Sgd78059 { 19276833Sgd78059 int i; 19286833Sgd78059 uint64_t rx_ring; 19296833Sgd78059 19306833Sgd78059 /* 19316833Sgd78059 * Initialize ERX Registers: 19326833Sgd78059 * rxring_lo, rxring_hi, config, rx_blanking, rx_pause_threshold. 19336833Sgd78059 * Also, rx_kick 19346833Sgd78059 * Read and save rxfifo_size. 19356833Sgd78059 * XXX: Use this to properly configure PAUSE threshold values. 19366833Sgd78059 */ 19376833Sgd78059 rx_ring = ERI_IOPBIOADDR(erip, erip->rmdp); 19386833Sgd78059 PUT_ERXREG(rxring_lo, (uint32_t)(rx_ring)); 19396833Sgd78059 PUT_ERXREG(rxring_hi, (uint32_t)(rx_ring >> 32)); 19406833Sgd78059 PUT_ERXREG(rx_kick, erip->rx_kick); 19416833Sgd78059 19426833Sgd78059 /* 19436833Sgd78059 * The Max ring size, ERI_RMDMAX is defined in eri_mac.h. 19446833Sgd78059 * More ERI_RPENDING will provide better performance but requires more 19456833Sgd78059 * system DVMA memory. 19466833Sgd78059 * eri_rx_ring_size can be used to tune this value from /etc/system 19476833Sgd78059 * eri_rx_ring_size cannot be NDD'able due to non-recoverable errors 19486833Sgd78059 * which cannot be detected from NDD operations 19496833Sgd78059 */ 19506833Sgd78059 19516833Sgd78059 /* 19526833Sgd78059 * get the rxring size bits 19536833Sgd78059 */ 19546833Sgd78059 switch (ERI_RPENDING) { 19556833Sgd78059 case 32: i = ERX_RINGSZ_32; 19566833Sgd78059 break; 19576833Sgd78059 case 64: i = ERX_RINGSZ_64; 19586833Sgd78059 break; 19596833Sgd78059 case 128: i = ERX_RINGSZ_128; 19606833Sgd78059 break; 19616833Sgd78059 case 256: i = ERX_RINGSZ_256; 19626833Sgd78059 break; 19636833Sgd78059 case 512: i = ERX_RINGSZ_512; 19646833Sgd78059 break; 19656833Sgd78059 case 1024: i = ERX_RINGSZ_1024; 19666833Sgd78059 break; 19676833Sgd78059 case 2048: i = ERX_RINGSZ_2048; 19686833Sgd78059 break; 19696833Sgd78059 case 4096: i = ERX_RINGSZ_4096; 19706833Sgd78059 break; 19716833Sgd78059 default: 19726833Sgd78059 ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG, 19736833Sgd78059 unk_rx_descr_sze_msg, ERI_RPENDING); 19746833Sgd78059 return (1); 19756833Sgd78059 } 19766833Sgd78059 19776833Sgd78059 i <<= ERI_RX_RINGSZ_SHIFT; 19786833Sgd78059 i |= (ERI_FSTBYTE_OFFSET << ERI_RX_CONFIG_FBO_SHIFT) | 19796833Sgd78059 (ETHERHEADER_SIZE << ERI_RX_CONFIG_RX_CSSTART_SHIFT) | 19806833Sgd78059 (ERI_RX_FIFOTH_1024 << ERI_RX_CONFIG_RXFIFOTH_SHIFT); 19816833Sgd78059 19826833Sgd78059 PUT_ERXREG(config, i); 19836833Sgd78059 PUT_ERXREG(rx_blanking, 19846833Sgd78059 (param_intr_blank_time << ERI_RX_BLNK_INTR_TIME_SHIFT) | 19856833Sgd78059 param_intr_blank_packets); 19866833Sgd78059 19876833Sgd78059 PUT_ERXREG(rx_pause_threshold, rx_pause_threshold); 19886833Sgd78059 erip->rxfifo_size = GET_ERXREG(rxfifo_size); 19896833Sgd78059 ENABLE_RXDMA(erip); 19906833Sgd78059 return (0); 19916833Sgd78059 } 19926833Sgd78059 19936833Sgd78059 static int 19946833Sgd78059 eri_freebufs(struct eri *erip) 19956833Sgd78059 { 19966833Sgd78059 int status = 0; 19976833Sgd78059 19987394Sgdamore@opensolaris.org status = eri_flush_rxbufs(erip); 19996833Sgd78059 return (status); 20006833Sgd78059 } 20016833Sgd78059 20026833Sgd78059 static void 20036833Sgd78059 eri_update_rxbufs(struct eri *erip) 20046833Sgd78059 { 20056833Sgd78059 int i; 20066833Sgd78059 volatile struct rmd *rmdp, *rmdpbase; 20076833Sgd78059 20086833Sgd78059 /* 20096833Sgd78059 * Hang out receive buffers. 20106833Sgd78059 */ 20116833Sgd78059 rmdpbase = erip->rmdp; 20126833Sgd78059 for (i = 0; i < ERI_RPENDING; i++) { 20136833Sgd78059 rmdp = rmdpbase + i; 20146833Sgd78059 UPDATE_RMD(rmdp); 20156833Sgd78059 } 20166833Sgd78059 20176833Sgd78059 /* 20186833Sgd78059 * sync RXDMA descriptors. 20196833Sgd78059 */ 20206833Sgd78059 ERI_SYNCIOPB(erip, erip->rmdp, (ERI_RPENDING * sizeof (struct rmd)), 20216833Sgd78059 DDI_DMA_SYNC_FORDEV); 20226833Sgd78059 /* 20236833Sgd78059 * Reset RMD 'walking' pointers. 20246833Sgd78059 */ 20256833Sgd78059 erip->rnextp = erip->rmdp; 20266833Sgd78059 erip->rx_completion = 0; 20276833Sgd78059 erip->rx_kick = ERI_RPENDING - 4; 20286833Sgd78059 } 20296833Sgd78059 20306833Sgd78059 /* 20316833Sgd78059 * This routine is used to reset the RX DMA only. In the case of RX 20326833Sgd78059 * failures such as RX Tag Error, RX hang etc... we don't want to 20336833Sgd78059 * do global reset which takes down the link and clears the FIFO's 20346833Sgd78059 * By doing RX only reset, we leave the TX and the link intact. 20356833Sgd78059 */ 20366833Sgd78059 static uint32_t 20376833Sgd78059 eri_init_rx_channel(struct eri *erip) 20386833Sgd78059 { 20396833Sgd78059 erip->flags &= ~ERI_RXINIT; 20406833Sgd78059 (void) eri_erx_reset(erip); 20416833Sgd78059 eri_update_rxbufs(erip); 20426833Sgd78059 if (eri_init_rxregs(erip)) 20436833Sgd78059 return (1); 20446833Sgd78059 PUT_MACREG(rxmask, BMAC_RXINTR_MASK); 20456833Sgd78059 PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB); 20466833Sgd78059 erip->rx_reset_issued = 0; 20476833Sgd78059 HSTAT(erip, rx_inits); 20486833Sgd78059 erip->flags |= ERI_RXINIT; 20496833Sgd78059 return (0); 20506833Sgd78059 } 20516833Sgd78059 20526833Sgd78059 static void 20536833Sgd78059 eri_init_rx(struct eri *erip) 20546833Sgd78059 { 20556833Sgd78059 uint16_t *ladrf; 20566833Sgd78059 20576833Sgd78059 /* 20586833Sgd78059 * First of all make sure the Receive MAC is stop. 20596833Sgd78059 */ 20606833Sgd78059 (void) eri_rxmac_disable(erip); /* Disable the RX MAC */ 20616833Sgd78059 20626833Sgd78059 /* 20636833Sgd78059 * Program BigMAC with local individual ethernet address. 20646833Sgd78059 */ 20656833Sgd78059 20666833Sgd78059 PUT_MACREG(madd0, (erip->ouraddr[4] << 8) | erip->ouraddr[5]); 20676833Sgd78059 PUT_MACREG(madd1, (erip->ouraddr[2] << 8) | erip->ouraddr[3]); 20686833Sgd78059 PUT_MACREG(madd2, (erip->ouraddr[0] << 8) | erip->ouraddr[1]); 20696833Sgd78059 20706833Sgd78059 /* 20716833Sgd78059 * Set up multicast address filter by passing all multicast 20726833Sgd78059 * addresses through a crc generator, and then using the 20736833Sgd78059 * low order 8 bits as a index into the 256 bit logical 20746833Sgd78059 * address filter. The high order four bits select the word, 20756833Sgd78059 * while the rest of the bits select the bit within the word. 20766833Sgd78059 */ 20776833Sgd78059 20786833Sgd78059 ladrf = erip->ladrf; 20796833Sgd78059 20806833Sgd78059 PUT_MACREG(hash0, ladrf[0]); 20816833Sgd78059 PUT_MACREG(hash1, ladrf[1]); 20826833Sgd78059 PUT_MACREG(hash2, ladrf[2]); 20836833Sgd78059 PUT_MACREG(hash3, ladrf[3]); 20846833Sgd78059 PUT_MACREG(hash4, ladrf[4]); 20856833Sgd78059 PUT_MACREG(hash5, ladrf[5]); 20866833Sgd78059 PUT_MACREG(hash6, ladrf[6]); 20876833Sgd78059 PUT_MACREG(hash7, ladrf[7]); 20886833Sgd78059 PUT_MACREG(hash8, ladrf[8]); 20896833Sgd78059 PUT_MACREG(hash9, ladrf[9]); 20906833Sgd78059 PUT_MACREG(hash10, ladrf[10]); 20916833Sgd78059 PUT_MACREG(hash11, ladrf[11]); 20926833Sgd78059 PUT_MACREG(hash12, ladrf[12]); 20936833Sgd78059 PUT_MACREG(hash13, ladrf[13]); 20946833Sgd78059 PUT_MACREG(hash14, ladrf[14]); 20956833Sgd78059 PUT_MACREG(hash15, ladrf[15]); 20966833Sgd78059 20976833Sgd78059 #ifdef ERI_DONT_STRIP_CRC 20986833Sgd78059 PUT_MACREG(rxcfg, 20996833Sgd78059 ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) | 21006833Sgd78059 (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) | 21016833Sgd78059 BMAC_RXCFG_ENAB)); 21026833Sgd78059 #else 21036833Sgd78059 PUT_MACREG(rxcfg, 21046833Sgd78059 ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) | 21056833Sgd78059 (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) | 21066833Sgd78059 BMAC_RXCFG_ENAB | BMAC_RXCFG_STRIP_CRC)); 21076833Sgd78059 #endif 21086833Sgd78059 /* wait after setting Hash Enable bit */ 21096833Sgd78059 /* drv_usecwait(10); */ 21106833Sgd78059 21116833Sgd78059 HSTAT(erip, rx_inits); 21126833Sgd78059 } 21136833Sgd78059 21146833Sgd78059 /* 21156833Sgd78059 * This routine is used to init the TX MAC only. 21166833Sgd78059 * &erip->xmitlock is held before calling this routine. 21176833Sgd78059 */ 21186833Sgd78059 void 21196833Sgd78059 eri_init_txmac(struct eri *erip) 21206833Sgd78059 { 21216833Sgd78059 uint32_t carrier_ext = 0; 21226833Sgd78059 21236833Sgd78059 erip->flags &= ~ERI_TXINIT; 21246833Sgd78059 /* 21256833Sgd78059 * Stop the Transmit MAC. 21266833Sgd78059 */ 21276833Sgd78059 (void) eri_txmac_disable(erip); 21286833Sgd78059 21296833Sgd78059 /* 21306833Sgd78059 * Must be Internal Transceiver 21316833Sgd78059 */ 21326833Sgd78059 if (param_mode) 21336833Sgd78059 PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ? 21346833Sgd78059 BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE)); 21356833Sgd78059 else 21366833Sgd78059 PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ? 21376833Sgd78059 BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE | 21386833Sgd78059 BMAC_XIFC_DIS_ECHO)); 21396833Sgd78059 21406833Sgd78059 /* 21416833Sgd78059 * Initialize the interpacket gap registers 21426833Sgd78059 */ 21436833Sgd78059 PUT_MACREG(ipg1, param_ipg1); 21446833Sgd78059 PUT_MACREG(ipg2, param_ipg2); 21456833Sgd78059 21466833Sgd78059 if (erip->ngu_enable) 21476833Sgd78059 PUT_MACREG(txcfg, ((param_mode ? BMAC_TXCFG_FDX: 0) | 21486833Sgd78059 ((param_lance_mode && (erip->lance_mode_enable)) ? 21496833Sgd78059 BMAC_TXCFG_ENIPG0 : 0) | 21506833Sgd78059 (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0) | 21516833Sgd78059 BMAC_TXCFG_NGU)); 21526833Sgd78059 else 21536833Sgd78059 PUT_MACREG(txcfg, ((param_mode ? BMAC_TXCFG_FDX: 0) | 21546833Sgd78059 ((param_lance_mode && (erip->lance_mode_enable)) ? 21556833Sgd78059 BMAC_TXCFG_ENIPG0 : 0) | 21566833Sgd78059 (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0))); 21576833Sgd78059 21586833Sgd78059 ENABLE_TXDMA(erip); 21596833Sgd78059 ENABLE_TXMAC(erip); 21606833Sgd78059 21616833Sgd78059 HSTAT(erip, tx_inits); 21626833Sgd78059 erip->flags |= ERI_TXINIT; 21636833Sgd78059 } 21646833Sgd78059 21656833Sgd78059 static void 21666833Sgd78059 eri_unallocthings(struct eri *erip) 21676833Sgd78059 { 21686833Sgd78059 uint32_t flag; 21696833Sgd78059 uint32_t i; 21706833Sgd78059 21716833Sgd78059 flag = erip->alloc_flag; 21726833Sgd78059 21736833Sgd78059 if (flag & ERI_DESC_MEM_MAP) 21746833Sgd78059 (void) ddi_dma_unbind_handle(erip->md_h); 21756833Sgd78059 21766833Sgd78059 if (flag & ERI_DESC_MEM_ALLOC) { 21776833Sgd78059 ddi_dma_mem_free(&erip->mdm_h); 21786833Sgd78059 erip->rmdp = NULL; 21796833Sgd78059 erip->eri_tmdp = NULL; 21806833Sgd78059 } 21816833Sgd78059 21826833Sgd78059 if (flag & ERI_DESC_HANDLE_ALLOC) 21836833Sgd78059 ddi_dma_free_handle(&erip->md_h); 21846833Sgd78059 21856833Sgd78059 (void) eri_freebufs(erip); 21866833Sgd78059 21876833Sgd78059 if (flag & ERI_RCV_HANDLE_ALLOC) 21886833Sgd78059 for (i = 0; i < erip->rcv_handle_cnt; i++) 21896833Sgd78059 ddi_dma_free_handle(&erip->ndmarh[i]); 21906833Sgd78059 21916833Sgd78059 if (flag & ERI_RCV_DVMA_ALLOC) { 21926833Sgd78059 (void) dvma_release(erip->eri_dvmarh); 21936833Sgd78059 erip->eri_dvmarh = NULL; 21946833Sgd78059 } 21956833Sgd78059 21966833Sgd78059 if (flag & ERI_XBUFS_KMEM_DMABIND) { 21976833Sgd78059 (void) ddi_dma_unbind_handle(erip->tbuf_handle); 21986833Sgd78059 erip->tbuf_ioaddr = 0; 21996833Sgd78059 } 22006833Sgd78059 22016833Sgd78059 if (flag & ERI_XBUFS_KMEM_ALLOC) { 22027394Sgdamore@opensolaris.org ddi_dma_mem_free(&erip->tbuf_acch); 22036833Sgd78059 erip->tbuf_kaddr = NULL; 22046833Sgd78059 } 22056833Sgd78059 22066833Sgd78059 if (flag & ERI_XBUFS_HANDLE_ALLOC) { 22076833Sgd78059 ddi_dma_free_handle(&erip->tbuf_handle); 22086833Sgd78059 erip->tbuf_handle = NULL; 22096833Sgd78059 } 22106833Sgd78059 22116833Sgd78059 } 22126833Sgd78059 22136833Sgd78059 /* 22146833Sgd78059 * Initialize channel. 22156833Sgd78059 * Return true on success, false on error. 22166833Sgd78059 * 22176833Sgd78059 * The recommended sequence for initialization is: 22186833Sgd78059 * 1. Issue a Global Reset command to the Ethernet Channel. 22196833Sgd78059 * 2. Poll the Global_Reset bits until the execution of the reset has been 22206833Sgd78059 * completed. 22216833Sgd78059 * 2(a). Use the MIF Frame/Output register to reset the transceiver. 22226833Sgd78059 * Poll Register 0 to till the Resetbit is 0. 22236833Sgd78059 * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op, 22246833Sgd78059 * 100Mbps and Non-Isolated mode. The main point here is to bring the 22256833Sgd78059 * PHY out of Isolate mode so that it can generate the rx_clk and tx_clk 22266833Sgd78059 * to the MII interface so that the Bigmac core can correctly reset 22276833Sgd78059 * upon a software reset. 22286833Sgd78059 * 2(c). Issue another Global Reset command to the Ethernet Channel and poll 22296833Sgd78059 * the Global_Reset bits till completion. 22306833Sgd78059 * 3. Set up all the data structures in the host memory. 22316833Sgd78059 * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration 22326833Sgd78059 * Register). 22336833Sgd78059 * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration 22346833Sgd78059 * Register). 22356833Sgd78059 * 6. Program the Transmit Descriptor Ring Base Address in the ETX. 22366833Sgd78059 * 7. Program the Receive Descriptor Ring Base Address in the ERX. 22376833Sgd78059 * 8. Program the Global Configuration and the Global Interrupt Mask Registers. 22386833Sgd78059 * 9. Program the ETX Configuration register (enable the Transmit DMA channel). 22396833Sgd78059 * 10. Program the ERX Configuration register (enable the Receive DMA channel). 22406833Sgd78059 * 11. Program the XIF Configuration Register (enable the XIF). 22416833Sgd78059 * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC). 22426833Sgd78059 * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC). 22436833Sgd78059 */ 22446833Sgd78059 /* 22456833Sgd78059 * lock order: 22466833Sgd78059 * intrlock->linklock->xmitlock->xcvrlock 22476833Sgd78059 */ 22486833Sgd78059 static boolean_t 22496833Sgd78059 eri_init(struct eri *erip) 22506833Sgd78059 { 22516833Sgd78059 uint32_t init_stat = 0; 22526833Sgd78059 uint32_t partial_init = 0; 22536833Sgd78059 uint32_t carrier_ext = 0; 22546833Sgd78059 uint32_t mac_ctl = 0; 22556833Sgd78059 boolean_t ret; 22566833Sgd78059 uint32_t link_timeout = ERI_LINKCHECK_TIMER; 22576833Sgd78059 link_state_t linkupdate = LINK_STATE_UNKNOWN; 22586833Sgd78059 22596833Sgd78059 /* 22606833Sgd78059 * Just return successfully if device is suspended. 22616833Sgd78059 * eri_init() will be called again from resume. 22626833Sgd78059 */ 22636833Sgd78059 ASSERT(erip != NULL); 22646833Sgd78059 22656833Sgd78059 if (erip->flags & ERI_SUSPENDED) { 22666833Sgd78059 ret = B_TRUE; 22676833Sgd78059 goto init_exit; 22686833Sgd78059 } 22696833Sgd78059 22706833Sgd78059 mutex_enter(&erip->intrlock); 22716833Sgd78059 eri_stop_timer(erip); /* acquire linklock */ 22726833Sgd78059 mutex_enter(&erip->xmitlock); 22736833Sgd78059 erip->flags &= (ERI_DLPI_LINKUP | ERI_STARTED); 22746833Sgd78059 erip->wantw = B_FALSE; 22756833Sgd78059 HSTAT(erip, inits); 22766833Sgd78059 erip->txhung = 0; 22776833Sgd78059 22786833Sgd78059 if ((erip->stats.inits > 1) && (erip->init_macregs == 0)) 22796833Sgd78059 eri_savecntrs(erip); 22806833Sgd78059 22816833Sgd78059 mutex_enter(&erip->xcvrlock); 22826833Sgd78059 if (!param_linkup || erip->linkcheck) { 22836833Sgd78059 if (!erip->linkcheck) 22846833Sgd78059 linkupdate = LINK_STATE_DOWN; 22856833Sgd78059 (void) eri_stop(erip); 22866833Sgd78059 } 22876833Sgd78059 if (!(erip->flags & ERI_DLPI_LINKUP) || !param_linkup) { 22886833Sgd78059 erip->flags |= ERI_DLPI_LINKUP; 22896833Sgd78059 eri_mif_poll(erip, MIF_POLL_STOP); 22906833Sgd78059 (void) eri_new_xcvr(erip); 22916833Sgd78059 ERI_DEBUG_MSG1(erip, XCVR_MSG, "New transceiver detected."); 22926833Sgd78059 if (param_transceiver != NO_XCVR) { 22936833Sgd78059 /* 22946833Sgd78059 * Reset the new PHY and bring up the 22956833Sgd78059 * link 22966833Sgd78059 */ 22976833Sgd78059 if (eri_reset_xcvr(erip)) { 22986833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, 22996833Sgd78059 ERI_VERB_MSG, "In Init after reset"); 23006833Sgd78059 mutex_exit(&erip->xcvrlock); 23016833Sgd78059 link_timeout = 0; 23026833Sgd78059 goto done; 23036833Sgd78059 } 23046833Sgd78059 if (erip->stats.link_up == LINK_STATE_UP) 23056833Sgd78059 linkupdate = LINK_STATE_UP; 23066833Sgd78059 } else { 23076833Sgd78059 erip->flags |= (ERI_RUNNING | ERI_INITIALIZED); 23086833Sgd78059 param_linkup = 0; 23096833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 23106833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 23116833Sgd78059 linkupdate = LINK_STATE_DOWN; 23126833Sgd78059 /* 23136833Sgd78059 * Still go on and complete the MAC initialization as 23146833Sgd78059 * xcvr might show up later. 23156833Sgd78059 * you must return to their mutex ordering. 23166833Sgd78059 */ 23176833Sgd78059 } 23186833Sgd78059 eri_mif_poll(erip, MIF_POLL_START); 23196833Sgd78059 } 23206833Sgd78059 23216833Sgd78059 mutex_exit(&erip->xcvrlock); 23226833Sgd78059 23236833Sgd78059 /* 23246833Sgd78059 * Allocate data structures. 23256833Sgd78059 */ 23266833Sgd78059 if (erip->global_reset_issued) { 23276833Sgd78059 if (erip->global_reset_issued == 2) { /* fast path */ 23287394Sgdamore@opensolaris.org 23296833Sgd78059 /* 23306833Sgd78059 * Hang out/Initialize descriptors and buffers. 23316833Sgd78059 */ 23326833Sgd78059 eri_init_txbufs(erip); 23336833Sgd78059 23346833Sgd78059 eri_update_rxbufs(erip); 23356833Sgd78059 } else { 23366833Sgd78059 init_stat = eri_allocthings(erip); 23376833Sgd78059 if (init_stat) 23386833Sgd78059 goto done; 23396833Sgd78059 23406833Sgd78059 if (eri_freebufs(erip)) 23416833Sgd78059 goto done; 23426833Sgd78059 /* 23436833Sgd78059 * Hang out/Initialize descriptors and buffers. 23446833Sgd78059 */ 23456833Sgd78059 eri_init_txbufs(erip); 23466833Sgd78059 if (eri_init_rxbufs(erip)) 23476833Sgd78059 goto done; 23486833Sgd78059 } 23496833Sgd78059 } 23506833Sgd78059 23516833Sgd78059 /* 23526833Sgd78059 * BigMAC requires that we confirm that tx, rx and hash are in 23536833Sgd78059 * quiescent state. 23546833Sgd78059 * MAC will not reset successfully if the transceiver is not reset and 23556833Sgd78059 * brought out of Isolate mode correctly. TXMAC reset may fail if the 23566833Sgd78059 * ext. transceiver is just disconnected. If it fails, try again by 23576833Sgd78059 * checking the transceiver. 23586833Sgd78059 */ 23596833Sgd78059 if (eri_txmac_disable(erip)) { 23606833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG, 23616833Sgd78059 disable_txmac_msg); 23626833Sgd78059 param_linkup = 0; /* force init again */ 23636833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 23646833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 23656833Sgd78059 linkupdate = LINK_STATE_DOWN; 23666833Sgd78059 goto done; 23676833Sgd78059 } 23686833Sgd78059 23696833Sgd78059 if (eri_rxmac_disable(erip)) { 23706833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG, 23716833Sgd78059 disable_rxmac_msg); 23726833Sgd78059 param_linkup = 0; /* force init again */ 23736833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 23746833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 23756833Sgd78059 linkupdate = LINK_STATE_DOWN; 23766833Sgd78059 goto done; 23776833Sgd78059 } 23786833Sgd78059 23796833Sgd78059 eri_init_macregs_generic(erip); 23806833Sgd78059 23816833Sgd78059 /* 23826833Sgd78059 * Initialize ERI Global registers : 23836833Sgd78059 * config 23846833Sgd78059 * For PCI : err_mask, bif_cfg 23856833Sgd78059 * 23866833Sgd78059 * Use user-configurable parameter for enabling 64-bit transfers. 23876833Sgd78059 * Note:For PCI, burst sizes are in multiples of 64-bytes. 23886833Sgd78059 */ 23896833Sgd78059 23906833Sgd78059 /* 23916833Sgd78059 * Significant performance improvements can be achieved by 23926833Sgd78059 * disabling transmit interrupt. Thus TMD's are reclaimed 23936833Sgd78059 * only very infrequently. 23946833Sgd78059 * The PCS Interrupt is masked here. It is enabled only when 23956833Sgd78059 * a PCS link is brought up because there is no second level 23966833Sgd78059 * mask for this interrupt.. 23976833Sgd78059 * Init GLOBAL, TXMAC, RXMAC and MACCTL interrupt masks here. 23986833Sgd78059 */ 23996833Sgd78059 if (! partial_init) { 24006833Sgd78059 PUT_GLOBREG(intmask, ERI_G_MASK_INTR); 24016833Sgd78059 erip->tx_int_me = 0; 24026833Sgd78059 PUT_MACREG(txmask, BMAC_TXINTR_MASK); 24036833Sgd78059 PUT_MACREG(rxmask, BMAC_RXINTR_MASK); 24046833Sgd78059 PUT_MACREG(macctl_mask, ERI_MACCTL_INTR_MASK); 24056833Sgd78059 } 24066833Sgd78059 24076833Sgd78059 if (erip->global_reset_issued) { 24086833Sgd78059 /* 24096833Sgd78059 * Initialize ETX Registers: 24106833Sgd78059 * config, txring_lo, txring_hi 24116833Sgd78059 */ 24126833Sgd78059 if (eri_init_txregs(erip)) 24136833Sgd78059 goto done; 24146833Sgd78059 /* 24156833Sgd78059 * Initialize ERX Registers: 24166833Sgd78059 * rxring_lo, rxring_hi, config, rx_blanking, 24176833Sgd78059 * rx_pause_threshold. Also, rx_kick 24186833Sgd78059 * Read and save rxfifo_size. 24196833Sgd78059 */ 24206833Sgd78059 if (eri_init_rxregs(erip)) 24216833Sgd78059 goto done; 24226833Sgd78059 } 24236833Sgd78059 24246833Sgd78059 PUT_MACREG(macctl_mask, ERI_MACCTL_INTR_MASK); 24256833Sgd78059 24266833Sgd78059 /* 24276833Sgd78059 * Set up the slottime,and rxconfig, txconfig without enabling 24286833Sgd78059 * the latter two at this time 24296833Sgd78059 */ 24306833Sgd78059 PUT_MACREG(slot, BMAC_SLOT_TIME); 24316833Sgd78059 carrier_ext = 0; 24326833Sgd78059 24336833Sgd78059 #ifdef ERI_DONT_STRIP_CRC 24346833Sgd78059 PUT_MACREG(rxcfg, 24356833Sgd78059 ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) | 24366833Sgd78059 (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) | 24376833Sgd78059 (carrier_ext ? BMAC_RXCFG_CARR_EXT : 0))); 24386833Sgd78059 #else 24396833Sgd78059 PUT_MACREG(rxcfg, 24406833Sgd78059 ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) | 24416833Sgd78059 (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) | 24426833Sgd78059 BMAC_RXCFG_STRIP_CRC | 24436833Sgd78059 (carrier_ext ? BMAC_RXCFG_CARR_EXT : 0))); 24446833Sgd78059 #endif 24456833Sgd78059 drv_usecwait(10); /* wait after setting Hash Enable bit */ 24466833Sgd78059 24476833Sgd78059 if (erip->ngu_enable) 24486833Sgd78059 PUT_MACREG(txcfg, 24496833Sgd78059 ((param_mode ? BMAC_TXCFG_FDX: 0) | 24506833Sgd78059 ((param_lance_mode && (erip->lance_mode_enable)) ? 24516833Sgd78059 BMAC_TXCFG_ENIPG0 : 0) | 24526833Sgd78059 (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0) | 24536833Sgd78059 BMAC_TXCFG_NGU)); 24546833Sgd78059 else 24556833Sgd78059 PUT_MACREG(txcfg, 24566833Sgd78059 ((param_mode ? BMAC_TXCFG_FDX: 0) | 24576833Sgd78059 ((param_lance_mode && (erip->lance_mode_enable)) ? 24586833Sgd78059 BMAC_TXCFG_ENIPG0 : 0) | 24596833Sgd78059 (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0))); 24606833Sgd78059 24616833Sgd78059 if (erip->pauseRX) 24626833Sgd78059 mac_ctl = ERI_MCTLCFG_RXPAUSE; 24636833Sgd78059 if (erip->pauseTX) 24646833Sgd78059 mac_ctl |= ERI_MCTLCFG_TXPAUSE; 24656833Sgd78059 24666833Sgd78059 PUT_MACREG(macctl_cfg, mac_ctl); 24676833Sgd78059 24686833Sgd78059 /* 24696833Sgd78059 * Must be Internal Transceiver 24706833Sgd78059 */ 24716833Sgd78059 if (param_mode) 24726833Sgd78059 PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ? 24736833Sgd78059 BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE)); 24746833Sgd78059 else { 24756833Sgd78059 PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ? 24766833Sgd78059 BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE | 24776833Sgd78059 BMAC_XIFC_DIS_ECHO)); 24786833Sgd78059 24796833Sgd78059 link_timeout = ERI_CHECK_HANG_TIMER; 24806833Sgd78059 } 24816833Sgd78059 24826833Sgd78059 /* 24836833Sgd78059 * if MAC int loopback flag is set, put xifc reg in mii loopback 24846833Sgd78059 * mode {DIAG} 24856833Sgd78059 */ 24866833Sgd78059 if (erip->flags & ERI_MACLOOPBACK) { 24876833Sgd78059 PUT_MACREG(xifc, GET_MACREG(xifc) | BMAC_XIFC_MIILPBK); 24886833Sgd78059 } 24896833Sgd78059 24906833Sgd78059 /* 24916833Sgd78059 * Enable TX and RX MACs. 24926833Sgd78059 */ 24936833Sgd78059 ENABLE_MAC(erip); 24946833Sgd78059 erip->flags |= (ERI_RUNNING | ERI_INITIALIZED | 24956833Sgd78059 ERI_TXINIT | ERI_RXINIT); 24966833Sgd78059 mac_tx_update(erip->mh); 24976833Sgd78059 erip->global_reset_issued = 0; 24986833Sgd78059 24996833Sgd78059 #ifdef ERI_10_10_FORCE_SPEED_WORKAROUND 25006833Sgd78059 eri_xcvr_force_mode(erip, &link_timeout); 25016833Sgd78059 #endif 25026833Sgd78059 25036833Sgd78059 done: 25046833Sgd78059 if (init_stat) 25056833Sgd78059 eri_unallocthings(erip); 25066833Sgd78059 25076833Sgd78059 mutex_exit(&erip->xmitlock); 25086833Sgd78059 eri_start_timer(erip, eri_check_link, link_timeout); 25096833Sgd78059 mutex_exit(&erip->intrlock); 25106833Sgd78059 25116833Sgd78059 if (linkupdate != LINK_STATE_UNKNOWN) 25126833Sgd78059 mac_link_update(erip->mh, linkupdate); 25136833Sgd78059 25146833Sgd78059 ret = (erip->flags & ERI_RUNNING) ? B_TRUE : B_FALSE; 25156833Sgd78059 if (!ret) { 25166833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, 25176833Sgd78059 "eri_init failed"); 25186833Sgd78059 } 25196833Sgd78059 25206833Sgd78059 init_exit: 25216833Sgd78059 ASSERT(!MUTEX_HELD(&erip->linklock)); 25226833Sgd78059 return (ret); 25236833Sgd78059 } 25246833Sgd78059 25256833Sgd78059 /* 25266833Sgd78059 * 0 as burstsize upon failure as it signifies no burst size. 25276833Sgd78059 */ 25286833Sgd78059 static int 25296833Sgd78059 eri_burstsize(struct eri *erip) 25306833Sgd78059 { 25316833Sgd78059 ddi_dma_handle_t handle; 25326833Sgd78059 25336833Sgd78059 if (ddi_dma_alloc_handle(erip->dip, &dma_attr, DDI_DMA_DONTWAIT, 25346833Sgd78059 NULL, &handle)) 25356833Sgd78059 return (DDI_FAILURE); 25366833Sgd78059 25376833Sgd78059 erip->burstsizes = ddi_dma_burstsizes(handle); 25386833Sgd78059 ddi_dma_free_handle(&handle); 25396833Sgd78059 25406833Sgd78059 if (erip->burstsizes) 25416833Sgd78059 return (DDI_SUCCESS); 25426833Sgd78059 25436833Sgd78059 return (DDI_FAILURE); 25446833Sgd78059 } 25456833Sgd78059 25466833Sgd78059 /* 25476833Sgd78059 * Un-initialize (STOP) ERI channel. 25486833Sgd78059 */ 25496833Sgd78059 static void 25506833Sgd78059 eri_uninit(struct eri *erip) 25516833Sgd78059 { 25526833Sgd78059 boolean_t needind; 25536833Sgd78059 25546833Sgd78059 /* 25556833Sgd78059 * Allow up to 'ERI_DRAINTIME' for pending xmit's to complete. 25566833Sgd78059 */ 25576833Sgd78059 ERI_DELAY((erip->tcurp == erip->tnextp), ERI_DRAINTIME); 25586833Sgd78059 25596833Sgd78059 mutex_enter(&erip->intrlock); 25606833Sgd78059 eri_stop_timer(erip); /* acquire linklock */ 25616833Sgd78059 mutex_enter(&erip->xmitlock); 25626833Sgd78059 mutex_enter(&erip->xcvrlock); 25636833Sgd78059 eri_mif_poll(erip, MIF_POLL_STOP); 25646833Sgd78059 erip->flags &= ~ERI_DLPI_LINKUP; 25656833Sgd78059 mutex_exit(&erip->xcvrlock); 25666833Sgd78059 25676833Sgd78059 needind = !erip->linkcheck; 25686833Sgd78059 (void) eri_stop(erip); 25696833Sgd78059 erip->flags &= ~ERI_RUNNING; 25706833Sgd78059 25716833Sgd78059 mutex_exit(&erip->xmitlock); 25726833Sgd78059 eri_start_timer(erip, eri_check_link, 0); 25736833Sgd78059 mutex_exit(&erip->intrlock); 25746833Sgd78059 25756833Sgd78059 if (needind) 25766833Sgd78059 mac_link_update(erip->mh, LINK_STATE_DOWN); 25776833Sgd78059 } 25786833Sgd78059 25796833Sgd78059 /* 25806833Sgd78059 * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and 25816833Sgd78059 * map it in IO space. 25826833Sgd78059 * 25836833Sgd78059 * The driver allocates STREAMS buffers which will be mapped in DVMA 25846833Sgd78059 * space using DDI DMA resources. 25856833Sgd78059 * 25866833Sgd78059 */ 25876833Sgd78059 static int 25886833Sgd78059 eri_allocthings(struct eri *erip) 25896833Sgd78059 { 25906833Sgd78059 25916833Sgd78059 uintptr_t a; 25926833Sgd78059 int size; 25936833Sgd78059 uint32_t rval; 25946833Sgd78059 int i; 25956833Sgd78059 size_t real_len; 25966833Sgd78059 uint32_t cookiec; 25976833Sgd78059 int alloc_stat = 0; 25986833Sgd78059 ddi_dma_cookie_t dma_cookie; 25996833Sgd78059 26006833Sgd78059 /* 26016833Sgd78059 * Return if resources are already allocated. 26026833Sgd78059 */ 26036833Sgd78059 if (erip->rmdp) 26046833Sgd78059 return (alloc_stat); 26056833Sgd78059 26066833Sgd78059 erip->alloc_flag = 0; 26076833Sgd78059 26086833Sgd78059 /* 26096833Sgd78059 * Allocate the TMD and RMD descriptors and extra for alignments. 26106833Sgd78059 */ 26116833Sgd78059 size = (ERI_RPENDING * sizeof (struct rmd) + 26126833Sgd78059 ERI_TPENDING * sizeof (struct eri_tmd)) + ERI_GMDALIGN; 26136833Sgd78059 26146833Sgd78059 rval = ddi_dma_alloc_handle(erip->dip, &desc_dma_attr, 26156833Sgd78059 DDI_DMA_DONTWAIT, 0, &erip->md_h); 26166833Sgd78059 if (rval != DDI_SUCCESS) { 26176833Sgd78059 return (++alloc_stat); 26186833Sgd78059 } 26196833Sgd78059 erip->alloc_flag |= ERI_DESC_HANDLE_ALLOC; 26206833Sgd78059 26216833Sgd78059 rval = ddi_dma_mem_alloc(erip->md_h, size, &erip->dev_attr, 26226833Sgd78059 DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0, 26236833Sgd78059 (caddr_t *)&erip->iopbkbase, &real_len, &erip->mdm_h); 26246833Sgd78059 if (rval != DDI_SUCCESS) { 26256833Sgd78059 return (++alloc_stat); 26266833Sgd78059 } 26276833Sgd78059 erip->alloc_flag |= ERI_DESC_MEM_ALLOC; 26286833Sgd78059 26296833Sgd78059 rval = ddi_dma_addr_bind_handle(erip->md_h, NULL, 26306833Sgd78059 (caddr_t)erip->iopbkbase, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 26316833Sgd78059 DDI_DMA_DONTWAIT, 0, &erip->md_c, &cookiec); 26326833Sgd78059 26336833Sgd78059 if (rval != DDI_DMA_MAPPED) 26346833Sgd78059 return (++alloc_stat); 26356833Sgd78059 26366833Sgd78059 erip->alloc_flag |= ERI_DESC_MEM_MAP; 26376833Sgd78059 26386833Sgd78059 if (cookiec != 1) 26396833Sgd78059 return (++alloc_stat); 26406833Sgd78059 26416833Sgd78059 erip->iopbiobase = erip->md_c.dmac_address; 26426833Sgd78059 26436833Sgd78059 a = erip->iopbkbase; 26446833Sgd78059 a = ROUNDUP(a, ERI_GMDALIGN); 26456833Sgd78059 erip->rmdp = (struct rmd *)a; 26466833Sgd78059 a += ERI_RPENDING * sizeof (struct rmd); 26476833Sgd78059 erip->eri_tmdp = (struct eri_tmd *)a; 26486833Sgd78059 /* 26496833Sgd78059 * Specifically we reserve n (ERI_TPENDING + ERI_RPENDING) 26506833Sgd78059 * pagetable entries. Therefore we have 2 ptes for each 26516833Sgd78059 * descriptor. Since the ethernet buffers are 1518 bytes 26526833Sgd78059 * so they can at most use 2 ptes. 26536833Sgd78059 * Will do a ddi_dma_addr_setup for each bufer 26546833Sgd78059 */ 26556833Sgd78059 /* 26566833Sgd78059 * In the current implementation, we use the ddi compliant 26577394Sgdamore@opensolaris.org * dma interface. We allocate ERI_RPENDING dma handles for receive 26587394Sgdamore@opensolaris.org * activity. The actual dma mapping is done in the io function 26597394Sgdamore@opensolaris.org * eri_read_dma(), by calling the ddi_dma_addr_bind_handle. 26606833Sgd78059 * Dma resources are deallocated by calling ddi_dma_unbind_handle 26616833Sgd78059 * in eri_reclaim() for transmit and eri_read_dma(), for receive io. 26626833Sgd78059 */ 26636833Sgd78059 26646833Sgd78059 if (eri_use_dvma_rx && 26656833Sgd78059 (dvma_reserve(erip->dip, &eri_dma_limits, (ERI_RPENDING * 2), 26666833Sgd78059 &erip->eri_dvmarh)) == DDI_SUCCESS) { 26676833Sgd78059 erip->alloc_flag |= ERI_RCV_DVMA_ALLOC; 26686833Sgd78059 } else { 26696833Sgd78059 erip->eri_dvmarh = NULL; 26706833Sgd78059 26716833Sgd78059 for (i = 0; i < ERI_RPENDING; i++) { 26726833Sgd78059 rval = ddi_dma_alloc_handle(erip->dip, 26736833Sgd78059 &dma_attr, DDI_DMA_DONTWAIT, 26746833Sgd78059 0, &erip->ndmarh[i]); 26756833Sgd78059 26766833Sgd78059 if (rval != DDI_SUCCESS) { 26776833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_HIGH, 26786833Sgd78059 ERI_VERB_MSG, alloc_rx_dmah_msg); 26796833Sgd78059 alloc_stat++; 26806833Sgd78059 break; 26816833Sgd78059 } 26826833Sgd78059 } 26836833Sgd78059 26846833Sgd78059 erip->rcv_handle_cnt = i; 26856833Sgd78059 26866833Sgd78059 if (i) 26876833Sgd78059 erip->alloc_flag |= ERI_RCV_HANDLE_ALLOC; 26886833Sgd78059 26896833Sgd78059 if (alloc_stat) 26906833Sgd78059 return (alloc_stat); 26916833Sgd78059 26926833Sgd78059 } 26936833Sgd78059 26946833Sgd78059 /* 26957394Sgdamore@opensolaris.org * Allocate TX buffer 26967394Sgdamore@opensolaris.org * Note: buffers must always be allocated in the native 26976833Sgd78059 * ordering of the CPU (always big-endian for Sparc). 26986833Sgd78059 * ddi_dma_mem_alloc returns memory in the native ordering 26996833Sgd78059 * of the bus (big endian for SBus, little endian for PCI). 27006833Sgd78059 * So we cannot use ddi_dma_mem_alloc(, &erip->ge_dev_attr) 27016833Sgd78059 * because we'll get little endian memory on PCI. 27026833Sgd78059 */ 27036833Sgd78059 if (ddi_dma_alloc_handle(erip->dip, &desc_dma_attr, DDI_DMA_DONTWAIT, 27046833Sgd78059 0, &erip->tbuf_handle) != DDI_SUCCESS) { 27056833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG, 27066833Sgd78059 alloc_tx_dmah_msg); 27076833Sgd78059 return (++alloc_stat); 27086833Sgd78059 } 27096833Sgd78059 erip->alloc_flag |= ERI_XBUFS_HANDLE_ALLOC; 27107394Sgdamore@opensolaris.org size = ERI_TPENDING * ERI_BUFSIZE; 27117394Sgdamore@opensolaris.org if (ddi_dma_mem_alloc(erip->tbuf_handle, size, &buf_attr, 27127394Sgdamore@opensolaris.org DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, &erip->tbuf_kaddr, 27137394Sgdamore@opensolaris.org &real_len, &erip->tbuf_acch) != DDI_SUCCESS) { 27146833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG, 27156833Sgd78059 alloc_tx_dmah_msg); 27166833Sgd78059 return (++alloc_stat); 27176833Sgd78059 } 27186833Sgd78059 erip->alloc_flag |= ERI_XBUFS_KMEM_ALLOC; 27196833Sgd78059 if (ddi_dma_addr_bind_handle(erip->tbuf_handle, NULL, 27206833Sgd78059 erip->tbuf_kaddr, size, DDI_DMA_WRITE | DDI_DMA_CONSISTENT, 27216833Sgd78059 DDI_DMA_DONTWAIT, 0, &dma_cookie, &cookiec) != DDI_DMA_MAPPED) { 27226833Sgd78059 return (++alloc_stat); 27236833Sgd78059 } 27246833Sgd78059 erip->tbuf_ioaddr = dma_cookie.dmac_address; 27256833Sgd78059 erip->alloc_flag |= ERI_XBUFS_KMEM_DMABIND; 27266833Sgd78059 if (cookiec != 1) 27276833Sgd78059 return (++alloc_stat); 27286833Sgd78059 27296833Sgd78059 /* 27306833Sgd78059 * Keep handy limit values for RMD, TMD, and Buffers. 27316833Sgd78059 */ 27326833Sgd78059 erip->rmdlimp = &((erip->rmdp)[ERI_RPENDING]); 27336833Sgd78059 erip->eri_tmdlimp = &((erip->eri_tmdp)[ERI_TPENDING]); 27346833Sgd78059 27356833Sgd78059 /* 27367394Sgdamore@opensolaris.org * Zero out RCV holders. 27376833Sgd78059 */ 27386833Sgd78059 bzero((caddr_t)erip->rmblkp, sizeof (erip->rmblkp)); 27396833Sgd78059 return (alloc_stat); 27406833Sgd78059 } 27416833Sgd78059 27426833Sgd78059 /* <<<<<<<<<<<<<<<<< INTERRUPT HANDLING FUNCTION >>>>>>>>>>>>>>>>>>>> */ 27436833Sgd78059 /* 27446833Sgd78059 * First check to see if it is our device interrupting. 27456833Sgd78059 */ 27466833Sgd78059 static uint_t 27476833Sgd78059 eri_intr(caddr_t arg) 27486833Sgd78059 { 27496833Sgd78059 struct eri *erip = (void *)arg; 27506833Sgd78059 uint32_t erisbits; 27516833Sgd78059 uint32_t mif_status; 27526833Sgd78059 uint32_t serviced = DDI_INTR_UNCLAIMED; 27536833Sgd78059 link_state_t linkupdate = LINK_STATE_UNKNOWN; 27546833Sgd78059 boolean_t macupdate = B_FALSE; 27556833Sgd78059 mblk_t *mp; 27566833Sgd78059 mblk_t *head; 27576833Sgd78059 mblk_t **tail; 27586833Sgd78059 27596833Sgd78059 head = NULL; 27606833Sgd78059 tail = &head; 27616833Sgd78059 27626833Sgd78059 mutex_enter(&erip->intrlock); 27636833Sgd78059 27646833Sgd78059 erisbits = GET_GLOBREG(status); 27656833Sgd78059 27666833Sgd78059 /* 27676833Sgd78059 * Check if it is only the RX_DONE interrupt, which is 27686833Sgd78059 * the most frequent one. 27696833Sgd78059 */ 27706833Sgd78059 if (((erisbits & ERI_G_STATUS_RX_INT) == ERI_G_STATUS_RX_DONE) && 27716833Sgd78059 (erip->flags & ERI_RUNNING)) { 27726833Sgd78059 serviced = DDI_INTR_CLAIMED; 27736833Sgd78059 goto rx_done_int; 27746833Sgd78059 } 27756833Sgd78059 27766833Sgd78059 /* Claim the first interrupt after initialization */ 27776833Sgd78059 if (erip->flags & ERI_INITIALIZED) { 27786833Sgd78059 erip->flags &= ~ERI_INITIALIZED; 27796833Sgd78059 serviced = DDI_INTR_CLAIMED; 27806833Sgd78059 } 27816833Sgd78059 27826833Sgd78059 /* Check for interesting events */ 27836833Sgd78059 if ((erisbits & ERI_G_STATUS_INTR) == 0) { 27846833Sgd78059 #ifdef ESTAR_WORKAROUND 27856833Sgd78059 uint32_t linkupdate; 27866833Sgd78059 #endif 27876833Sgd78059 27886833Sgd78059 ERI_DEBUG_MSG2(erip, DIAG_MSG, 27896833Sgd78059 "eri_intr: Interrupt Not Claimed gsbits %X", erisbits); 27906833Sgd78059 #ifdef DEBUG 27916833Sgd78059 noteri++; 27926833Sgd78059 #endif 27936833Sgd78059 ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:MIF Config = 0x%X", 27946833Sgd78059 GET_MIFREG(mif_cfg)); 27956833Sgd78059 ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:MIF imask = 0x%X", 27966833Sgd78059 GET_MIFREG(mif_imask)); 27976833Sgd78059 ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:INT imask = 0x%X", 27986833Sgd78059 GET_GLOBREG(intmask)); 27996833Sgd78059 ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:alias %X", 28006833Sgd78059 GET_GLOBREG(status_alias)); 28016833Sgd78059 #ifdef ESTAR_WORKAROUND 28026833Sgd78059 linkupdate = eri_check_link_noind(erip); 28036833Sgd78059 #endif 28046833Sgd78059 mutex_exit(&erip->intrlock); 28056833Sgd78059 #ifdef ESTAR_WORKAROUND 28066833Sgd78059 if (linkupdate != LINK_STATE_UNKNOWN) 28076833Sgd78059 mac_link_update(erip->mh, linkupdate); 28086833Sgd78059 #endif 28096833Sgd78059 return (serviced); 28106833Sgd78059 } 28116833Sgd78059 serviced = DDI_INTR_CLAIMED; 28126833Sgd78059 28136833Sgd78059 if (!(erip->flags & ERI_RUNNING)) { 28146833Sgd78059 mutex_exit(&erip->intrlock); 28156833Sgd78059 eri_uninit(erip); 28166833Sgd78059 return (serviced); 28176833Sgd78059 } 28186833Sgd78059 28196833Sgd78059 if (erisbits & ERI_G_STATUS_FATAL_ERR) { 28206833Sgd78059 ERI_DEBUG_MSG2(erip, INTR_MSG, 28216833Sgd78059 "eri_intr: fatal error: erisbits = %X", erisbits); 28226833Sgd78059 (void) eri_fatal_err(erip, erisbits); 28236833Sgd78059 eri_reinit_fatal++; 28246833Sgd78059 28256833Sgd78059 if (erip->rx_reset_issued) { 28266833Sgd78059 erip->rx_reset_issued = 0; 28276833Sgd78059 (void) eri_init_rx_channel(erip); 28286833Sgd78059 mutex_exit(&erip->intrlock); 28296833Sgd78059 } else { 28306833Sgd78059 param_linkup = 0; 28316833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 28326833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 28336833Sgd78059 DISABLE_MAC(erip); 28346833Sgd78059 mutex_exit(&erip->intrlock); 28356833Sgd78059 (void) eri_init(erip); 28366833Sgd78059 } 28376833Sgd78059 return (serviced); 28386833Sgd78059 } 28396833Sgd78059 28406833Sgd78059 if (erisbits & ERI_G_STATUS_NONFATAL_ERR) { 28416833Sgd78059 ERI_DEBUG_MSG2(erip, INTR_MSG, 28426833Sgd78059 "eri_intr: non-fatal error: erisbits = %X", erisbits); 28436833Sgd78059 (void) eri_nonfatal_err(erip, erisbits); 28446833Sgd78059 if (erip->linkcheck) { 28456833Sgd78059 mutex_exit(&erip->intrlock); 28466833Sgd78059 (void) eri_init(erip); 28476833Sgd78059 return (serviced); 28486833Sgd78059 } 28496833Sgd78059 } 28506833Sgd78059 28516833Sgd78059 if (erisbits & ERI_G_STATUS_MIF_INT) { 28526833Sgd78059 uint16_t stat; 28536833Sgd78059 ERI_DEBUG_MSG2(erip, XCVR_MSG, 28546833Sgd78059 "eri_intr:MIF Interrupt:mii_status %X", erip->mii_status); 28556833Sgd78059 eri_stop_timer(erip); /* acquire linklock */ 28566833Sgd78059 28576833Sgd78059 mutex_enter(&erip->xmitlock); 28586833Sgd78059 mutex_enter(&erip->xcvrlock); 28596833Sgd78059 #ifdef ERI_MIF_POLL_STATUS_WORKAROUND 28606833Sgd78059 mif_status = GET_MIFREG(mif_bsts); 28616833Sgd78059 eri_mif_poll(erip, MIF_POLL_STOP); 28626833Sgd78059 ERI_DEBUG_MSG3(erip, XCVR_MSG, 28636833Sgd78059 "eri_intr: new MIF interrupt status %X XCVR status %X", 28646833Sgd78059 mif_status, erip->mii_status); 28656833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat); 28666833Sgd78059 linkupdate = eri_mif_check(erip, stat, stat); 28676833Sgd78059 28686833Sgd78059 #else 28696833Sgd78059 mif_status = GET_MIFREG(mif_bsts); 28706833Sgd78059 eri_mif_poll(erip, MIF_POLL_STOP); 28716833Sgd78059 linkupdate = eri_mif_check(erip, (uint16_t)mif_status, 28726833Sgd78059 (uint16_t)(mif_status >> 16)); 28736833Sgd78059 #endif 28746833Sgd78059 eri_mif_poll(erip, MIF_POLL_START); 28756833Sgd78059 mutex_exit(&erip->xcvrlock); 28766833Sgd78059 mutex_exit(&erip->xmitlock); 28776833Sgd78059 28786833Sgd78059 if (!erip->openloop_autoneg) 28796833Sgd78059 eri_start_timer(erip, eri_check_link, 28806833Sgd78059 ERI_LINKCHECK_TIMER); 28816833Sgd78059 else 28826833Sgd78059 eri_start_timer(erip, eri_check_link, 28836833Sgd78059 ERI_P_FAULT_TIMER); 28846833Sgd78059 } 28856833Sgd78059 28866833Sgd78059 ERI_DEBUG_MSG2(erip, INTR_MSG, 28876833Sgd78059 "eri_intr:May have Read Interrupt status:status %X", erisbits); 28886833Sgd78059 28896833Sgd78059 rx_done_int: 28906833Sgd78059 if ((erisbits & (ERI_G_STATUS_TX_INT_ME)) || 28916833Sgd78059 (erip->tx_cur_cnt >= tx_interrupt_rate)) { 28926833Sgd78059 mutex_enter(&erip->xmitlock); 28936833Sgd78059 erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) & 28946833Sgd78059 ETX_COMPLETION_MASK); 28956833Sgd78059 28966833Sgd78059 macupdate |= eri_reclaim(erip, erip->tx_completion); 2897*10306SVitezslav.Batrla@Sun.COM if (macupdate) 2898*10306SVitezslav.Batrla@Sun.COM erip->wantw = B_FALSE; 2899*10306SVitezslav.Batrla@Sun.COM 29006833Sgd78059 mutex_exit(&erip->xmitlock); 29016833Sgd78059 } 29026833Sgd78059 29036833Sgd78059 if (erisbits & ERI_G_STATUS_RX_DONE) { 29046833Sgd78059 volatile struct rmd *rmdp, *rmdpbase; 29056833Sgd78059 volatile uint32_t rmdi; 29066833Sgd78059 uint8_t loop_limit = 0x20; 29076833Sgd78059 uint64_t flags; 29086833Sgd78059 uint32_t rmdmax_mask = erip->rmdmax_mask; 29096833Sgd78059 29106833Sgd78059 rmdpbase = erip->rmdp; 29116833Sgd78059 rmdi = erip->rx_completion; 29126833Sgd78059 rmdp = rmdpbase + rmdi; 29136833Sgd78059 29146833Sgd78059 /* 29156833Sgd78059 * Sync RMD before looking at it. 29166833Sgd78059 */ 29176833Sgd78059 ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd), 29186833Sgd78059 DDI_DMA_SYNC_FORCPU); 29196833Sgd78059 /* 29206833Sgd78059 * Loop through each RMD. 29216833Sgd78059 */ 29226833Sgd78059 29236833Sgd78059 flags = GET_RMD_FLAGS(rmdp); 29246833Sgd78059 while (((flags & ERI_RMD_OWN) == 0) && (loop_limit)) { 29256833Sgd78059 /* process one packet */ 29266833Sgd78059 mp = eri_read_dma(erip, rmdp, rmdi, flags); 29276833Sgd78059 rmdi = (rmdi + 1) & rmdmax_mask; 29286833Sgd78059 rmdp = rmdpbase + rmdi; 29296833Sgd78059 29306833Sgd78059 if (mp != NULL) { 29316833Sgd78059 *tail = mp; 29326833Sgd78059 tail = &mp->b_next; 29336833Sgd78059 } 29346833Sgd78059 29356833Sgd78059 /* 29366833Sgd78059 * ERI RCV DMA fetches or updates four descriptors 29376833Sgd78059 * a time. Also we don't want to update the desc. 29386833Sgd78059 * batch we just received packet on. So we update 29396833Sgd78059 * descriptors for every 4 packets and we update 29406833Sgd78059 * the group of 4 after the current batch. 29416833Sgd78059 */ 29426833Sgd78059 29436833Sgd78059 if (!(rmdi % 4)) { 29446833Sgd78059 if (eri_overflow_reset && 29456833Sgd78059 (GET_GLOBREG(status_alias) & 29466833Sgd78059 ERI_G_STATUS_NONFATAL_ERR)) { 29476833Sgd78059 loop_limit = 1; 29486833Sgd78059 } else { 29496833Sgd78059 erip->rx_kick = 29506833Sgd78059 (rmdi + ERI_RPENDING - 4) & 29516833Sgd78059 rmdmax_mask; 29526833Sgd78059 PUT_ERXREG(rx_kick, erip->rx_kick); 29536833Sgd78059 } 29546833Sgd78059 } 29556833Sgd78059 29566833Sgd78059 /* 29576833Sgd78059 * Sync the next RMD before looking at it. 29586833Sgd78059 */ 29596833Sgd78059 ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd), 29606833Sgd78059 DDI_DMA_SYNC_FORCPU); 29616833Sgd78059 flags = GET_RMD_FLAGS(rmdp); 29626833Sgd78059 loop_limit--; 29636833Sgd78059 } 29646833Sgd78059 erip->rx_completion = rmdi; 29656833Sgd78059 } 29666833Sgd78059 29676833Sgd78059 mutex_exit(&erip->intrlock); 29686833Sgd78059 29696833Sgd78059 if (head) 29706833Sgd78059 mac_rx(erip->mh, NULL, head); 29716833Sgd78059 29726833Sgd78059 if (macupdate) 29736833Sgd78059 mac_tx_update(erip->mh); 29746833Sgd78059 29756833Sgd78059 if (linkupdate != LINK_STATE_UNKNOWN) 29766833Sgd78059 mac_link_update(erip->mh, linkupdate); 29776833Sgd78059 29786833Sgd78059 return (serviced); 29796833Sgd78059 } 29806833Sgd78059 29816833Sgd78059 /* 29826833Sgd78059 * Handle interrupts for fatal errors 29836833Sgd78059 * Need reinitialization. 29846833Sgd78059 */ 29856833Sgd78059 #define PCI_DATA_PARITY_REP (1 << 8) 29866833Sgd78059 #define PCI_SING_TARGET_ABORT (1 << 11) 29876833Sgd78059 #define PCI_RCV_TARGET_ABORT (1 << 12) 29886833Sgd78059 #define PCI_RCV_MASTER_ABORT (1 << 13) 29896833Sgd78059 #define PCI_SING_SYSTEM_ERR (1 << 14) 29906833Sgd78059 #define PCI_DATA_PARITY_ERR (1 << 15) 29916833Sgd78059 29926833Sgd78059 /* called with intrlock held */ 29936833Sgd78059 static void 29946833Sgd78059 eri_fatal_err(struct eri *erip, uint32_t erisbits) 29956833Sgd78059 { 29966833Sgd78059 uint16_t pci_status; 29976833Sgd78059 uint32_t pci_error_int = 0; 29986833Sgd78059 29996833Sgd78059 if (erisbits & ERI_G_STATUS_RX_TAG_ERR) { 30006833Sgd78059 erip->rx_reset_issued = 1; 30016833Sgd78059 HSTAT(erip, rxtag_err); 30026833Sgd78059 } else { 30036833Sgd78059 erip->global_reset_issued = 1; 30046833Sgd78059 if (erisbits & ERI_G_STATUS_BUS_ERR_INT) { 30056833Sgd78059 pci_error_int = 1; 30066833Sgd78059 HSTAT(erip, pci_error_int); 30076833Sgd78059 } else if (erisbits & ERI_G_STATUS_PERR_INT) { 30086833Sgd78059 HSTAT(erip, parity_error); 30096833Sgd78059 } else { 30106833Sgd78059 HSTAT(erip, unknown_fatal); 30116833Sgd78059 } 30126833Sgd78059 } 30136833Sgd78059 30146833Sgd78059 /* 30156833Sgd78059 * PCI bus error 30166833Sgd78059 */ 30176833Sgd78059 if (pci_error_int && erip->pci_config_handle) { 30186833Sgd78059 pci_status = pci_config_get16(erip->pci_config_handle, 30196833Sgd78059 PCI_CONF_STAT); 30206833Sgd78059 ERI_DEBUG_MSG2(erip, FATAL_ERR_MSG, "Bus Error Status %x", 30216833Sgd78059 pci_status); 30226833Sgd78059 if (pci_status & PCI_DATA_PARITY_REP) 30236833Sgd78059 HSTAT(erip, pci_data_parity_err); 30246833Sgd78059 if (pci_status & PCI_SING_TARGET_ABORT) 30256833Sgd78059 HSTAT(erip, pci_signal_target_abort); 30266833Sgd78059 if (pci_status & PCI_RCV_TARGET_ABORT) 30276833Sgd78059 HSTAT(erip, pci_rcvd_target_abort); 30286833Sgd78059 if (pci_status & PCI_RCV_MASTER_ABORT) 30296833Sgd78059 HSTAT(erip, pci_rcvd_master_abort); 30306833Sgd78059 if (pci_status & PCI_SING_SYSTEM_ERR) 30316833Sgd78059 HSTAT(erip, pci_signal_system_err); 30326833Sgd78059 if (pci_status & PCI_DATA_PARITY_ERR) 30336833Sgd78059 HSTAT(erip, pci_signal_system_err); 30346833Sgd78059 /* 30356833Sgd78059 * clear it by writing the value that was read back. 30366833Sgd78059 */ 30376833Sgd78059 pci_config_put16(erip->pci_config_handle, PCI_CONF_STAT, 30386833Sgd78059 pci_status); 30396833Sgd78059 } 30406833Sgd78059 } 30416833Sgd78059 30426833Sgd78059 /* 30436833Sgd78059 * Handle interrupts regarding non-fatal events. 30446833Sgd78059 * TXMAC, RXMAC and MACCTL events 30456833Sgd78059 */ 30466833Sgd78059 static void 30476833Sgd78059 eri_nonfatal_err(struct eri *erip, uint32_t erisbits) 30486833Sgd78059 { 30496833Sgd78059 30506833Sgd78059 uint32_t txmac_sts, rxmac_sts, macctl_sts, pause_time; 30516833Sgd78059 30526833Sgd78059 #ifdef ERI_PM_WORKAROUND 30536833Sgd78059 if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED, 30546833Sgd78059 PCI_PM_IDLESPEED_NONE) == DDI_SUCCESS) 30556833Sgd78059 erip->stats.pmcap = ERI_PMCAP_NONE; 30566833Sgd78059 #endif 30576833Sgd78059 30586833Sgd78059 if (erisbits & ERI_G_STATUS_TX_MAC_INT) { 30596833Sgd78059 txmac_sts = GET_MACREG(txsts); 30606833Sgd78059 if (txmac_sts & BMAC_TXSTS_TX_URUN) { 30616833Sgd78059 erip->linkcheck = 1; 30626833Sgd78059 HSTAT(erip, txmac_urun); 30636833Sgd78059 HSTAT(erip, oerrors); 30646833Sgd78059 } 30656833Sgd78059 30666833Sgd78059 if (txmac_sts & BMAC_TXSTS_MAXPKT_ERR) { 30676833Sgd78059 erip->linkcheck = 1; 30686833Sgd78059 HSTAT(erip, txmac_maxpkt_err); 30696833Sgd78059 HSTAT(erip, oerrors); 30706833Sgd78059 } 30716833Sgd78059 if (txmac_sts & BMAC_TXSTS_NCC_EXP) { 30726833Sgd78059 erip->stats.collisions += 0x10000; 30736833Sgd78059 } 30746833Sgd78059 30756833Sgd78059 if (txmac_sts & BMAC_TXSTS_ECC_EXP) { 30766833Sgd78059 erip->stats.excessive_coll += 0x10000; 30776833Sgd78059 } 30786833Sgd78059 30796833Sgd78059 if (txmac_sts & BMAC_TXSTS_LCC_EXP) { 30806833Sgd78059 erip->stats.late_coll += 0x10000; 30816833Sgd78059 } 30826833Sgd78059 30836833Sgd78059 if (txmac_sts & BMAC_TXSTS_FCC_EXP) { 30846833Sgd78059 erip->stats.first_coll += 0x10000; 30856833Sgd78059 } 30866833Sgd78059 30876833Sgd78059 if (txmac_sts & BMAC_TXSTS_DEFER_EXP) { 30886833Sgd78059 HSTAT(erip, defer_timer_exp); 30896833Sgd78059 } 30906833Sgd78059 30916833Sgd78059 if (txmac_sts & BMAC_TXSTS_PEAK_EXP) { 30926833Sgd78059 erip->stats.peak_attempt_cnt += 0x100; 30936833Sgd78059 } 30946833Sgd78059 } 30956833Sgd78059 30966833Sgd78059 if (erisbits & ERI_G_STATUS_RX_NO_BUF) { 30976833Sgd78059 ERI_DEBUG_MSG1(erip, NONFATAL_MSG, "rx dropped/no free desc"); 30986833Sgd78059 30996833Sgd78059 if (eri_overflow_reset) 31006833Sgd78059 erip->linkcheck = 1; 31016833Sgd78059 31026833Sgd78059 HSTAT(erip, no_free_rx_desc); 31036833Sgd78059 HSTAT(erip, ierrors); 31046833Sgd78059 } 31056833Sgd78059 if (erisbits & ERI_G_STATUS_RX_MAC_INT) { 31066833Sgd78059 rxmac_sts = GET_MACREG(rxsts); 31076833Sgd78059 if (rxmac_sts & BMAC_RXSTS_RX_OVF) { 31086833Sgd78059 #ifndef ERI_RMAC_HANG_WORKAROUND 31096833Sgd78059 eri_stop_timer(erip); /* acquire linklock */ 31106833Sgd78059 erip->check_rmac_hang ++; 31116833Sgd78059 erip->check2_rmac_hang = 0; 31126833Sgd78059 erip->rxfifo_wr_ptr = GET_ERXREG(rxfifo_wr_ptr); 31136833Sgd78059 erip->rxfifo_rd_ptr = GET_ERXREG(rxfifo_rd_ptr); 31146833Sgd78059 31156833Sgd78059 ERI_DEBUG_MSG5(erip, NONFATAL_MSG, 31166833Sgd78059 "overflow intr %d: %8x wr:%2x rd:%2x", 31176833Sgd78059 erip->check_rmac_hang, 31186833Sgd78059 GET_MACREG(macsm), 31196833Sgd78059 GET_ERXREG(rxfifo_wr_ptr), 31206833Sgd78059 GET_ERXREG(rxfifo_rd_ptr)); 31216833Sgd78059 31226833Sgd78059 eri_start_timer(erip, eri_check_link, 31236833Sgd78059 ERI_CHECK_HANG_TIMER); 31246833Sgd78059 #endif 31256833Sgd78059 if (eri_overflow_reset) 31266833Sgd78059 erip->linkcheck = 1; 31276833Sgd78059 31286833Sgd78059 HSTAT(erip, rx_overflow); 31296833Sgd78059 HSTAT(erip, ierrors); 31306833Sgd78059 } 31316833Sgd78059 31326833Sgd78059 if (rxmac_sts & BMAC_RXSTS_ALE_EXP) { 31336833Sgd78059 erip->stats.rx_align_err += 0x10000; 31346833Sgd78059 erip->stats.ierrors += 0x10000; 31356833Sgd78059 } 31366833Sgd78059 31376833Sgd78059 if (rxmac_sts & BMAC_RXSTS_CRC_EXP) { 31386833Sgd78059 erip->stats.rx_crc_err += 0x10000; 31396833Sgd78059 erip->stats.ierrors += 0x10000; 31406833Sgd78059 } 31416833Sgd78059 31426833Sgd78059 if (rxmac_sts & BMAC_RXSTS_LEN_EXP) { 31436833Sgd78059 erip->stats.rx_length_err += 0x10000; 31446833Sgd78059 erip->stats.ierrors += 0x10000; 31456833Sgd78059 } 31466833Sgd78059 31476833Sgd78059 if (rxmac_sts & BMAC_RXSTS_CVI_EXP) { 31486833Sgd78059 erip->stats.rx_code_viol_err += 0x10000; 31496833Sgd78059 erip->stats.ierrors += 0x10000; 31506833Sgd78059 } 31516833Sgd78059 } 31526833Sgd78059 31536833Sgd78059 if (erisbits & ERI_G_STATUS_MAC_CTRL_INT) { 31546833Sgd78059 31556833Sgd78059 macctl_sts = GET_MACREG(macctl_sts); 31566833Sgd78059 if (macctl_sts & ERI_MCTLSTS_PAUSE_RCVD) { 31576833Sgd78059 pause_time = ((macctl_sts & 31586833Sgd78059 ERI_MCTLSTS_PAUSE_TIME) >> 16); 31596833Sgd78059 ERI_DEBUG_MSG2(erip, NONFATAL_MSG, 31606833Sgd78059 "PAUSE Received. pause time = %X slot_times", 31616833Sgd78059 pause_time); 31626833Sgd78059 HSTAT(erip, pause_rxcount); 31636833Sgd78059 erip->stats.pause_time_count += pause_time; 31646833Sgd78059 } 31656833Sgd78059 31666833Sgd78059 if (macctl_sts & ERI_MCTLSTS_PAUSE_STATE) { 31676833Sgd78059 HSTAT(erip, pause_oncount); 31686833Sgd78059 erip->stats.pausing = 1; 31696833Sgd78059 } 31706833Sgd78059 31716833Sgd78059 if (macctl_sts & ERI_MCTLSTS_NONPAUSE) { 31726833Sgd78059 HSTAT(erip, pause_offcount); 31736833Sgd78059 erip->stats.pausing = 0; 31746833Sgd78059 } 31756833Sgd78059 } 31766833Sgd78059 31776833Sgd78059 } 31786833Sgd78059 31796833Sgd78059 /* 31806833Sgd78059 * if this is the first init do not bother to save the 31816833Sgd78059 * counters. 31826833Sgd78059 */ 31836833Sgd78059 static void 31846833Sgd78059 eri_savecntrs(struct eri *erip) 31856833Sgd78059 { 31866833Sgd78059 uint32_t fecnt, aecnt, lecnt, rxcv; 31876833Sgd78059 uint32_t ltcnt, excnt, fccnt; 31886833Sgd78059 31896833Sgd78059 /* XXX What all gets added in ierrors and oerrors? */ 31906833Sgd78059 fecnt = GET_MACREG(fecnt); 31916833Sgd78059 HSTATN(erip, rx_crc_err, fecnt); 31926833Sgd78059 PUT_MACREG(fecnt, 0); 31936833Sgd78059 31946833Sgd78059 aecnt = GET_MACREG(aecnt); 31956833Sgd78059 HSTATN(erip, rx_align_err, aecnt); 31966833Sgd78059 PUT_MACREG(aecnt, 0); 31976833Sgd78059 31986833Sgd78059 lecnt = GET_MACREG(lecnt); 31996833Sgd78059 HSTATN(erip, rx_length_err, lecnt); 32006833Sgd78059 PUT_MACREG(lecnt, 0); 32016833Sgd78059 32026833Sgd78059 rxcv = GET_MACREG(rxcv); 32036833Sgd78059 HSTATN(erip, rx_code_viol_err, rxcv); 32046833Sgd78059 PUT_MACREG(rxcv, 0); 32056833Sgd78059 32066833Sgd78059 ltcnt = GET_MACREG(ltcnt); 32076833Sgd78059 HSTATN(erip, late_coll, ltcnt); 32086833Sgd78059 PUT_MACREG(ltcnt, 0); 32096833Sgd78059 32106833Sgd78059 erip->stats.collisions += (GET_MACREG(nccnt) + ltcnt); 32116833Sgd78059 PUT_MACREG(nccnt, 0); 32126833Sgd78059 32136833Sgd78059 excnt = GET_MACREG(excnt); 32146833Sgd78059 HSTATN(erip, excessive_coll, excnt); 32156833Sgd78059 PUT_MACREG(excnt, 0); 32166833Sgd78059 32176833Sgd78059 fccnt = GET_MACREG(fccnt); 32186833Sgd78059 HSTATN(erip, first_coll, fccnt); 32196833Sgd78059 PUT_MACREG(fccnt, 0); 32206833Sgd78059 32216833Sgd78059 /* 32226833Sgd78059 * Do not add code violations to input errors. 32236833Sgd78059 * They are already counted in CRC errors 32246833Sgd78059 */ 32256833Sgd78059 HSTATN(erip, ierrors, (fecnt + aecnt + lecnt)); 32266833Sgd78059 HSTATN(erip, oerrors, (ltcnt + excnt)); 32276833Sgd78059 } 32286833Sgd78059 32296833Sgd78059 mblk_t * 32306833Sgd78059 eri_allocb_sp(size_t size) 32316833Sgd78059 { 32326833Sgd78059 mblk_t *mp; 32336833Sgd78059 32346833Sgd78059 size += 128; 32356833Sgd78059 if ((mp = allocb(size + 3 * ERI_BURSTSIZE, BPRI_HI)) == NULL) { 32366833Sgd78059 return (NULL); 32376833Sgd78059 } 32386833Sgd78059 mp->b_wptr += 128; 32396833Sgd78059 mp->b_wptr = (uint8_t *)ROUNDUP2(mp->b_wptr, ERI_BURSTSIZE); 32406833Sgd78059 mp->b_rptr = mp->b_wptr; 32416833Sgd78059 32426833Sgd78059 return (mp); 32436833Sgd78059 } 32446833Sgd78059 32456833Sgd78059 mblk_t * 32466833Sgd78059 eri_allocb(size_t size) 32476833Sgd78059 { 32486833Sgd78059 mblk_t *mp; 32496833Sgd78059 32506833Sgd78059 if ((mp = allocb(size + 3 * ERI_BURSTSIZE, BPRI_HI)) == NULL) { 32516833Sgd78059 return (NULL); 32526833Sgd78059 } 32536833Sgd78059 mp->b_wptr = (uint8_t *)ROUNDUP2(mp->b_wptr, ERI_BURSTSIZE); 32546833Sgd78059 mp->b_rptr = mp->b_wptr; 32556833Sgd78059 32566833Sgd78059 return (mp); 32576833Sgd78059 } 32586833Sgd78059 32596833Sgd78059 /* 32606833Sgd78059 * Hardware Dependent Functions 32616833Sgd78059 * New Section. 32626833Sgd78059 */ 32636833Sgd78059 32646833Sgd78059 /* <<<<<<<<<<<<<<<< Fast Ethernet PHY Bit Bang Operations >>>>>>>>>>>>>>>>>> */ 32656833Sgd78059 32666833Sgd78059 static void 32676833Sgd78059 send_bit(struct eri *erip, uint32_t x) 32686833Sgd78059 { 32696833Sgd78059 PUT_MIFREG(mif_bbdata, x); 32706833Sgd78059 PUT_MIFREG(mif_bbclk, ERI_BBCLK_LOW); 32716833Sgd78059 PUT_MIFREG(mif_bbclk, ERI_BBCLK_HIGH); 32726833Sgd78059 } 32736833Sgd78059 32746833Sgd78059 /* 32756833Sgd78059 * To read the MII register bits according to the IEEE Standard 32766833Sgd78059 */ 32776833Sgd78059 static uint32_t 32786833Sgd78059 get_bit_std(struct eri *erip) 32796833Sgd78059 { 32806833Sgd78059 uint32_t x; 32816833Sgd78059 32826833Sgd78059 PUT_MIFREG(mif_bbclk, ERI_BBCLK_LOW); 32836833Sgd78059 drv_usecwait(1); /* wait for >330 ns for stable data */ 32846833Sgd78059 if (param_transceiver == INTERNAL_XCVR) 32856833Sgd78059 x = (GET_MIFREG(mif_cfg) & ERI_MIF_CFGM0) ? 1 : 0; 32866833Sgd78059 else 32876833Sgd78059 x = (GET_MIFREG(mif_cfg) & ERI_MIF_CFGM1) ? 1 : 0; 32886833Sgd78059 PUT_MIFREG(mif_bbclk, ERI_BBCLK_HIGH); 32896833Sgd78059 return (x); 32906833Sgd78059 } 32916833Sgd78059 32926833Sgd78059 #define SEND_BIT(x) send_bit(erip, x) 32936833Sgd78059 #define GET_BIT_STD(x) x = get_bit_std(erip) 32946833Sgd78059 32956833Sgd78059 32966833Sgd78059 static void 32976833Sgd78059 eri_bb_mii_write(struct eri *erip, uint8_t regad, uint16_t data) 32986833Sgd78059 { 32996833Sgd78059 uint8_t phyad; 33006833Sgd78059 int i; 33016833Sgd78059 33026833Sgd78059 PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 33036833Sgd78059 phyad = erip->phyad; 33046833Sgd78059 (void) eri_bb_force_idle(erip); 33056833Sgd78059 SEND_BIT(0); SEND_BIT(1); /* <ST> */ 33066833Sgd78059 SEND_BIT(0); SEND_BIT(1); /* <OP> */ 33076833Sgd78059 for (i = 4; i >= 0; i--) { /* <AAAAA> */ 33086833Sgd78059 SEND_BIT((phyad >> i) & 1); 33096833Sgd78059 } 33106833Sgd78059 for (i = 4; i >= 0; i--) { /* <RRRRR> */ 33116833Sgd78059 SEND_BIT((regad >> i) & 1); 33126833Sgd78059 } 33136833Sgd78059 SEND_BIT(1); SEND_BIT(0); /* <TA> */ 33146833Sgd78059 for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 33156833Sgd78059 SEND_BIT((data >> i) & 1); 33166833Sgd78059 } 33176833Sgd78059 PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 33186833Sgd78059 } 33196833Sgd78059 33206833Sgd78059 /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 33216833Sgd78059 static uint32_t 33226833Sgd78059 eri_bb_mii_read(struct eri *erip, uint8_t regad, uint16_t *datap) 33236833Sgd78059 { 33246833Sgd78059 uint8_t phyad; 33256833Sgd78059 int i; 33266833Sgd78059 uint32_t x; 33276833Sgd78059 uint32_t y; 33286833Sgd78059 33296833Sgd78059 *datap = 0; 33306833Sgd78059 33316833Sgd78059 PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 33326833Sgd78059 phyad = erip->phyad; 33336833Sgd78059 (void) eri_bb_force_idle(erip); 33346833Sgd78059 SEND_BIT(0); SEND_BIT(1); /* <ST> */ 33356833Sgd78059 SEND_BIT(1); SEND_BIT(0); /* <OP> */ 33366833Sgd78059 for (i = 4; i >= 0; i--) { /* <AAAAA> */ 33376833Sgd78059 SEND_BIT((phyad >> i) & 1); 33386833Sgd78059 } 33396833Sgd78059 for (i = 4; i >= 0; i--) { /* <RRRRR> */ 33406833Sgd78059 SEND_BIT((regad >> i) & 1); 33416833Sgd78059 } 33426833Sgd78059 33436833Sgd78059 PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 33446833Sgd78059 33456833Sgd78059 GET_BIT_STD(x); 33466833Sgd78059 GET_BIT_STD(y); /* <TA> */ 33476833Sgd78059 for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 33486833Sgd78059 GET_BIT_STD(x); 33496833Sgd78059 *datap += (x << i); 33506833Sgd78059 } 33516833Sgd78059 /* Kludge to get the Transceiver out of hung mode */ 33526833Sgd78059 /* XXX: Test if this is still needed */ 33536833Sgd78059 GET_BIT_STD(x); 33546833Sgd78059 GET_BIT_STD(x); 33556833Sgd78059 GET_BIT_STD(x); 33566833Sgd78059 33576833Sgd78059 return (y); 33586833Sgd78059 } 33596833Sgd78059 33606833Sgd78059 static void 33616833Sgd78059 eri_bb_force_idle(struct eri *erip) 33626833Sgd78059 { 33636833Sgd78059 int i; 33646833Sgd78059 33656833Sgd78059 for (i = 0; i < 33; i++) { 33666833Sgd78059 SEND_BIT(1); 33676833Sgd78059 } 33686833Sgd78059 } 33696833Sgd78059 33706833Sgd78059 /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ 33716833Sgd78059 33726833Sgd78059 33736833Sgd78059 /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */ 33746833Sgd78059 33756833Sgd78059 #ifdef ERI_FRM_DEBUG 33766833Sgd78059 int frame_flag = 0; 33776833Sgd78059 #endif 33786833Sgd78059 33796833Sgd78059 /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 33806833Sgd78059 static uint32_t 33816833Sgd78059 eri_mii_read(struct eri *erip, uint8_t regad, uint16_t *datap) 33826833Sgd78059 { 33836833Sgd78059 uint32_t frame; 33846833Sgd78059 uint8_t phyad; 33856833Sgd78059 33866833Sgd78059 if (param_transceiver == NO_XCVR) 33876833Sgd78059 return (1); /* No xcvr present */ 33886833Sgd78059 33896833Sgd78059 if (!erip->frame_enable) 33906833Sgd78059 return (eri_bb_mii_read(erip, regad, datap)); 33916833Sgd78059 33926833Sgd78059 phyad = erip->phyad; 33936833Sgd78059 #ifdef ERI_FRM_DEBUG 33946833Sgd78059 if (!frame_flag) { 33956833Sgd78059 eri_errror(erip->dip, "Frame Register used for MII"); 33966833Sgd78059 frame_flag = 1; 33976833Sgd78059 } 33986833Sgd78059 #endif 33996833Sgd78059 ERI_DEBUG_MSG3(erip, FRM_MSG, 34006833Sgd78059 "Frame Reg :mii_read: phyad = %X reg = %X ", phyad, regad); 34016833Sgd78059 34026833Sgd78059 PUT_MIFREG(mif_frame, ERI_MIF_FRREAD | 34036833Sgd78059 (phyad << ERI_MIF_FRPHYAD_SHIFT) | 34046833Sgd78059 (regad << ERI_MIF_FRREGAD_SHIFT)); 34056833Sgd78059 MIF_ERIDELAY(300, phyad, regad); 34066833Sgd78059 frame = GET_MIFREG(mif_frame); 34076833Sgd78059 if ((frame & ERI_MIF_FRTA0) == 0) { 34086833Sgd78059 return (1); 34096833Sgd78059 } else { 34106833Sgd78059 *datap = (uint16_t)(frame & ERI_MIF_FRDATA); 34116833Sgd78059 return (0); 34126833Sgd78059 } 34136833Sgd78059 34146833Sgd78059 } 34156833Sgd78059 34166833Sgd78059 static void 34176833Sgd78059 eri_mii_write(struct eri *erip, uint8_t regad, uint16_t data) 34186833Sgd78059 { 34196833Sgd78059 uint8_t phyad; 34206833Sgd78059 34216833Sgd78059 if (!erip->frame_enable) { 34226833Sgd78059 eri_bb_mii_write(erip, regad, data); 34236833Sgd78059 return; 34246833Sgd78059 } 34256833Sgd78059 34266833Sgd78059 phyad = erip->phyad; 34276833Sgd78059 34286833Sgd78059 PUT_MIFREG(mif_frame, (ERI_MIF_FRWRITE | 34296833Sgd78059 (phyad << ERI_MIF_FRPHYAD_SHIFT) | 34306833Sgd78059 (regad << ERI_MIF_FRREGAD_SHIFT) | data)); 34316833Sgd78059 MIF_ERIDELAY(300, phyad, regad); 34326833Sgd78059 (void) GET_MIFREG(mif_frame); 34336833Sgd78059 } 34346833Sgd78059 34356833Sgd78059 34366833Sgd78059 /* <<<<<<<<<<<<<<<<< PACKET TRANSMIT FUNCTIONS >>>>>>>>>>>>>>>>>>>> */ 34376833Sgd78059 34386833Sgd78059 #define ERI_CROSS_PAGE_BOUNDRY(i, size, pagesize) \ 34396833Sgd78059 ((i & pagesize) != ((i + size) & pagesize)) 34406833Sgd78059 34416833Sgd78059 /* 34426833Sgd78059 * Send a single mblk. Returns B_TRUE if the packet is sent, or disposed of 34436833Sgd78059 * by freemsg. Returns B_FALSE if the packet was not sent or queued, and 34446833Sgd78059 * should be retried later (due to tx resource exhaustion.) 34456833Sgd78059 */ 34466833Sgd78059 static boolean_t 34476833Sgd78059 eri_send_msg(struct eri *erip, mblk_t *mp) 34486833Sgd78059 { 34496833Sgd78059 volatile struct eri_tmd *tmdp = NULL; 34506833Sgd78059 volatile struct eri_tmd *tbasep = NULL; 34517394Sgdamore@opensolaris.org uint32_t len_msg = 0; 34527394Sgdamore@opensolaris.org uint32_t i; 34536833Sgd78059 uint64_t int_me = 0; 34546833Sgd78059 uint_t tmdcsum = 0; 34556833Sgd78059 uint_t start_offset = 0; 34566833Sgd78059 uint_t stuff_offset = 0; 34576833Sgd78059 uint_t flags = 0; 34586833Sgd78059 34596833Sgd78059 caddr_t ptr; 34606833Sgd78059 uint32_t offset; 34616833Sgd78059 uint64_t ctrl; 34626833Sgd78059 ddi_dma_cookie_t c; 34636833Sgd78059 34646833Sgd78059 if (!param_linkup) { 34656833Sgd78059 freemsg(mp); 34666833Sgd78059 HSTAT(erip, tnocar); 34676833Sgd78059 HSTAT(erip, oerrors); 34686833Sgd78059 return (B_TRUE); 34696833Sgd78059 } 34706833Sgd78059 34716833Sgd78059 #ifdef ERI_HWCSUM 34726833Sgd78059 hcksum_retrieve(mp, NULL, NULL, &start_offset, &stuff_offset, 34736833Sgd78059 NULL, NULL, &flags); 34746833Sgd78059 34756833Sgd78059 if (flags & HCK_PARTIALCKSUM) { 34766833Sgd78059 if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) { 34776833Sgd78059 start_offset += ETHERHEADER_SIZE + 4; 34786833Sgd78059 stuff_offset += ETHERHEADER_SIZE + 4; 34796833Sgd78059 } else { 34806833Sgd78059 start_offset += ETHERHEADER_SIZE; 34816833Sgd78059 stuff_offset += ETHERHEADER_SIZE; 34826833Sgd78059 } 34836833Sgd78059 tmdcsum = ERI_TMD_CSENABL; 34846833Sgd78059 } 34856833Sgd78059 #endif /* ERI_HWCSUM */ 34867394Sgdamore@opensolaris.org 34877394Sgdamore@opensolaris.org if ((len_msg = msgsize(mp)) > ERI_BUFSIZE) { 34887394Sgdamore@opensolaris.org /* 34897394Sgdamore@opensolaris.org * This sholdn't ever occur, as GLD should not send us 34907394Sgdamore@opensolaris.org * packets that are too big. 34917394Sgdamore@opensolaris.org */ 34927394Sgdamore@opensolaris.org HSTAT(erip, oerrors); 34937394Sgdamore@opensolaris.org freemsg(mp); 34947394Sgdamore@opensolaris.org return (B_TRUE); 34956833Sgd78059 } 34966833Sgd78059 34976833Sgd78059 /* 34986833Sgd78059 * update MIB II statistics 34996833Sgd78059 */ 35006833Sgd78059 BUMP_OutNUcast(erip, mp->b_rptr); 35016833Sgd78059 35026833Sgd78059 mutex_enter(&erip->xmitlock); 35036833Sgd78059 35046833Sgd78059 tbasep = erip->eri_tmdp; 35056833Sgd78059 35066833Sgd78059 /* Check if there are enough descriptors for this packet */ 35076833Sgd78059 tmdp = erip->tnextp; 35086833Sgd78059 35096833Sgd78059 if (tmdp >= erip->tcurp) /* check notmds */ 35106833Sgd78059 i = tmdp - erip->tcurp; 35116833Sgd78059 else 35126833Sgd78059 i = tmdp + ERI_TPENDING - erip->tcurp; 35136833Sgd78059 35146833Sgd78059 if (i > (ERI_TPENDING - 4)) 35156833Sgd78059 goto notmds; 35166833Sgd78059 3517*10306SVitezslav.Batrla@Sun.COM if (i >= (ERI_TPENDING >> 1) && !(erip->starts & 0x7)) { 35186833Sgd78059 int_me = ERI_TMD_INTME; 35196833Sgd78059 3520*10306SVitezslav.Batrla@Sun.COM if (!erip->tx_int_me) { 3521*10306SVitezslav.Batrla@Sun.COM PUT_GLOBREG(intmask, GET_GLOBREG(intmask) & 3522*10306SVitezslav.Batrla@Sun.COM ~(ERI_G_MASK_TX_INT_ME)); 3523*10306SVitezslav.Batrla@Sun.COM erip->tx_int_me = 1; 3524*10306SVitezslav.Batrla@Sun.COM } 3525*10306SVitezslav.Batrla@Sun.COM } 3526*10306SVitezslav.Batrla@Sun.COM 35277394Sgdamore@opensolaris.org i = tmdp - tbasep; /* index */ 35287394Sgdamore@opensolaris.org 35297394Sgdamore@opensolaris.org offset = (i * ERI_BUFSIZE); 35307394Sgdamore@opensolaris.org ptr = erip->tbuf_kaddr + offset; 35317394Sgdamore@opensolaris.org 35327394Sgdamore@opensolaris.org mcopymsg(mp, ptr); 35336833Sgd78059 35346833Sgd78059 #ifdef ERI_HDX_BUG_WORKAROUND 35357394Sgdamore@opensolaris.org if ((param_mode) || (eri_hdx_pad_enable == 0)) { 35367394Sgdamore@opensolaris.org if (len_msg < ETHERMIN) { 35377394Sgdamore@opensolaris.org bzero((ptr + len_msg), (ETHERMIN - len_msg)); 35387394Sgdamore@opensolaris.org len_msg = ETHERMIN; 35397394Sgdamore@opensolaris.org } 35407394Sgdamore@opensolaris.org } else { 35417394Sgdamore@opensolaris.org if (len_msg < 97) { 35427394Sgdamore@opensolaris.org bzero((ptr + len_msg), (97 - len_msg)); 35437394Sgdamore@opensolaris.org len_msg = 97; 35447394Sgdamore@opensolaris.org } 35457394Sgdamore@opensolaris.org } 35466833Sgd78059 #endif 35477394Sgdamore@opensolaris.org c.dmac_address = erip->tbuf_ioaddr + offset; 35487394Sgdamore@opensolaris.org (void) ddi_dma_sync(erip->tbuf_handle, 35497394Sgdamore@opensolaris.org (off_t)offset, len_msg, DDI_DMA_SYNC_FORDEV); 35507394Sgdamore@opensolaris.org 35517394Sgdamore@opensolaris.org /* first and last (and only!) descr of packet */ 35527394Sgdamore@opensolaris.org ctrl = ERI_TMD_SOP | ERI_TMD_EOP | int_me | tmdcsum | 35537394Sgdamore@opensolaris.org (start_offset << ERI_TMD_CSSTART_SHIFT) | 35547394Sgdamore@opensolaris.org (stuff_offset << ERI_TMD_CSSTUFF_SHIFT); 35557394Sgdamore@opensolaris.org 35567394Sgdamore@opensolaris.org PUT_TMD(tmdp, c, len_msg, ctrl); 35577394Sgdamore@opensolaris.org ERI_SYNCIOPB(erip, tmdp, sizeof (struct eri_tmd), 35587394Sgdamore@opensolaris.org DDI_DMA_SYNC_FORDEV); 35597394Sgdamore@opensolaris.org 35607394Sgdamore@opensolaris.org tmdp = NEXTTMD(erip, tmdp); 35617394Sgdamore@opensolaris.org erip->tx_cur_cnt++; 35626833Sgd78059 35636833Sgd78059 erip->tx_kick = tmdp - tbasep; 35646833Sgd78059 PUT_ETXREG(tx_kick, erip->tx_kick); 35656833Sgd78059 erip->tnextp = tmdp; 35666833Sgd78059 35676833Sgd78059 erip->starts++; 35686833Sgd78059 35696833Sgd78059 if (erip->tx_cur_cnt >= tx_interrupt_rate) { 35706833Sgd78059 erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) & 35716833Sgd78059 ETX_COMPLETION_MASK); 3572*10306SVitezslav.Batrla@Sun.COM (void) eri_reclaim(erip, erip->tx_completion); 35736833Sgd78059 } 35746833Sgd78059 mutex_exit(&erip->xmitlock); 35756833Sgd78059 35766833Sgd78059 return (B_TRUE); 35776833Sgd78059 35786833Sgd78059 notmds: 35796833Sgd78059 HSTAT(erip, notmds); 35806833Sgd78059 erip->wantw = B_TRUE; 35816833Sgd78059 35826833Sgd78059 mutex_exit(&erip->xmitlock); 35836833Sgd78059 35846833Sgd78059 return (B_FALSE); 35856833Sgd78059 } 35866833Sgd78059 35876833Sgd78059 static mblk_t * 35886833Sgd78059 eri_m_tx(void *arg, mblk_t *mp) 35896833Sgd78059 { 35906833Sgd78059 struct eri *erip = arg; 35916833Sgd78059 mblk_t *next; 35926833Sgd78059 35936833Sgd78059 while (mp != NULL) { 35946833Sgd78059 next = mp->b_next; 35956833Sgd78059 mp->b_next = NULL; 35966833Sgd78059 if (!eri_send_msg(erip, mp)) { 35976833Sgd78059 mp->b_next = next; 35986833Sgd78059 break; 35996833Sgd78059 } 36006833Sgd78059 mp = next; 36016833Sgd78059 } 36026833Sgd78059 36036833Sgd78059 return (mp); 36046833Sgd78059 } 36056833Sgd78059 36066833Sgd78059 /* 36076833Sgd78059 * Transmit completion reclaiming. 36086833Sgd78059 */ 36096833Sgd78059 static boolean_t 36106833Sgd78059 eri_reclaim(struct eri *erip, uint32_t tx_completion) 36116833Sgd78059 { 36126833Sgd78059 volatile struct eri_tmd *tmdp; 36136833Sgd78059 struct eri_tmd *tcomp; 36146833Sgd78059 struct eri_tmd *tbasep; 36156833Sgd78059 struct eri_tmd *tlimp; 36166833Sgd78059 uint64_t flags; 36176833Sgd78059 uint_t reclaimed = 0; 36186833Sgd78059 36196833Sgd78059 tbasep = erip->eri_tmdp; 36206833Sgd78059 tlimp = erip->eri_tmdlimp; 36216833Sgd78059 36226833Sgd78059 tmdp = erip->tcurp; 36236833Sgd78059 tcomp = tbasep + tx_completion; /* pointer to completion tmd */ 36246833Sgd78059 36256833Sgd78059 /* 36266833Sgd78059 * Loop through each TMD starting from tcurp and upto tcomp. 36276833Sgd78059 */ 36286833Sgd78059 while (tmdp != tcomp) { 36296833Sgd78059 flags = GET_TMD_FLAGS(tmdp); 36306833Sgd78059 if (flags & (ERI_TMD_SOP)) 36316833Sgd78059 HSTAT(erip, opackets64); 36326833Sgd78059 36336833Sgd78059 HSTATN(erip, obytes64, (flags & ERI_TMD_BUFSIZE)); 36346833Sgd78059 36356833Sgd78059 tmdp = NEXTTMDP(tbasep, tlimp, tmdp); 36366833Sgd78059 reclaimed++; 36376833Sgd78059 } 36386833Sgd78059 36396833Sgd78059 erip->tcurp = tmdp; 36406833Sgd78059 erip->tx_cur_cnt -= reclaimed; 36416833Sgd78059 36426833Sgd78059 return (erip->wantw && reclaimed ? B_TRUE : B_FALSE); 36436833Sgd78059 } 36446833Sgd78059 36456833Sgd78059 36466833Sgd78059 /* <<<<<<<<<<<<<<<<<<< PACKET RECEIVE FUNCTIONS >>>>>>>>>>>>>>>>>>> */ 36476833Sgd78059 static mblk_t * 36486833Sgd78059 eri_read_dma(struct eri *erip, volatile struct rmd *rmdp, 36496833Sgd78059 int rmdi, uint64_t flags) 36506833Sgd78059 { 36516833Sgd78059 mblk_t *bp, *nbp; 36526833Sgd78059 int len; 36536833Sgd78059 uint_t ccnt; 36546833Sgd78059 ddi_dma_cookie_t c; 36556833Sgd78059 #ifdef ERI_RCV_CKSUM 36566833Sgd78059 ushort_t sum; 36576833Sgd78059 #endif /* ERI_RCV_CKSUM */ 36586833Sgd78059 mblk_t *retmp = NULL; 36596833Sgd78059 36606833Sgd78059 bp = erip->rmblkp[rmdi]; 36616833Sgd78059 len = (flags & ERI_RMD_BUFSIZE) >> ERI_RMD_BUFSIZE_SHIFT; 36626833Sgd78059 #ifdef ERI_DONT_STRIP_CRC 36636833Sgd78059 len -= 4; 36646833Sgd78059 #endif 36656833Sgd78059 /* 36666833Sgd78059 * In the event of RX FIFO overflow error, ERI REV 1.0 ASIC can 36676833Sgd78059 * corrupt packets following the descriptor corresponding the 36686833Sgd78059 * overflow. To detect the corrupted packets, we disable the 36696833Sgd78059 * dropping of the "bad" packets at the MAC. The descriptor 36706833Sgd78059 * then would have the "BAD" bit set. We drop the overflowing 36716833Sgd78059 * packet and the packet following it. We could have done some sort 36726833Sgd78059 * of checking to determine if the second packet was indeed bad 36736833Sgd78059 * (using CRC or checksum) but it would be expensive in this 36746833Sgd78059 * routine, since it is run in interrupt context. 36756833Sgd78059 */ 36766833Sgd78059 if ((flags & ERI_RMD_BAD) || (len < ETHERMIN) || (len > ETHERMAX+4)) { 36776833Sgd78059 36786833Sgd78059 HSTAT(erip, rx_bad_pkts); 36796833Sgd78059 if ((flags & ERI_RMD_BAD) == 0) 36806833Sgd78059 HSTAT(erip, ierrors); 36816833Sgd78059 if (len < ETHERMIN) { 36826833Sgd78059 HSTAT(erip, rx_runt); 36836833Sgd78059 } else if (len > ETHERMAX+4) { 36846833Sgd78059 HSTAT(erip, rx_toolong_pkts); 36856833Sgd78059 } 36866833Sgd78059 HSTAT(erip, drop); 36876833Sgd78059 UPDATE_RMD(rmdp); 36886833Sgd78059 36896833Sgd78059 ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd), 36906833Sgd78059 DDI_DMA_SYNC_FORDEV); 36916833Sgd78059 return (NULL); 36926833Sgd78059 } 36936833Sgd78059 #ifdef ERI_DONT_STRIP_CRC 36946833Sgd78059 { 36956833Sgd78059 uint32_t hw_fcs, tail_fcs; 36966833Sgd78059 /* 36976833Sgd78059 * since we don't let the hardware strip the CRC in hdx 36986833Sgd78059 * then the driver needs to do it. 36996833Sgd78059 * this is to workaround a hardware bug 37006833Sgd78059 */ 37016833Sgd78059 bp->b_wptr = bp->b_rptr + ERI_FSTBYTE_OFFSET + len; 37026833Sgd78059 /* 37036833Sgd78059 * Get the Checksum calculated by the hardware. 37046833Sgd78059 */ 37056833Sgd78059 hw_fcs = flags & ERI_RMD_CKSUM; 37066833Sgd78059 /* 37076833Sgd78059 * Catch the case when the CRC starts on an odd 37086833Sgd78059 * boundary. 37096833Sgd78059 */ 37106833Sgd78059 tail_fcs = bp->b_wptr[0] << 8 | bp->b_wptr[1]; 37116833Sgd78059 tail_fcs += bp->b_wptr[2] << 8 | bp->b_wptr[3]; 37126833Sgd78059 tail_fcs = (tail_fcs & 0xffff) + (tail_fcs >> 16); 37136833Sgd78059 if ((uintptr_t)(bp->b_wptr) & 1) { 37146833Sgd78059 tail_fcs = (tail_fcs << 8) & 0xffff | (tail_fcs >> 8); 37156833Sgd78059 } 37166833Sgd78059 hw_fcs += tail_fcs; 37176833Sgd78059 hw_fcs = (hw_fcs & 0xffff) + (hw_fcs >> 16); 37186833Sgd78059 hw_fcs &= 0xffff; 37196833Sgd78059 /* 37206833Sgd78059 * Now we can replace what the hardware wrote, make believe 37216833Sgd78059 * it got it right in the first place. 37226833Sgd78059 */ 37236833Sgd78059 flags = (flags & ~(uint64_t)ERI_RMD_CKSUM) | hw_fcs; 37246833Sgd78059 } 37256833Sgd78059 #endif 37266833Sgd78059 /* 37276833Sgd78059 * Packet Processing 37286833Sgd78059 * Once we get a packet bp, we try allocate a new mblk, nbp 37296833Sgd78059 * to replace this one. If we succeed, we map it to the current 37306833Sgd78059 * dma handle and update the descriptor with the new cookie. We 37316833Sgd78059 * then put bp in our read service queue erip->ipq, if it exists 37326833Sgd78059 * or we just bp to the streams expecting it. 37336833Sgd78059 * If allocation of the new mblk fails, we implicitly drop the 37346833Sgd78059 * current packet, i.e do not pass up the mblk and re-use it. 37356833Sgd78059 * Re-mapping is not required. 37366833Sgd78059 */ 37376833Sgd78059 37386833Sgd78059 if (len < eri_rx_bcopy_max) { 37396833Sgd78059 if ((nbp = eri_allocb_sp(len + ERI_FSTBYTE_OFFSET))) { 37406833Sgd78059 (void) ddi_dma_sync(erip->ndmarh[rmdi], 0, 37416833Sgd78059 len + ERI_FSTBYTE_OFFSET, DDI_DMA_SYNC_FORCPU); 37426833Sgd78059 DB_TYPE(nbp) = M_DATA; 37436833Sgd78059 bcopy(bp->b_rptr, nbp->b_rptr, 37446833Sgd78059 len + ERI_FSTBYTE_OFFSET); 37456833Sgd78059 UPDATE_RMD(rmdp); 37466833Sgd78059 ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd), 37476833Sgd78059 DDI_DMA_SYNC_FORDEV); 37486833Sgd78059 37496833Sgd78059 /* Add the First Byte offset to the b_rptr */ 37506833Sgd78059 nbp->b_rptr += ERI_FSTBYTE_OFFSET; 37516833Sgd78059 nbp->b_wptr = nbp->b_rptr + len; 37526833Sgd78059 37536833Sgd78059 #ifdef ERI_RCV_CKSUM 37546833Sgd78059 sum = ~(uint16_t)(flags & ERI_RMD_CKSUM); 37556833Sgd78059 ERI_PROCESS_READ(erip, nbp, sum); 37566833Sgd78059 #else 37576833Sgd78059 ERI_PROCESS_READ(erip, nbp); 37586833Sgd78059 #endif 37596833Sgd78059 retmp = nbp; 37606833Sgd78059 } else { 37616833Sgd78059 37626833Sgd78059 /* 37636833Sgd78059 * mblk allocation has failed. Re-use the old mblk for 37646833Sgd78059 * the next packet. Re-mapping is not required since 37656833Sgd78059 * the same mblk and dma cookie is to be used again. 37666833Sgd78059 */ 37676833Sgd78059 HSTAT(erip, ierrors); 37686833Sgd78059 HSTAT(erip, allocbfail); 37696833Sgd78059 HSTAT(erip, norcvbuf); 37706833Sgd78059 37716833Sgd78059 UPDATE_RMD(rmdp); 37726833Sgd78059 ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd), 37736833Sgd78059 DDI_DMA_SYNC_FORDEV); 37746833Sgd78059 ERI_DEBUG_MSG1(erip, RESOURCE_MSG, "allocb fail"); 37756833Sgd78059 } 37766833Sgd78059 } else { 37776833Sgd78059 /* Use dma unmap/map */ 37786833Sgd78059 if ((nbp = eri_allocb_sp(ERI_BUFSIZE))) { 37796833Sgd78059 /* 37806833Sgd78059 * How do we harden this, specially if unbind 37816833Sgd78059 * succeeds and then bind fails? 37826833Sgd78059 * If Unbind fails, we can leave without updating 37836833Sgd78059 * the descriptor but would it continue to work on 37846833Sgd78059 * next round? 37856833Sgd78059 */ 37866833Sgd78059 (void) ddi_dma_unbind_handle(erip->ndmarh[rmdi]); 37876833Sgd78059 (void) ddi_dma_addr_bind_handle(erip->ndmarh[rmdi], 37886833Sgd78059 NULL, (caddr_t)nbp->b_rptr, ERI_BUFSIZE, 37896833Sgd78059 DDI_DMA_READ | DDI_DMA_CONSISTENT, 37906833Sgd78059 DDI_DMA_DONTWAIT, 0, &c, &ccnt); 37916833Sgd78059 37926833Sgd78059 erip->rmblkp[rmdi] = nbp; 37936833Sgd78059 PUT_RMD(rmdp, c); 37946833Sgd78059 ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd), 37956833Sgd78059 DDI_DMA_SYNC_FORDEV); 37966833Sgd78059 37976833Sgd78059 /* Add the First Byte offset to the b_rptr */ 37986833Sgd78059 37996833Sgd78059 bp->b_rptr += ERI_FSTBYTE_OFFSET; 38006833Sgd78059 bp->b_wptr = bp->b_rptr + len; 38016833Sgd78059 38026833Sgd78059 #ifdef ERI_RCV_CKSUM 38036833Sgd78059 sum = ~(uint16_t)(flags & ERI_RMD_CKSUM); 38046833Sgd78059 ERI_PROCESS_READ(erip, bp, sum); 38056833Sgd78059 #else 38066833Sgd78059 ERI_PROCESS_READ(erip, bp); 38076833Sgd78059 #endif 38086833Sgd78059 retmp = bp; 38096833Sgd78059 } else { 38106833Sgd78059 38116833Sgd78059 /* 38126833Sgd78059 * mblk allocation has failed. Re-use the old mblk for 38136833Sgd78059 * the next packet. Re-mapping is not required since 38146833Sgd78059 * the same mblk and dma cookie is to be used again. 38156833Sgd78059 */ 38166833Sgd78059 HSTAT(erip, ierrors); 38176833Sgd78059 HSTAT(erip, allocbfail); 38186833Sgd78059 HSTAT(erip, norcvbuf); 38196833Sgd78059 38206833Sgd78059 UPDATE_RMD(rmdp); 38216833Sgd78059 ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd), 38226833Sgd78059 DDI_DMA_SYNC_FORDEV); 38236833Sgd78059 ERI_DEBUG_MSG1(erip, RESOURCE_MSG, "allocb fail"); 38246833Sgd78059 } 38256833Sgd78059 } 38266833Sgd78059 38276833Sgd78059 return (retmp); 38286833Sgd78059 } 38296833Sgd78059 38306833Sgd78059 #define LINK_STAT_DISPLAY_TIME 20 38316833Sgd78059 38326833Sgd78059 static int 38336833Sgd78059 eri_init_xfer_params(struct eri *erip) 38346833Sgd78059 { 38356833Sgd78059 int i; 38366833Sgd78059 dev_info_t *dip; 38376833Sgd78059 38386833Sgd78059 dip = erip->dip; 38396833Sgd78059 38406833Sgd78059 for (i = 0; i < A_CNT(param_arr); i++) 38416833Sgd78059 erip->param_arr[i] = param_arr[i]; 38426833Sgd78059 38436833Sgd78059 erip->xmit_dma_mode = 0; 38446833Sgd78059 erip->rcv_dma_mode = 0; 38456833Sgd78059 erip->mifpoll_enable = mifpoll_enable; 38466833Sgd78059 erip->lance_mode_enable = lance_mode; 38476833Sgd78059 erip->frame_enable = 1; 38486833Sgd78059 erip->ngu_enable = ngu_enable; 38496833Sgd78059 38506833Sgd78059 if (!erip->g_nd && !eri_param_register(erip, 38516833Sgd78059 erip->param_arr, A_CNT(param_arr))) { 38526833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG, 38536833Sgd78059 param_reg_fail_msg); 38546833Sgd78059 return (-1); 38556833Sgd78059 } 38566833Sgd78059 38576833Sgd78059 /* 38586833Sgd78059 * Set up the start-up values for user-configurable parameters 38596833Sgd78059 * Get the values from the global variables first. 38606833Sgd78059 * Use the MASK to limit the value to allowed maximum. 38616833Sgd78059 */ 38626833Sgd78059 38636833Sgd78059 param_transceiver = NO_XCVR; 38646833Sgd78059 38656833Sgd78059 /* 38666833Sgd78059 * The link speed may be forced to either 10 Mbps or 100 Mbps using the 38676833Sgd78059 * property "transfer-speed". This may be done in OBP by using the command 38686833Sgd78059 * "apply transfer-speed=<speed> <device>". The speed may be either 10 or 100. 38696833Sgd78059 */ 38706833Sgd78059 i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "transfer-speed", 0); 38716833Sgd78059 if (i != 0) { 38726833Sgd78059 param_autoneg = 0; /* force speed */ 38736833Sgd78059 param_anar_100T4 = 0; 38746833Sgd78059 param_anar_10fdx = 0; 38756833Sgd78059 param_anar_10hdx = 0; 38766833Sgd78059 param_anar_100fdx = 0; 38776833Sgd78059 param_anar_100hdx = 0; 38786833Sgd78059 param_anar_asm_dir = 0; 38796833Sgd78059 param_anar_pause = 0; 38806833Sgd78059 38816833Sgd78059 if (i == 10) 38826833Sgd78059 param_anar_10hdx = 1; 38836833Sgd78059 else if (i == 100) 38846833Sgd78059 param_anar_100hdx = 1; 38856833Sgd78059 } 38866833Sgd78059 38876833Sgd78059 /* 38886833Sgd78059 * Get the parameter values configured in .conf file. 38896833Sgd78059 */ 38906833Sgd78059 param_ipg1 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg1", ipg1) & 38916833Sgd78059 ERI_MASK_8BIT; 38926833Sgd78059 38936833Sgd78059 param_ipg2 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg2", ipg2) & 38946833Sgd78059 ERI_MASK_8BIT; 38956833Sgd78059 38966833Sgd78059 param_use_intphy = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 38976833Sgd78059 "use_int_xcvr", use_int_xcvr) & ERI_MASK_1BIT; 38986833Sgd78059 38996833Sgd78059 param_use_intphy = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39006833Sgd78059 "pace_size", pace_size) & ERI_MASK_8BIT; 39016833Sgd78059 39026833Sgd78059 param_autoneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39036833Sgd78059 "adv_autoneg_cap", adv_autoneg_cap) & ERI_MASK_1BIT; 39046833Sgd78059 39056833Sgd78059 param_autoneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39066833Sgd78059 "adv_autoneg_cap", adv_autoneg_cap) & ERI_MASK_1BIT; 39076833Sgd78059 39086833Sgd78059 param_anar_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39096833Sgd78059 "adv_100T4_cap", adv_100T4_cap) & ERI_MASK_1BIT; 39106833Sgd78059 39116833Sgd78059 param_anar_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39126833Sgd78059 "adv_100fdx_cap", adv_100fdx_cap) & ERI_MASK_1BIT; 39136833Sgd78059 39146833Sgd78059 param_anar_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39156833Sgd78059 "adv_100hdx_cap", adv_100hdx_cap) & ERI_MASK_1BIT; 39166833Sgd78059 39176833Sgd78059 param_anar_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39186833Sgd78059 "adv_10fdx_cap", adv_10fdx_cap) & ERI_MASK_1BIT; 39196833Sgd78059 39206833Sgd78059 param_anar_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39216833Sgd78059 "adv_10hdx_cap", adv_10hdx_cap) & ERI_MASK_1BIT; 39226833Sgd78059 39236833Sgd78059 param_ipg0 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg0", ipg0) & 39246833Sgd78059 ERI_MASK_8BIT; 39256833Sgd78059 39266833Sgd78059 param_intr_blank_time = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39276833Sgd78059 "intr_blank_time", intr_blank_time) & ERI_MASK_8BIT; 39286833Sgd78059 39296833Sgd78059 param_intr_blank_packets = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39306833Sgd78059 "intr_blank_packets", intr_blank_packets) & ERI_MASK_8BIT; 39316833Sgd78059 39326833Sgd78059 param_lance_mode = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39336833Sgd78059 "lance_mode", lance_mode) & ERI_MASK_1BIT; 39346833Sgd78059 39356833Sgd78059 param_select_link = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39366833Sgd78059 "select_link", select_link) & ERI_MASK_1BIT; 39376833Sgd78059 39386833Sgd78059 param_default_link = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39396833Sgd78059 "default_link", default_link) & ERI_MASK_1BIT; 39406833Sgd78059 39416833Sgd78059 param_anar_asm_dir = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39426833Sgd78059 "adv_asm_dir_cap", adv_pauseTX_cap) & ERI_MASK_1BIT; 39436833Sgd78059 39446833Sgd78059 param_anar_pause = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 39456833Sgd78059 "adv_pause_cap", adv_pauseRX_cap) & ERI_MASK_1BIT; 39466833Sgd78059 39476833Sgd78059 if (link_pulse_disabled) 39486833Sgd78059 erip->link_pulse_disabled = 1; 39496833Sgd78059 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 0, "link-pulse-disabled")) 39506833Sgd78059 erip->link_pulse_disabled = 1; 39516833Sgd78059 39526833Sgd78059 eri_statinit(erip); 39536833Sgd78059 return (0); 39546833Sgd78059 39556833Sgd78059 } 39566833Sgd78059 39576833Sgd78059 static void 39586833Sgd78059 eri_process_ndd_ioctl(struct eri *erip, queue_t *wq, mblk_t *mp, int cmd) 39596833Sgd78059 { 39606833Sgd78059 39616833Sgd78059 uint32_t old_ipg1, old_ipg2, old_use_int_xcvr, old_autoneg; 39626833Sgd78059 uint32_t old_100T4; 39636833Sgd78059 uint32_t old_100fdx, old_100hdx, old_10fdx, old_10hdx; 39646833Sgd78059 uint32_t old_ipg0, old_lance_mode; 39656833Sgd78059 uint32_t old_intr_blank_time, old_intr_blank_packets; 39666833Sgd78059 uint32_t old_asm_dir, old_pause; 39676833Sgd78059 uint32_t old_select_link, old_default_link; 39686833Sgd78059 39696833Sgd78059 switch (cmd) { 39706833Sgd78059 case ERI_ND_GET: 39716833Sgd78059 39726833Sgd78059 old_autoneg = param_autoneg; 39736833Sgd78059 old_100T4 = param_anar_100T4; 39746833Sgd78059 old_100fdx = param_anar_100fdx; 39756833Sgd78059 old_100hdx = param_anar_100hdx; 39766833Sgd78059 old_10fdx = param_anar_10fdx; 39776833Sgd78059 old_10hdx = param_anar_10hdx; 39786833Sgd78059 old_asm_dir = param_anar_asm_dir; 39796833Sgd78059 old_pause = param_anar_pause; 39806833Sgd78059 39816833Sgd78059 param_autoneg = old_autoneg & ~ERI_NOTUSR; 39826833Sgd78059 param_anar_100T4 = old_100T4 & ~ERI_NOTUSR; 39836833Sgd78059 param_anar_100fdx = old_100fdx & ~ERI_NOTUSR; 39846833Sgd78059 param_anar_100hdx = old_100hdx & ~ERI_NOTUSR; 39856833Sgd78059 param_anar_10fdx = old_10fdx & ~ERI_NOTUSR; 39866833Sgd78059 param_anar_10hdx = old_10hdx & ~ERI_NOTUSR; 39876833Sgd78059 param_anar_asm_dir = old_asm_dir & ~ERI_NOTUSR; 39886833Sgd78059 param_anar_pause = old_pause & ~ERI_NOTUSR; 39896833Sgd78059 39906833Sgd78059 if (!eri_nd_getset(wq, erip->g_nd, mp)) { 39916833Sgd78059 param_autoneg = old_autoneg; 39926833Sgd78059 param_anar_100T4 = old_100T4; 39936833Sgd78059 param_anar_100fdx = old_100fdx; 39946833Sgd78059 param_anar_100hdx = old_100hdx; 39956833Sgd78059 param_anar_10fdx = old_10fdx; 39966833Sgd78059 param_anar_10hdx = old_10hdx; 39976833Sgd78059 param_anar_asm_dir = old_asm_dir; 39986833Sgd78059 param_anar_pause = old_pause; 39996833Sgd78059 miocnak(wq, mp, 0, EINVAL); 40006833Sgd78059 return; 40016833Sgd78059 } 40026833Sgd78059 param_autoneg = old_autoneg; 40036833Sgd78059 param_anar_100T4 = old_100T4; 40046833Sgd78059 param_anar_100fdx = old_100fdx; 40056833Sgd78059 param_anar_100hdx = old_100hdx; 40066833Sgd78059 param_anar_10fdx = old_10fdx; 40076833Sgd78059 param_anar_10hdx = old_10hdx; 40086833Sgd78059 param_anar_asm_dir = old_asm_dir; 40096833Sgd78059 param_anar_pause = old_pause; 40106833Sgd78059 40116833Sgd78059 qreply(wq, mp); 40126833Sgd78059 break; 40136833Sgd78059 40146833Sgd78059 case ERI_ND_SET: 40156833Sgd78059 old_ipg0 = param_ipg0; 40166833Sgd78059 old_intr_blank_time = param_intr_blank_time; 40176833Sgd78059 old_intr_blank_packets = param_intr_blank_packets; 40186833Sgd78059 old_lance_mode = param_lance_mode; 40196833Sgd78059 old_ipg1 = param_ipg1; 40206833Sgd78059 old_ipg2 = param_ipg2; 40216833Sgd78059 old_use_int_xcvr = param_use_intphy; 40226833Sgd78059 old_autoneg = param_autoneg; 40236833Sgd78059 old_100T4 = param_anar_100T4; 40246833Sgd78059 old_100fdx = param_anar_100fdx; 40256833Sgd78059 old_100hdx = param_anar_100hdx; 40266833Sgd78059 old_10fdx = param_anar_10fdx; 40276833Sgd78059 old_10hdx = param_anar_10hdx; 40286833Sgd78059 param_autoneg = 0xff; 40296833Sgd78059 old_asm_dir = param_anar_asm_dir; 40306833Sgd78059 param_anar_asm_dir = 0xff; 40316833Sgd78059 old_pause = param_anar_pause; 40326833Sgd78059 param_anar_pause = 0xff; 40336833Sgd78059 old_select_link = param_select_link; 40346833Sgd78059 old_default_link = param_default_link; 40356833Sgd78059 40366833Sgd78059 if (!eri_nd_getset(wq, erip->g_nd, mp)) { 40376833Sgd78059 param_autoneg = old_autoneg; 40386833Sgd78059 miocnak(wq, mp, 0, EINVAL); 40396833Sgd78059 return; 40406833Sgd78059 } 40416833Sgd78059 40426833Sgd78059 qreply(wq, mp); 40436833Sgd78059 40446833Sgd78059 if (param_autoneg != 0xff) { 40456833Sgd78059 ERI_DEBUG_MSG2(erip, NDD_MSG, 40466833Sgd78059 "ndd_ioctl: new param_autoneg %d", param_autoneg); 40476833Sgd78059 param_linkup = 0; 40486833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 40496833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 40506833Sgd78059 (void) eri_init(erip); 40516833Sgd78059 } else { 40526833Sgd78059 param_autoneg = old_autoneg; 40536833Sgd78059 if ((old_use_int_xcvr != param_use_intphy) || 40546833Sgd78059 (old_default_link != param_default_link) || 40556833Sgd78059 (old_select_link != param_select_link)) { 40566833Sgd78059 param_linkup = 0; 40576833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 40586833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 40596833Sgd78059 (void) eri_init(erip); 40606833Sgd78059 } else if ((old_ipg1 != param_ipg1) || 40616833Sgd78059 (old_ipg2 != param_ipg2) || 40626833Sgd78059 (old_ipg0 != param_ipg0) || 40636833Sgd78059 (old_intr_blank_time != param_intr_blank_time) || 40646833Sgd78059 (old_intr_blank_packets != 40656833Sgd78059 param_intr_blank_packets) || 40666833Sgd78059 (old_lance_mode != param_lance_mode)) { 40676833Sgd78059 param_linkup = 0; 40686833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 40696833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 40706833Sgd78059 (void) eri_init(erip); 40716833Sgd78059 } 40726833Sgd78059 } 40736833Sgd78059 break; 40746833Sgd78059 } 40756833Sgd78059 } 40766833Sgd78059 40776833Sgd78059 40786833Sgd78059 static int 40796833Sgd78059 eri_stat_kstat_update(kstat_t *ksp, int rw) 40806833Sgd78059 { 40816833Sgd78059 struct eri *erip; 40826833Sgd78059 struct erikstat *erikp; 40836833Sgd78059 struct stats *esp; 40846833Sgd78059 boolean_t macupdate = B_FALSE; 40856833Sgd78059 40866833Sgd78059 erip = (struct eri *)ksp->ks_private; 40876833Sgd78059 erikp = (struct erikstat *)ksp->ks_data; 40886833Sgd78059 40896833Sgd78059 if (rw != KSTAT_READ) 40906833Sgd78059 return (EACCES); 40916833Sgd78059 /* 40926833Sgd78059 * Update all the stats by reading all the counter registers. 40936833Sgd78059 * Counter register stats are not updated till they overflow 40946833Sgd78059 * and interrupt. 40956833Sgd78059 */ 40966833Sgd78059 40976833Sgd78059 mutex_enter(&erip->xmitlock); 40986833Sgd78059 if ((erip->flags & ERI_RUNNING) && (erip->flags & ERI_TXINIT)) { 40996833Sgd78059 erip->tx_completion = 41006833Sgd78059 GET_ETXREG(tx_completion) & ETX_COMPLETION_MASK; 41016833Sgd78059 macupdate |= eri_reclaim(erip, erip->tx_completion); 41026833Sgd78059 } 41036833Sgd78059 mutex_exit(&erip->xmitlock); 41046833Sgd78059 if (macupdate) 41056833Sgd78059 mac_tx_update(erip->mh); 41066833Sgd78059 41076833Sgd78059 eri_savecntrs(erip); 41086833Sgd78059 41096833Sgd78059 esp = &erip->stats; 41106833Sgd78059 41116833Sgd78059 erikp->erik_txmac_maxpkt_err.value.ul = esp->txmac_maxpkt_err; 41126833Sgd78059 erikp->erik_defer_timer_exp.value.ul = esp->defer_timer_exp; 41136833Sgd78059 erikp->erik_peak_attempt_cnt.value.ul = esp->peak_attempt_cnt; 41146833Sgd78059 erikp->erik_tx_hang.value.ul = esp->tx_hang; 41156833Sgd78059 41166833Sgd78059 erikp->erik_no_free_rx_desc.value.ul = esp->no_free_rx_desc; 41176833Sgd78059 41186833Sgd78059 erikp->erik_rx_hang.value.ul = esp->rx_hang; 41196833Sgd78059 erikp->erik_rx_length_err.value.ul = esp->rx_length_err; 41206833Sgd78059 erikp->erik_rx_code_viol_err.value.ul = esp->rx_code_viol_err; 41216833Sgd78059 erikp->erik_pause_rxcount.value.ul = esp->pause_rxcount; 41226833Sgd78059 erikp->erik_pause_oncount.value.ul = esp->pause_oncount; 41236833Sgd78059 erikp->erik_pause_offcount.value.ul = esp->pause_offcount; 41246833Sgd78059 erikp->erik_pause_time_count.value.ul = esp->pause_time_count; 41256833Sgd78059 41266833Sgd78059 erikp->erik_inits.value.ul = esp->inits; 41276833Sgd78059 erikp->erik_jab.value.ul = esp->jab; 41286833Sgd78059 erikp->erik_notmds.value.ul = esp->notmds; 41296833Sgd78059 erikp->erik_allocbfail.value.ul = esp->allocbfail; 41306833Sgd78059 erikp->erik_drop.value.ul = esp->drop; 41316833Sgd78059 erikp->erik_rx_bad_pkts.value.ul = esp->rx_bad_pkts; 41326833Sgd78059 erikp->erik_rx_inits.value.ul = esp->rx_inits; 41336833Sgd78059 erikp->erik_tx_inits.value.ul = esp->tx_inits; 41346833Sgd78059 erikp->erik_rxtag_err.value.ul = esp->rxtag_err; 41356833Sgd78059 erikp->erik_parity_error.value.ul = esp->parity_error; 41366833Sgd78059 erikp->erik_pci_error_int.value.ul = esp->pci_error_int; 41376833Sgd78059 erikp->erik_unknown_fatal.value.ul = esp->unknown_fatal; 41386833Sgd78059 erikp->erik_pci_data_parity_err.value.ul = esp->pci_data_parity_err; 41396833Sgd78059 erikp->erik_pci_signal_target_abort.value.ul = 41406833Sgd78059 esp->pci_signal_target_abort; 41416833Sgd78059 erikp->erik_pci_rcvd_target_abort.value.ul = 41426833Sgd78059 esp->pci_rcvd_target_abort; 41436833Sgd78059 erikp->erik_pci_rcvd_master_abort.value.ul = 41446833Sgd78059 esp->pci_rcvd_master_abort; 41456833Sgd78059 erikp->erik_pci_signal_system_err.value.ul = 41466833Sgd78059 esp->pci_signal_system_err; 41476833Sgd78059 erikp->erik_pci_det_parity_err.value.ul = esp->pci_det_parity_err; 41486833Sgd78059 41496833Sgd78059 erikp->erik_pmcap.value.ul = esp->pmcap; 41506833Sgd78059 41516833Sgd78059 return (0); 41526833Sgd78059 } 41536833Sgd78059 41546833Sgd78059 static void 41556833Sgd78059 eri_statinit(struct eri *erip) 41566833Sgd78059 { 41576833Sgd78059 struct kstat *ksp; 41586833Sgd78059 struct erikstat *erikp; 41596833Sgd78059 41606833Sgd78059 if ((ksp = kstat_create("eri", erip->instance, "driver_info", "net", 41616833Sgd78059 KSTAT_TYPE_NAMED, 41626833Sgd78059 sizeof (struct erikstat) / sizeof (kstat_named_t), 0)) == NULL) { 41636833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG, 41646833Sgd78059 kstat_create_fail_msg); 41656833Sgd78059 return; 41666833Sgd78059 } 41676833Sgd78059 41686833Sgd78059 erip->ksp = ksp; 41696833Sgd78059 erikp = (struct erikstat *)(ksp->ks_data); 41706833Sgd78059 /* 41716833Sgd78059 * MIB II kstat variables 41726833Sgd78059 */ 41736833Sgd78059 41746833Sgd78059 kstat_named_init(&erikp->erik_inits, "inits", KSTAT_DATA_ULONG); 41756833Sgd78059 41766833Sgd78059 kstat_named_init(&erikp->erik_txmac_maxpkt_err, "txmac_maxpkt_err", 41776833Sgd78059 KSTAT_DATA_ULONG); 41786833Sgd78059 kstat_named_init(&erikp->erik_defer_timer_exp, "defer_timer_exp", 41796833Sgd78059 KSTAT_DATA_ULONG); 41806833Sgd78059 kstat_named_init(&erikp->erik_peak_attempt_cnt, "peak_attempt_cnt", 41816833Sgd78059 KSTAT_DATA_ULONG); 41826833Sgd78059 kstat_named_init(&erikp->erik_tx_hang, "tx_hang", KSTAT_DATA_ULONG); 41836833Sgd78059 41846833Sgd78059 kstat_named_init(&erikp->erik_no_free_rx_desc, "no_free_rx_desc", 41856833Sgd78059 KSTAT_DATA_ULONG); 41866833Sgd78059 kstat_named_init(&erikp->erik_rx_hang, "rx_hang", KSTAT_DATA_ULONG); 41876833Sgd78059 kstat_named_init(&erikp->erik_rx_length_err, "rx_length_err", 41886833Sgd78059 KSTAT_DATA_ULONG); 41896833Sgd78059 kstat_named_init(&erikp->erik_rx_code_viol_err, "rx_code_viol_err", 41906833Sgd78059 KSTAT_DATA_ULONG); 41916833Sgd78059 41926833Sgd78059 kstat_named_init(&erikp->erik_pause_rxcount, "pause_rcv_cnt", 41936833Sgd78059 KSTAT_DATA_ULONG); 41946833Sgd78059 41956833Sgd78059 kstat_named_init(&erikp->erik_pause_oncount, "pause_on_cnt", 41966833Sgd78059 KSTAT_DATA_ULONG); 41976833Sgd78059 41986833Sgd78059 kstat_named_init(&erikp->erik_pause_offcount, "pause_off_cnt", 41996833Sgd78059 KSTAT_DATA_ULONG); 42006833Sgd78059 kstat_named_init(&erikp->erik_pause_time_count, "pause_time_cnt", 42016833Sgd78059 KSTAT_DATA_ULONG); 42026833Sgd78059 42036833Sgd78059 kstat_named_init(&erikp->erik_jab, "jabber", KSTAT_DATA_ULONG); 42046833Sgd78059 kstat_named_init(&erikp->erik_notmds, "no_tmds", KSTAT_DATA_ULONG); 42056833Sgd78059 kstat_named_init(&erikp->erik_allocbfail, "allocbfail", 42066833Sgd78059 KSTAT_DATA_ULONG); 42076833Sgd78059 42086833Sgd78059 kstat_named_init(&erikp->erik_drop, "drop", KSTAT_DATA_ULONG); 42096833Sgd78059 42106833Sgd78059 kstat_named_init(&erikp->erik_rx_bad_pkts, "bad_pkts", 42116833Sgd78059 KSTAT_DATA_ULONG); 42126833Sgd78059 42136833Sgd78059 kstat_named_init(&erikp->erik_rx_inits, "rx_inits", KSTAT_DATA_ULONG); 42146833Sgd78059 42156833Sgd78059 kstat_named_init(&erikp->erik_tx_inits, "tx_inits", KSTAT_DATA_ULONG); 42166833Sgd78059 42176833Sgd78059 kstat_named_init(&erikp->erik_rxtag_err, "rxtag_error", 42186833Sgd78059 KSTAT_DATA_ULONG); 42196833Sgd78059 42206833Sgd78059 kstat_named_init(&erikp->erik_parity_error, "parity_error", 42216833Sgd78059 KSTAT_DATA_ULONG); 42226833Sgd78059 42236833Sgd78059 kstat_named_init(&erikp->erik_pci_error_int, "pci_error_interrupt", 42246833Sgd78059 KSTAT_DATA_ULONG); 42256833Sgd78059 kstat_named_init(&erikp->erik_unknown_fatal, "unknown_fatal", 42266833Sgd78059 KSTAT_DATA_ULONG); 42276833Sgd78059 kstat_named_init(&erikp->erik_pci_data_parity_err, 42286833Sgd78059 "pci_data_parity_err", KSTAT_DATA_ULONG); 42296833Sgd78059 kstat_named_init(&erikp->erik_pci_signal_target_abort, 42306833Sgd78059 "pci_signal_target_abort", KSTAT_DATA_ULONG); 42316833Sgd78059 kstat_named_init(&erikp->erik_pci_rcvd_target_abort, 42326833Sgd78059 "pci_rcvd_target_abort", KSTAT_DATA_ULONG); 42336833Sgd78059 kstat_named_init(&erikp->erik_pci_rcvd_master_abort, 42346833Sgd78059 "pci_rcvd_master_abort", KSTAT_DATA_ULONG); 42356833Sgd78059 kstat_named_init(&erikp->erik_pci_signal_system_err, 42366833Sgd78059 "pci_signal_system_err", KSTAT_DATA_ULONG); 42376833Sgd78059 kstat_named_init(&erikp->erik_pci_det_parity_err, 42386833Sgd78059 "pci_det_parity_err", KSTAT_DATA_ULONG); 42396833Sgd78059 42406833Sgd78059 kstat_named_init(&erikp->erik_pmcap, "pmcap", KSTAT_DATA_ULONG); 42416833Sgd78059 42426833Sgd78059 42436833Sgd78059 ksp->ks_update = eri_stat_kstat_update; 42446833Sgd78059 ksp->ks_private = (void *) erip; 42456833Sgd78059 kstat_install(ksp); 42466833Sgd78059 } 42476833Sgd78059 42486833Sgd78059 42496833Sgd78059 /* <<<<<<<<<<<<<<<<<<<<<<< NDD SUPPORT FUNCTIONS >>>>>>>>>>>>>>>>>>> */ 42506833Sgd78059 /* 42516833Sgd78059 * ndd support functions to get/set parameters 42526833Sgd78059 */ 42536833Sgd78059 /* Free the Named Dispatch Table by calling eri_nd_free */ 42546833Sgd78059 static void 42556833Sgd78059 eri_param_cleanup(struct eri *erip) 42566833Sgd78059 { 42576833Sgd78059 if (erip->g_nd) 42586833Sgd78059 (void) eri_nd_free(&erip->g_nd); 42596833Sgd78059 } 42606833Sgd78059 42616833Sgd78059 /* 42626833Sgd78059 * Extracts the value from the eri parameter array and prints the 42636833Sgd78059 * parameter value. cp points to the required parameter. 42646833Sgd78059 */ 42656833Sgd78059 /* ARGSUSED */ 42666833Sgd78059 static int 42676833Sgd78059 eri_param_get(queue_t *q, mblk_t *mp, caddr_t cp) 42686833Sgd78059 { 42696833Sgd78059 param_t *eripa = (void *)cp; 42706833Sgd78059 int param_len = 1; 42716833Sgd78059 uint32_t param_val; 42726833Sgd78059 mblk_t *nmp; 42736833Sgd78059 int ok; 42746833Sgd78059 42756833Sgd78059 param_val = eripa->param_val; 42766833Sgd78059 /* 42776833Sgd78059 * Calculate space required in mblk. 42786833Sgd78059 * Remember to include NULL terminator. 42796833Sgd78059 */ 42806833Sgd78059 do { 42816833Sgd78059 param_len++; 42826833Sgd78059 param_val /= 10; 42836833Sgd78059 } while (param_val); 42846833Sgd78059 42856833Sgd78059 ok = eri_mk_mblk_tail_space(mp, &nmp, param_len); 42866833Sgd78059 if (ok == 0) { 42876833Sgd78059 (void) sprintf((char *)nmp->b_wptr, "%d", eripa->param_val); 42886833Sgd78059 nmp->b_wptr += param_len; 42896833Sgd78059 } 42906833Sgd78059 42916833Sgd78059 return (ok); 42926833Sgd78059 } 42936833Sgd78059 42946833Sgd78059 /* 42956833Sgd78059 * Check if there is space for p_val at the end if mblk. 42966833Sgd78059 * If not, allocate new 1k mblk. 42976833Sgd78059 */ 42986833Sgd78059 static int 42996833Sgd78059 eri_mk_mblk_tail_space(mblk_t *mp, mblk_t **nmp, size_t sz) 43006833Sgd78059 { 43016833Sgd78059 mblk_t *tmp = mp; 43026833Sgd78059 43036833Sgd78059 while (tmp->b_cont) 43046833Sgd78059 tmp = tmp->b_cont; 43056833Sgd78059 43066833Sgd78059 if (MBLKTAIL(tmp) < sz) { 43076833Sgd78059 if ((tmp->b_cont = allocb(1024, BPRI_HI)) == NULL) 43086833Sgd78059 return (ENOMEM); 43096833Sgd78059 tmp = tmp->b_cont; 43106833Sgd78059 } 43116833Sgd78059 *nmp = tmp; 43126833Sgd78059 return (0); 43136833Sgd78059 } 43146833Sgd78059 43156833Sgd78059 /* 43166833Sgd78059 * Register each element of the parameter array with the 43176833Sgd78059 * named dispatch handler. Each element is loaded using 43186833Sgd78059 * eri_nd_load() 43196833Sgd78059 */ 43206833Sgd78059 static int 43216833Sgd78059 eri_param_register(struct eri *erip, param_t *eripa, int cnt) 43226833Sgd78059 { 43236833Sgd78059 /* cnt gives the count of the number of */ 43246833Sgd78059 /* elements present in the parameter array */ 43256833Sgd78059 43266833Sgd78059 int i; 43276833Sgd78059 43286833Sgd78059 for (i = 0; i < cnt; i++, eripa++) { 43296833Sgd78059 pfi_t setter = (pfi_t)eri_param_set; 43306833Sgd78059 43316833Sgd78059 switch (eripa->param_name[0]) { 43326833Sgd78059 case '+': /* read-write */ 43336833Sgd78059 setter = (pfi_t)eri_param_set; 43346833Sgd78059 break; 43356833Sgd78059 43366833Sgd78059 case '-': /* read-only */ 43376833Sgd78059 setter = NULL; 43386833Sgd78059 break; 43396833Sgd78059 43406833Sgd78059 case '!': /* read-only, not displayed */ 43416833Sgd78059 case '%': /* read-write, not displayed */ 43426833Sgd78059 continue; 43436833Sgd78059 } 43446833Sgd78059 43456833Sgd78059 if (!eri_nd_load(&erip->g_nd, eripa->param_name + 1, 43466833Sgd78059 (pfi_t)eri_param_get, setter, (caddr_t)eripa)) { 43476833Sgd78059 (void) eri_nd_free(&erip->g_nd); 43486833Sgd78059 return (B_FALSE); 43496833Sgd78059 } 43506833Sgd78059 } 43516833Sgd78059 43526833Sgd78059 return (B_TRUE); 43536833Sgd78059 } 43546833Sgd78059 43556833Sgd78059 /* 43566833Sgd78059 * Sets the eri parameter to the value in the param_register using 43576833Sgd78059 * eri_nd_load(). 43586833Sgd78059 */ 43596833Sgd78059 /* ARGSUSED */ 43606833Sgd78059 static int 43616833Sgd78059 eri_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp) 43626833Sgd78059 { 43636833Sgd78059 char *end; 43646833Sgd78059 long new_value; 43656833Sgd78059 param_t *eripa = (void *)cp; 43666833Sgd78059 43676833Sgd78059 if (ddi_strtol(value, &end, 10, &new_value) != 0) 43686833Sgd78059 return (EINVAL); 43696833Sgd78059 if (end == value || new_value < eripa->param_min || 43706833Sgd78059 new_value > eripa->param_max) { 43716833Sgd78059 return (EINVAL); 43726833Sgd78059 } 43736833Sgd78059 eripa->param_val = (uint32_t)new_value; 43746833Sgd78059 return (0); 43756833Sgd78059 43766833Sgd78059 } 43776833Sgd78059 43786833Sgd78059 /* Free the table pointed to by 'ndp' */ 43796833Sgd78059 static void 43806833Sgd78059 eri_nd_free(caddr_t *nd_pparam) 43816833Sgd78059 { 43826833Sgd78059 ND *nd; 43836833Sgd78059 43846833Sgd78059 if ((nd = (void *)(*nd_pparam)) != NULL) { 43856833Sgd78059 if (nd->nd_tbl) 43866833Sgd78059 kmem_free(nd->nd_tbl, nd->nd_size); 43876833Sgd78059 kmem_free(nd, sizeof (ND)); 43886833Sgd78059 *nd_pparam = NULL; 43896833Sgd78059 } 43906833Sgd78059 } 43916833Sgd78059 43926833Sgd78059 static int 43936833Sgd78059 eri_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp) 43946833Sgd78059 { 43956833Sgd78059 int err; 43966833Sgd78059 IOCP iocp; 43976833Sgd78059 MBLKP mp1; 43986833Sgd78059 ND *nd; 43996833Sgd78059 NDE *nde; 44006833Sgd78059 char *valp; 44016833Sgd78059 size_t avail; 44026833Sgd78059 mblk_t *nmp; 44036833Sgd78059 44046833Sgd78059 if (!nd_param) 44056833Sgd78059 return (B_FALSE); 44066833Sgd78059 44076833Sgd78059 nd = (void *)nd_param; 44086833Sgd78059 iocp = (void *)mp->b_rptr; 44096833Sgd78059 if ((iocp->ioc_count == 0) || !(mp1 = mp->b_cont)) { 44106833Sgd78059 mp->b_datap->db_type = M_IOCACK; 44116833Sgd78059 iocp->ioc_count = 0; 44126833Sgd78059 iocp->ioc_error = EINVAL; 44136833Sgd78059 return (B_TRUE); 44146833Sgd78059 } 44156833Sgd78059 /* 44166833Sgd78059 * NOTE - logic throughout nd_xxx assumes single data block for ioctl. 44176833Sgd78059 * However, existing code sends in some big buffers. 44186833Sgd78059 */ 44196833Sgd78059 avail = iocp->ioc_count; 44206833Sgd78059 if (mp1->b_cont) { 44216833Sgd78059 freemsg(mp1->b_cont); 44226833Sgd78059 mp1->b_cont = NULL; 44236833Sgd78059 } 44246833Sgd78059 44256833Sgd78059 mp1->b_datap->db_lim[-1] = '\0'; /* Force null termination */ 44266833Sgd78059 valp = (char *)mp1->b_rptr; 44276833Sgd78059 44286833Sgd78059 for (nde = nd->nd_tbl; /* */; nde++) { 44296833Sgd78059 if (!nde->nde_name) 44306833Sgd78059 return (B_FALSE); 44316833Sgd78059 if (strcmp(nde->nde_name, valp) == 0) 44326833Sgd78059 break; 44336833Sgd78059 } 44346833Sgd78059 err = EINVAL; 44356833Sgd78059 44366833Sgd78059 while (*valp++) 44376833Sgd78059 ; 44386833Sgd78059 44396833Sgd78059 if (!*valp || valp >= (char *)mp1->b_wptr) 44406833Sgd78059 valp = NULL; 44416833Sgd78059 44426833Sgd78059 switch (iocp->ioc_cmd) { 44436833Sgd78059 case ND_GET: 44446833Sgd78059 /* 44456833Sgd78059 * (XXX) hack: "*valp" is size of user buffer for copyout. If result 44466833Sgd78059 * of action routine is too big, free excess and return ioc_rval as buf 44476833Sgd78059 * size needed. Return as many mblocks as will fit, free the rest. For 44486833Sgd78059 * backward compatibility, assume size of orig ioctl buffer if "*valp" 44496833Sgd78059 * bad or not given. 44506833Sgd78059 */ 44516833Sgd78059 if (valp) 44526833Sgd78059 (void) ddi_strtol(valp, NULL, 10, (long *)&avail); 44536833Sgd78059 /* We overwrite the name/value with the reply data */ 44546833Sgd78059 { 44556833Sgd78059 mblk_t *mp2 = mp1; 44566833Sgd78059 44576833Sgd78059 while (mp2) { 44586833Sgd78059 mp2->b_wptr = mp2->b_rptr; 44596833Sgd78059 mp2 = mp2->b_cont; 44606833Sgd78059 } 44616833Sgd78059 } 44626833Sgd78059 err = (*nde->nde_get_pfi)(q, mp1, nde->nde_data, iocp->ioc_cr); 44636833Sgd78059 if (!err) { 44646833Sgd78059 size_t size_out; 44656833Sgd78059 ssize_t excess; 44666833Sgd78059 44676833Sgd78059 iocp->ioc_rval = 0; 44686833Sgd78059 44696833Sgd78059 /* Tack on the null */ 44706833Sgd78059 err = eri_mk_mblk_tail_space(mp1, &nmp, 1); 44716833Sgd78059 if (!err) { 44726833Sgd78059 *nmp->b_wptr++ = '\0'; 44736833Sgd78059 size_out = msgdsize(mp1); 44746833Sgd78059 excess = size_out - avail; 44756833Sgd78059 if (excess > 0) { 44766833Sgd78059 iocp->ioc_rval = (unsigned)size_out; 44776833Sgd78059 size_out -= excess; 44786833Sgd78059 (void) adjmsg(mp1, -(excess + 1)); 44796833Sgd78059 err = eri_mk_mblk_tail_space(mp1, 44806833Sgd78059 &nmp, 1); 44816833Sgd78059 if (!err) 44826833Sgd78059 *nmp->b_wptr++ = '\0'; 44836833Sgd78059 else 44846833Sgd78059 size_out = 0; 44856833Sgd78059 } 44866833Sgd78059 44876833Sgd78059 } else 44886833Sgd78059 size_out = 0; 44896833Sgd78059 44906833Sgd78059 iocp->ioc_count = size_out; 44916833Sgd78059 } 44926833Sgd78059 break; 44936833Sgd78059 44946833Sgd78059 case ND_SET: 44956833Sgd78059 if (valp) { 44966833Sgd78059 err = (*nde->nde_set_pfi)(q, mp1, valp, 44976833Sgd78059 nde->nde_data, iocp->ioc_cr); 44986833Sgd78059 iocp->ioc_count = 0; 44996833Sgd78059 freemsg(mp1); 45006833Sgd78059 mp->b_cont = NULL; 45016833Sgd78059 } 45026833Sgd78059 break; 45036833Sgd78059 } 45046833Sgd78059 45056833Sgd78059 iocp->ioc_error = err; 45066833Sgd78059 mp->b_datap->db_type = M_IOCACK; 45076833Sgd78059 return (B_TRUE); 45086833Sgd78059 } 45096833Sgd78059 45106833Sgd78059 /* 45116833Sgd78059 * Load 'name' into the named dispatch table pointed to by 'ndp'. 45126833Sgd78059 * 'ndp' should be the address of a char pointer cell. If the table 45136833Sgd78059 * does not exist (*ndp == 0), a new table is allocated and 'ndp' 45146833Sgd78059 * is stuffed. If there is not enough space in the table for a new 45156833Sgd78059 * entry, more space is allocated. 45166833Sgd78059 */ 45176833Sgd78059 static boolean_t 45186833Sgd78059 eri_nd_load(caddr_t *nd_pparam, char *name, pfi_t get_pfi, 45196833Sgd78059 pfi_t set_pfi, caddr_t data) 45206833Sgd78059 { 45216833Sgd78059 ND *nd; 45226833Sgd78059 NDE *nde; 45236833Sgd78059 45246833Sgd78059 if (!nd_pparam) 45256833Sgd78059 return (B_FALSE); 45266833Sgd78059 45276833Sgd78059 if ((nd = (void *)(*nd_pparam)) == NULL) { 45286833Sgd78059 if ((nd = (ND *)kmem_zalloc(sizeof (ND), KM_NOSLEEP)) 45296833Sgd78059 == NULL) 45306833Sgd78059 return (B_FALSE); 45316833Sgd78059 *nd_pparam = (caddr_t)nd; 45326833Sgd78059 } 45336833Sgd78059 if (nd->nd_tbl) { 45346833Sgd78059 for (nde = nd->nd_tbl; nde->nde_name; nde++) { 45356833Sgd78059 if (strcmp(name, nde->nde_name) == 0) 45366833Sgd78059 goto fill_it; 45376833Sgd78059 } 45386833Sgd78059 } 45396833Sgd78059 if (nd->nd_free_count <= 1) { 45406833Sgd78059 if ((nde = (NDE *)kmem_zalloc(nd->nd_size + 45416833Sgd78059 NDE_ALLOC_SIZE, KM_NOSLEEP)) == NULL) 45426833Sgd78059 return (B_FALSE); 45436833Sgd78059 45446833Sgd78059 nd->nd_free_count += NDE_ALLOC_COUNT; 45456833Sgd78059 if (nd->nd_tbl) { 45466833Sgd78059 bcopy((char *)nd->nd_tbl, (char *)nde, nd->nd_size); 45476833Sgd78059 kmem_free((char *)nd->nd_tbl, nd->nd_size); 45486833Sgd78059 } else { 45496833Sgd78059 nd->nd_free_count--; 45506833Sgd78059 nde->nde_name = "?"; 45516833Sgd78059 nde->nde_get_pfi = nd_get_names; 45526833Sgd78059 nde->nde_set_pfi = nd_set_default; 45536833Sgd78059 } 45546833Sgd78059 nde->nde_data = (caddr_t)nd; 45556833Sgd78059 nd->nd_tbl = nde; 45566833Sgd78059 nd->nd_size += NDE_ALLOC_SIZE; 45576833Sgd78059 } 45586833Sgd78059 for (nde = nd->nd_tbl; nde->nde_name; nde++) 45596833Sgd78059 ; 45606833Sgd78059 nd->nd_free_count--; 45616833Sgd78059 fill_it: 45626833Sgd78059 nde->nde_name = name; 45636833Sgd78059 nde->nde_get_pfi = get_pfi ? get_pfi : nd_get_default; 45646833Sgd78059 nde->nde_set_pfi = set_pfi ? set_pfi : nd_set_default; 45656833Sgd78059 nde->nde_data = data; 45666833Sgd78059 return (B_TRUE); 45676833Sgd78059 } 45686833Sgd78059 45696833Sgd78059 /* 45706833Sgd78059 * Hardening Functions 45716833Sgd78059 * New Section 45726833Sgd78059 */ 45736833Sgd78059 #ifdef DEBUG 45746833Sgd78059 /*PRINTFLIKE5*/ 45756833Sgd78059 static void 45766833Sgd78059 eri_debug_msg(const char *file, int line, struct eri *erip, 45776833Sgd78059 debug_msg_t type, const char *fmt, ...) 45786833Sgd78059 { 45796833Sgd78059 char msg_buffer[255]; 45806833Sgd78059 va_list ap; 45816833Sgd78059 45826833Sgd78059 va_start(ap, fmt); 45836833Sgd78059 (void) vsprintf(msg_buffer, fmt, ap); 45846833Sgd78059 va_end(ap); 45856833Sgd78059 45866833Sgd78059 if (eri_msg_out & ERI_CON_MSG) { 45876833Sgd78059 if (((type <= eri_debug_level) && eri_debug_all) || 45886833Sgd78059 ((type == eri_debug_level) && !eri_debug_all)) { 45896833Sgd78059 if (erip) 45906833Sgd78059 cmn_err(CE_CONT, "D: %s %s%d:(%s%d) %s\n", 45916833Sgd78059 debug_msg_string[type], file, line, 45926833Sgd78059 ddi_driver_name(erip->dip), erip->instance, 45936833Sgd78059 msg_buffer); 45946833Sgd78059 else 45956833Sgd78059 cmn_err(CE_CONT, "D: %s %s(%d): %s\n", 45966833Sgd78059 debug_msg_string[type], file, 45976833Sgd78059 line, msg_buffer); 45986833Sgd78059 } 45996833Sgd78059 } 46006833Sgd78059 } 46016833Sgd78059 #endif 46026833Sgd78059 46036833Sgd78059 46046833Sgd78059 /*PRINTFLIKE4*/ 46056833Sgd78059 static void 46066833Sgd78059 eri_fault_msg(struct eri *erip, uint_t severity, msg_t type, 46076833Sgd78059 const char *fmt, ...) 46086833Sgd78059 { 46096833Sgd78059 char msg_buffer[255]; 46106833Sgd78059 va_list ap; 46116833Sgd78059 46126833Sgd78059 va_start(ap, fmt); 46136833Sgd78059 (void) vsprintf(msg_buffer, fmt, ap); 46146833Sgd78059 va_end(ap); 46156833Sgd78059 46166833Sgd78059 if (erip == NULL) { 46176833Sgd78059 cmn_err(CE_NOTE, "eri : %s", msg_buffer); 46186833Sgd78059 return; 46196833Sgd78059 } 46206833Sgd78059 46216833Sgd78059 if (severity == SEVERITY_HIGH) { 46226833Sgd78059 cmn_err(CE_WARN, "%s%d : %s", ddi_driver_name(erip->dip), 46236833Sgd78059 erip->instance, msg_buffer); 46246833Sgd78059 } else switch (type) { 46256833Sgd78059 case ERI_VERB_MSG: 46266833Sgd78059 cmn_err(CE_CONT, "?%s%d : %s", ddi_driver_name(erip->dip), 46276833Sgd78059 erip->instance, msg_buffer); 46286833Sgd78059 break; 46296833Sgd78059 case ERI_LOG_MSG: 46306833Sgd78059 cmn_err(CE_NOTE, "^%s%d : %s", ddi_driver_name(erip->dip), 46316833Sgd78059 erip->instance, msg_buffer); 46326833Sgd78059 break; 46336833Sgd78059 case ERI_BUF_MSG: 46346833Sgd78059 cmn_err(CE_NOTE, "!%s%d : %s", ddi_driver_name(erip->dip), 46356833Sgd78059 erip->instance, msg_buffer); 46366833Sgd78059 break; 46376833Sgd78059 case ERI_CON_MSG: 46386833Sgd78059 cmn_err(CE_CONT, "%s%d : %s", ddi_driver_name(erip->dip), 46396833Sgd78059 erip->instance, msg_buffer); 46406833Sgd78059 default: 46416833Sgd78059 break; 46426833Sgd78059 } 46436833Sgd78059 } 46446833Sgd78059 46456833Sgd78059 /* 46466833Sgd78059 * Transceiver (xcvr) Functions 46476833Sgd78059 * New Section 46486833Sgd78059 */ 46496833Sgd78059 /* 46506833Sgd78059 * eri_stop_timer function is used by a function before doing link-related 46516833Sgd78059 * processing. It locks the "linklock" to protect the link-related data 46526833Sgd78059 * structures. This lock will be subsequently released in eri_start_timer(). 46536833Sgd78059 */ 46546833Sgd78059 static void 46556833Sgd78059 eri_stop_timer(struct eri *erip) 46566833Sgd78059 { 46576833Sgd78059 timeout_id_t id; 46586833Sgd78059 mutex_enter(&erip->linklock); 46596833Sgd78059 if (erip->timerid) { 46606833Sgd78059 erip->flags |= ERI_NOTIMEOUTS; /* prevent multiple timeout */ 46616833Sgd78059 id = erip->timerid; 46626833Sgd78059 erip->timerid = 0; /* prevent other thread do untimeout */ 46636833Sgd78059 mutex_exit(&erip->linklock); /* no mutex across untimeout() */ 46646833Sgd78059 46656833Sgd78059 (void) untimeout(id); 46666833Sgd78059 mutex_enter(&erip->linklock); /* acquire mutex again */ 46676833Sgd78059 erip->flags &= ~ERI_NOTIMEOUTS; 46686833Sgd78059 } 46696833Sgd78059 } 46706833Sgd78059 46716833Sgd78059 /* 46726833Sgd78059 * If msec parameter is zero, just release "linklock". 46736833Sgd78059 */ 46746833Sgd78059 static void 46756833Sgd78059 eri_start_timer(struct eri *erip, fptrv_t func, clock_t msec) 46766833Sgd78059 { 46776833Sgd78059 if (msec) { 46786833Sgd78059 if (!(erip->flags & ERI_NOTIMEOUTS) && 46796833Sgd78059 (erip->flags & ERI_RUNNING)) { 46806833Sgd78059 erip->timerid = timeout(func, (caddr_t)erip, 46816833Sgd78059 drv_usectohz(1000*msec)); 46826833Sgd78059 } 46836833Sgd78059 } 46846833Sgd78059 46856833Sgd78059 mutex_exit(&erip->linklock); 46866833Sgd78059 } 46876833Sgd78059 46886833Sgd78059 static int 46896833Sgd78059 eri_new_xcvr(struct eri *erip) 46906833Sgd78059 { 46916833Sgd78059 int status; 46926833Sgd78059 uint32_t cfg; 46936833Sgd78059 int old_transceiver; 46946833Sgd78059 46956833Sgd78059 if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED, 46966833Sgd78059 PCI_PM_IDLESPEED_NONE) == DDI_SUCCESS) 46976833Sgd78059 erip->stats.pmcap = ERI_PMCAP_NONE; 46986833Sgd78059 46996833Sgd78059 status = B_FALSE; /* no change */ 47006833Sgd78059 cfg = GET_MIFREG(mif_cfg); 47016833Sgd78059 ERI_DEBUG_MSG2(erip, MIF_MSG, "cfg value = %X", cfg); 47026833Sgd78059 old_transceiver = param_transceiver; 47036833Sgd78059 47046833Sgd78059 if ((cfg & ERI_MIF_CFGM1) && !use_int_xcvr) { 47056833Sgd78059 ERI_DEBUG_MSG1(erip, PHY_MSG, "Found External XCVR"); 47066833Sgd78059 /* 47076833Sgd78059 * An External Transceiver was found and it takes priority 47086833Sgd78059 * over an internal, given the use_int_xcvr flag 47096833Sgd78059 * is false. 47106833Sgd78059 */ 47116833Sgd78059 if (old_transceiver != EXTERNAL_XCVR) { 47126833Sgd78059 /* 47136833Sgd78059 * External transceiver has just been plugged 47146833Sgd78059 * in. Isolate the internal Transceiver. 47156833Sgd78059 */ 47166833Sgd78059 if (old_transceiver == INTERNAL_XCVR) { 47176833Sgd78059 eri_mii_write(erip, ERI_PHY_BMCR, 47186833Sgd78059 (PHY_BMCR_ISOLATE | PHY_BMCR_PWRDN | 47196833Sgd78059 PHY_BMCR_LPBK)); 47206833Sgd78059 } 47216833Sgd78059 status = B_TRUE; 47226833Sgd78059 } 47236833Sgd78059 /* 47246833Sgd78059 * Select the external Transceiver. 47256833Sgd78059 */ 47266833Sgd78059 erip->phyad = ERI_EXTERNAL_PHYAD; 47276833Sgd78059 param_transceiver = EXTERNAL_XCVR; 47286833Sgd78059 erip->mif_config &= ~ERI_MIF_CFGPD; 47296833Sgd78059 erip->mif_config |= (erip->phyad << ERI_MIF_CFGPD_SHIFT); 47306833Sgd78059 erip->mif_config |= ERI_MIF_CFGPS; 47316833Sgd78059 PUT_MIFREG(mif_cfg, erip->mif_config); 47326833Sgd78059 47336833Sgd78059 PUT_MACREG(xifc, GET_MACREG(xifc) | BMAC_XIFC_MIIBUF_OE); 47346833Sgd78059 drv_usecwait(ERI_MIF_POLL_DELAY); 47356833Sgd78059 } else if (cfg & ERI_MIF_CFGM0) { 47366833Sgd78059 ERI_DEBUG_MSG1(erip, PHY_MSG, "Found Internal XCVR"); 47376833Sgd78059 /* 47386833Sgd78059 * An Internal Transceiver was found or the 47396833Sgd78059 * use_int_xcvr flag is true. 47406833Sgd78059 */ 47416833Sgd78059 if (old_transceiver != INTERNAL_XCVR) { 47426833Sgd78059 /* 47436833Sgd78059 * The external transceiver has just been 47446833Sgd78059 * disconnected or we're moving from a no 47456833Sgd78059 * transceiver state. 47466833Sgd78059 */ 47476833Sgd78059 if ((old_transceiver == EXTERNAL_XCVR) && 47486833Sgd78059 (cfg & ERI_MIF_CFGM0)) { 47496833Sgd78059 eri_mii_write(erip, ERI_PHY_BMCR, 47506833Sgd78059 (PHY_BMCR_ISOLATE | PHY_BMCR_PWRDN | 47516833Sgd78059 PHY_BMCR_LPBK)); 47526833Sgd78059 } 47536833Sgd78059 status = B_TRUE; 47546833Sgd78059 } 47556833Sgd78059 /* 47566833Sgd78059 * Select the internal transceiver. 47576833Sgd78059 */ 47586833Sgd78059 erip->phyad = ERI_INTERNAL_PHYAD; 47596833Sgd78059 param_transceiver = INTERNAL_XCVR; 47606833Sgd78059 erip->mif_config &= ~ERI_MIF_CFGPD; 47616833Sgd78059 erip->mif_config |= (erip->phyad << ERI_MIF_CFGPD_SHIFT); 47626833Sgd78059 erip->mif_config &= ~ERI_MIF_CFGPS; 47636833Sgd78059 PUT_MIFREG(mif_cfg, erip->mif_config); 47646833Sgd78059 47656833Sgd78059 PUT_MACREG(xifc, GET_MACREG(xifc) & ~ BMAC_XIFC_MIIBUF_OE); 47666833Sgd78059 drv_usecwait(ERI_MIF_POLL_DELAY); 47676833Sgd78059 } else { 47686833Sgd78059 /* 47696833Sgd78059 * Did not find a valid xcvr. 47706833Sgd78059 */ 47716833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, 47726833Sgd78059 "Eri_new_xcvr : Select None"); 47736833Sgd78059 param_transceiver = NO_XCVR; 47746833Sgd78059 erip->xcvr_status = PHY_LINK_DOWN; 47756833Sgd78059 } 47766833Sgd78059 47776833Sgd78059 if (erip->stats.pmcap == ERI_PMCAP_NONE) { 47786833Sgd78059 if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED, 47796833Sgd78059 (void *)4000) == DDI_SUCCESS) 47806833Sgd78059 erip->stats.pmcap = ERI_PMCAP_4MHZ; 47816833Sgd78059 } 47826833Sgd78059 47836833Sgd78059 return (status); 47846833Sgd78059 } 47856833Sgd78059 47866833Sgd78059 /* 47876833Sgd78059 * This function is used for timers. No locks are held on timer expiry. 47886833Sgd78059 */ 47896833Sgd78059 static void 47906833Sgd78059 eri_check_link(struct eri *erip) 47916833Sgd78059 { 47926833Sgd78059 link_state_t linkupdate = eri_check_link_noind(erip); 47936833Sgd78059 47946833Sgd78059 if (linkupdate != LINK_STATE_UNKNOWN) 47956833Sgd78059 mac_link_update(erip->mh, linkupdate); 47966833Sgd78059 } 47976833Sgd78059 47986833Sgd78059 /* 47996833Sgd78059 * Compare our xcvr in our structure to the xcvr that we get from 48006833Sgd78059 * eri_check_mii_xcvr(). If they are different then mark the 48016833Sgd78059 * link down, reset xcvr, and return. 48026833Sgd78059 * 48036833Sgd78059 * Note without the MII connector, conditions can not change that 48046833Sgd78059 * will then use a external phy, thus this code has been cleaned 48056833Sgd78059 * to not even call the function or to possibly change the xcvr. 48066833Sgd78059 */ 48076833Sgd78059 static uint32_t 48086833Sgd78059 eri_check_link_noind(struct eri *erip) 48096833Sgd78059 { 48106833Sgd78059 uint16_t stat, control, mif_ints; 48116833Sgd78059 uint32_t link_timeout = ERI_LINKCHECK_TIMER; 48126833Sgd78059 uint32_t linkupdate = 0; 48136833Sgd78059 48146833Sgd78059 eri_stop_timer(erip); /* acquire linklock */ 48156833Sgd78059 48166833Sgd78059 mutex_enter(&erip->xmitlock); 48176833Sgd78059 mutex_enter(&erip->xcvrlock); 48186833Sgd78059 eri_mif_poll(erip, MIF_POLL_STOP); 48196833Sgd78059 48206833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat); 48216833Sgd78059 mif_ints = erip->mii_status ^ stat; 48226833Sgd78059 48236833Sgd78059 if (erip->openloop_autoneg) { 48246833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat); 48256833Sgd78059 ERI_DEBUG_MSG3(erip, XCVR_MSG, 48266833Sgd78059 "eri_check_link:openloop stat %X mii_status %X", 48276833Sgd78059 stat, erip->mii_status); 48286833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_BMCR, &control); 48296833Sgd78059 if (!(stat & PHY_BMSR_LNKSTS) && 48306833Sgd78059 (erip->openloop_autoneg < 2)) { 48316833Sgd78059 if (param_speed) { 48326833Sgd78059 control &= ~PHY_BMCR_100M; 48336833Sgd78059 param_anlpar_100hdx = 0; 48346833Sgd78059 param_anlpar_10hdx = 1; 48356833Sgd78059 param_speed = 0; 48366833Sgd78059 erip->stats.ifspeed = 10; 48376833Sgd78059 48386833Sgd78059 } else { 48396833Sgd78059 control |= PHY_BMCR_100M; 48406833Sgd78059 param_anlpar_100hdx = 1; 48416833Sgd78059 param_anlpar_10hdx = 0; 48426833Sgd78059 param_speed = 1; 48436833Sgd78059 erip->stats.ifspeed = 100; 48446833Sgd78059 } 48456833Sgd78059 ERI_DEBUG_MSG3(erip, XCVR_MSG, 48466833Sgd78059 "eri_check_link: trying speed %X stat %X", 48476833Sgd78059 param_speed, stat); 48486833Sgd78059 48496833Sgd78059 erip->openloop_autoneg ++; 48506833Sgd78059 eri_mii_write(erip, ERI_PHY_BMCR, control); 48516833Sgd78059 link_timeout = ERI_P_FAULT_TIMER; 48526833Sgd78059 } else { 48536833Sgd78059 erip->openloop_autoneg = 0; 48546833Sgd78059 linkupdate = eri_mif_check(erip, stat, stat); 48556833Sgd78059 if (erip->openloop_autoneg) 48566833Sgd78059 link_timeout = ERI_P_FAULT_TIMER; 48576833Sgd78059 } 48586833Sgd78059 eri_mif_poll(erip, MIF_POLL_START); 48596833Sgd78059 mutex_exit(&erip->xcvrlock); 48606833Sgd78059 mutex_exit(&erip->xmitlock); 48616833Sgd78059 48626833Sgd78059 eri_start_timer(erip, eri_check_link, link_timeout); 48636833Sgd78059 return (linkupdate); 48646833Sgd78059 } 48656833Sgd78059 48666833Sgd78059 linkupdate = eri_mif_check(erip, mif_ints, stat); 48676833Sgd78059 eri_mif_poll(erip, MIF_POLL_START); 48686833Sgd78059 mutex_exit(&erip->xcvrlock); 48696833Sgd78059 mutex_exit(&erip->xmitlock); 48706833Sgd78059 48716833Sgd78059 #ifdef ERI_RMAC_HANG_WORKAROUND 48726833Sgd78059 /* 48736833Sgd78059 * Check if rx hung. 48746833Sgd78059 */ 48756833Sgd78059 if ((erip->flags & ERI_RUNNING) && param_linkup) { 48766833Sgd78059 if (erip->check_rmac_hang) { 48776833Sgd78059 ERI_DEBUG_MSG5(erip, 48786833Sgd78059 NONFATAL_MSG, 48796833Sgd78059 "check1 %d: macsm:%8x wr:%2x rd:%2x", 48806833Sgd78059 erip->check_rmac_hang, 48816833Sgd78059 GET_MACREG(macsm), 48826833Sgd78059 GET_ERXREG(rxfifo_wr_ptr), 48836833Sgd78059 GET_ERXREG(rxfifo_rd_ptr)); 48846833Sgd78059 48856833Sgd78059 erip->check_rmac_hang = 0; 48866833Sgd78059 erip->check2_rmac_hang ++; 48876833Sgd78059 48886833Sgd78059 erip->rxfifo_wr_ptr_c = GET_ERXREG(rxfifo_wr_ptr); 48896833Sgd78059 erip->rxfifo_rd_ptr_c = GET_ERXREG(rxfifo_rd_ptr); 48906833Sgd78059 48916833Sgd78059 eri_start_timer(erip, eri_check_link, 48926833Sgd78059 ERI_CHECK_HANG_TIMER); 48936833Sgd78059 return (linkupdate); 48946833Sgd78059 } 48956833Sgd78059 48966833Sgd78059 if (erip->check2_rmac_hang) { 48976833Sgd78059 ERI_DEBUG_MSG5(erip, 48986833Sgd78059 NONFATAL_MSG, 48996833Sgd78059 "check2 %d: macsm:%8x wr:%2x rd:%2x", 49006833Sgd78059 erip->check2_rmac_hang, 49016833Sgd78059 GET_MACREG(macsm), 49026833Sgd78059 GET_ERXREG(rxfifo_wr_ptr), 49036833Sgd78059 GET_ERXREG(rxfifo_rd_ptr)); 49046833Sgd78059 49056833Sgd78059 erip->check2_rmac_hang = 0; 49066833Sgd78059 49076833Sgd78059 erip->rxfifo_wr_ptr = GET_ERXREG(rxfifo_wr_ptr); 49086833Sgd78059 erip->rxfifo_rd_ptr = GET_ERXREG(rxfifo_rd_ptr); 49096833Sgd78059 49106833Sgd78059 if (((GET_MACREG(macsm) & BMAC_OVERFLOW_STATE) == 49116833Sgd78059 BMAC_OVERFLOW_STATE) && 49126833Sgd78059 ((erip->rxfifo_wr_ptr_c == erip->rxfifo_rd_ptr_c) || 49136833Sgd78059 ((erip->rxfifo_rd_ptr == erip->rxfifo_rd_ptr_c) && 49146833Sgd78059 (erip->rxfifo_wr_ptr == erip->rxfifo_wr_ptr_c)))) { 49156833Sgd78059 ERI_DEBUG_MSG1(erip, 49166833Sgd78059 NONFATAL_MSG, 49176833Sgd78059 "RX hang: Reset mac"); 49186833Sgd78059 49196833Sgd78059 HSTAT(erip, rx_hang); 49206833Sgd78059 erip->linkcheck = 1; 49216833Sgd78059 49226833Sgd78059 eri_start_timer(erip, eri_check_link, 49236833Sgd78059 ERI_LINKCHECK_TIMER); 49246833Sgd78059 (void) eri_init(erip); 49256833Sgd78059 return (linkupdate); 49266833Sgd78059 } 49276833Sgd78059 } 49286833Sgd78059 } 49296833Sgd78059 #endif 49306833Sgd78059 49316833Sgd78059 /* 49326833Sgd78059 * Check if tx hung. 49336833Sgd78059 */ 49346833Sgd78059 #ifdef ERI_TX_HUNG 49356833Sgd78059 if ((erip->flags & ERI_RUNNING) && param_linkup && 49366833Sgd78059 (eri_check_txhung(erip))) { 49376833Sgd78059 HSTAT(erip, tx_hang); 49386833Sgd78059 eri_reinit_txhung++; 49396833Sgd78059 erip->linkcheck = 1; 49406833Sgd78059 eri_start_timer(erip, eri_check_link, ERI_CHECK_HANG_TIMER); 49416833Sgd78059 (void) eri_init(erip); 49426833Sgd78059 return (linkupdate); 49436833Sgd78059 } 49446833Sgd78059 #endif 49456833Sgd78059 49466833Sgd78059 #ifdef ERI_PM_WORKAROUND 49476833Sgd78059 if (erip->stats.pmcap == ERI_PMCAP_NONE) { 49486833Sgd78059 if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED, 49496833Sgd78059 (void *)4000) == DDI_SUCCESS) 49506833Sgd78059 erip->stats.pmcap = ERI_PMCAP_4MHZ; 49516833Sgd78059 49526833Sgd78059 ERI_DEBUG_MSG2(erip, NONFATAL_MSG, 49536833Sgd78059 "eri_check_link: PMCAP %d", erip->stats.pmcap); 49546833Sgd78059 } 49556833Sgd78059 #endif 49566833Sgd78059 if ((!param_mode) && (param_transceiver != NO_XCVR)) 49576833Sgd78059 eri_start_timer(erip, eri_check_link, ERI_CHECK_HANG_TIMER); 49586833Sgd78059 else 49596833Sgd78059 eri_start_timer(erip, eri_check_link, ERI_LINKCHECK_TIMER); 49606833Sgd78059 return (linkupdate); 49616833Sgd78059 } 49626833Sgd78059 49636833Sgd78059 static link_state_t 49646833Sgd78059 eri_mif_check(struct eri *erip, uint16_t mif_ints, uint16_t mif_data) 49656833Sgd78059 { 49666833Sgd78059 uint16_t control, aner, anlpar, anar, an_common; 49676833Sgd78059 uint16_t old_mintrans; 49686833Sgd78059 int restart_autoneg = 0; 49696833Sgd78059 link_state_t retv; 49706833Sgd78059 49716833Sgd78059 ERI_DEBUG_MSG4(erip, XCVR_MSG, "eri_mif_check: mif_mask: %X, %X, %X", 49726833Sgd78059 erip->mif_mask, mif_ints, mif_data); 49736833Sgd78059 49746833Sgd78059 mif_ints &= ~erip->mif_mask; 49756833Sgd78059 erip->mii_status = mif_data; 49766833Sgd78059 /* 49776833Sgd78059 * Now check if someone has pulled the xcvr or 49786833Sgd78059 * a new xcvr has shown up 49796833Sgd78059 * If so try to find out what the new xcvr setup is. 49806833Sgd78059 */ 49816833Sgd78059 if (((mif_ints & PHY_BMSR_RES1) && (mif_data == 0xFFFF)) || 49826833Sgd78059 (param_transceiver == NO_XCVR)) { 49836833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, 49846833Sgd78059 "No status transceiver gone"); 49856833Sgd78059 if (eri_new_xcvr(erip)) { 49866833Sgd78059 if (param_transceiver != NO_XCVR) { 49876833Sgd78059 /* 49886833Sgd78059 * Reset the new PHY and bring up the link 49896833Sgd78059 */ 49906833Sgd78059 (void) eri_reset_xcvr(erip); 49916833Sgd78059 } 49926833Sgd78059 } 49936833Sgd78059 return (LINK_STATE_UNKNOWN); 49946833Sgd78059 } 49956833Sgd78059 49966833Sgd78059 if (param_autoneg && (mif_ints & PHY_BMSR_LNKSTS) && 49976833Sgd78059 (mif_data & PHY_BMSR_LNKSTS) && (mif_data & PHY_BMSR_ANC)) { 49986833Sgd78059 mif_ints |= PHY_BMSR_ANC; 49996833Sgd78059 ERI_DEBUG_MSG3(erip, PHY_MSG, 50006833Sgd78059 "eri_mif_check: Set ANC bit mif_data %X mig_ints %X", 50016833Sgd78059 mif_data, mif_ints); 50026833Sgd78059 } 50036833Sgd78059 50046833Sgd78059 if ((mif_ints & PHY_BMSR_ANC) && (mif_data & PHY_BMSR_ANC)) { 50056833Sgd78059 ERI_DEBUG_MSG1(erip, PHY_MSG, "Auto-negotiation interrupt."); 50066833Sgd78059 50076833Sgd78059 /* 50086833Sgd78059 * Switch off Auto-negotiation interrupts and switch on 50096833Sgd78059 * Link ststus interrupts. 50106833Sgd78059 */ 50116833Sgd78059 erip->mif_mask |= PHY_BMSR_ANC; 50126833Sgd78059 erip->mif_mask &= ~PHY_BMSR_LNKSTS; 50136833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_ANER, &aner); 50146833Sgd78059 param_aner_lpancap = 1 && (aner & PHY_ANER_LPNW); 50156833Sgd78059 if ((aner & PHY_ANER_MLF) || (eri_force_mlf)) { 50166833Sgd78059 ERI_DEBUG_MSG1(erip, XCVR_MSG, 50176833Sgd78059 "parallel detection fault"); 50186833Sgd78059 /* 50196833Sgd78059 * Consider doing open loop auto-negotiation. 50206833Sgd78059 */ 50216833Sgd78059 ERI_DEBUG_MSG1(erip, XCVR_MSG, 50226833Sgd78059 "Going into Open loop Auto-neg"); 50236833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_BMCR, &control); 50246833Sgd78059 50256833Sgd78059 control &= ~(PHY_BMCR_ANE | PHY_BMCR_RAN | 50266833Sgd78059 PHY_BMCR_FDX); 50276833Sgd78059 if (param_anar_100fdx || param_anar_100hdx) { 50286833Sgd78059 control |= PHY_BMCR_100M; 50296833Sgd78059 param_anlpar_100hdx = 1; 50306833Sgd78059 param_anlpar_10hdx = 0; 50316833Sgd78059 param_speed = 1; 50326833Sgd78059 erip->stats.ifspeed = 100; 50336833Sgd78059 50346833Sgd78059 } else if (param_anar_10fdx || param_anar_10hdx) { 50356833Sgd78059 control &= ~PHY_BMCR_100M; 50366833Sgd78059 param_anlpar_100hdx = 0; 50376833Sgd78059 param_anlpar_10hdx = 1; 50386833Sgd78059 param_speed = 0; 50396833Sgd78059 erip->stats.ifspeed = 10; 50406833Sgd78059 } else { 50416833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, 50426833Sgd78059 ERI_VERB_MSG, 50436833Sgd78059 "Transceiver speed set incorrectly."); 50446833Sgd78059 return (0); 50456833Sgd78059 } 50466833Sgd78059 50476833Sgd78059 (void) eri_mii_write(erip, ERI_PHY_BMCR, control); 50486833Sgd78059 param_anlpar_100fdx = 0; 50496833Sgd78059 param_anlpar_10fdx = 0; 50506833Sgd78059 param_mode = 0; 50516833Sgd78059 erip->openloop_autoneg = 1; 50526833Sgd78059 return (0); 50536833Sgd78059 } 50546833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_ANLPAR, &anlpar); 50556833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_ANAR, &anar); 50566833Sgd78059 an_common = anar & anlpar; 50576833Sgd78059 50586833Sgd78059 ERI_DEBUG_MSG2(erip, XCVR_MSG, "an_common = 0x%X", an_common); 50596833Sgd78059 50606833Sgd78059 if (an_common & (PHY_ANLPAR_TXFDX | PHY_ANLPAR_TX)) { 50616833Sgd78059 param_speed = 1; 50626833Sgd78059 erip->stats.ifspeed = 100; 50636833Sgd78059 param_mode = 1 && (an_common & PHY_ANLPAR_TXFDX); 50646833Sgd78059 50656833Sgd78059 } else if (an_common & (PHY_ANLPAR_10FDX | PHY_ANLPAR_10)) { 50666833Sgd78059 param_speed = 0; 50676833Sgd78059 erip->stats.ifspeed = 10; 50686833Sgd78059 param_mode = 1 && (an_common & PHY_ANLPAR_10FDX); 50696833Sgd78059 50706833Sgd78059 } else an_common = 0x0; 50716833Sgd78059 50726833Sgd78059 if (!an_common) { 50736833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_MID, ERI_VERB_MSG, 50746833Sgd78059 "Transceiver: anar not set with speed selection"); 50756833Sgd78059 } 50766833Sgd78059 param_anlpar_100T4 = 1 && (anlpar & PHY_ANLPAR_T4); 50776833Sgd78059 param_anlpar_100fdx = 1 && (anlpar & PHY_ANLPAR_TXFDX); 50786833Sgd78059 param_anlpar_100hdx = 1 && (anlpar & PHY_ANLPAR_TX); 50796833Sgd78059 param_anlpar_10fdx = 1 && (anlpar & PHY_ANLPAR_10FDX); 50806833Sgd78059 param_anlpar_10hdx = 1 && (anlpar & PHY_ANLPAR_10); 50816833Sgd78059 50826833Sgd78059 ERI_DEBUG_MSG2(erip, PHY_MSG, 50836833Sgd78059 "Link duplex = 0x%X", param_mode); 50846833Sgd78059 ERI_DEBUG_MSG2(erip, PHY_MSG, 50856833Sgd78059 "Link speed = 0x%X", param_speed); 50866833Sgd78059 /* mif_ints |= PHY_BMSR_LNKSTS; prevent double msg */ 50876833Sgd78059 /* mif_data |= PHY_BMSR_LNKSTS; prevent double msg */ 50886833Sgd78059 } 50896833Sgd78059 retv = LINK_STATE_UNKNOWN; 50906833Sgd78059 if (mif_ints & PHY_BMSR_LNKSTS) { 50916833Sgd78059 if (mif_data & PHY_BMSR_LNKSTS) { 50926833Sgd78059 ERI_DEBUG_MSG1(erip, PHY_MSG, "Link Up"); 50936833Sgd78059 /* 50946833Sgd78059 * Program Lu3X31T for mininum transition 50956833Sgd78059 */ 50966833Sgd78059 if (eri_phy_mintrans) { 50976833Sgd78059 eri_mii_write(erip, 31, 0x8000); 50986833Sgd78059 (void) eri_mii_read(erip, 0, &old_mintrans); 50996833Sgd78059 eri_mii_write(erip, 0, 0x00F1); 51006833Sgd78059 eri_mii_write(erip, 31, 0x0000); 51016833Sgd78059 } 51026833Sgd78059 /* 51036833Sgd78059 * The link is up. 51046833Sgd78059 */ 51056833Sgd78059 eri_init_txmac(erip); 51066833Sgd78059 param_linkup = 1; 51076833Sgd78059 erip->stats.link_up = LINK_STATE_UP; 51086833Sgd78059 if (param_mode) 51096833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_FULL; 51106833Sgd78059 else 51116833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_HALF; 51126833Sgd78059 51136833Sgd78059 retv = LINK_STATE_UP; 51146833Sgd78059 } else { 51156833Sgd78059 ERI_DEBUG_MSG1(erip, PHY_MSG, "Link down."); 51166833Sgd78059 param_linkup = 0; 51176833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 51186833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 51196833Sgd78059 retv = LINK_STATE_DOWN; 51206833Sgd78059 if (param_autoneg) { 51216833Sgd78059 restart_autoneg = 1; 51226833Sgd78059 } 51236833Sgd78059 } 51246833Sgd78059 } else { 51256833Sgd78059 if (mif_data & PHY_BMSR_LNKSTS) { 51266833Sgd78059 if (!param_linkup) { 51276833Sgd78059 ERI_DEBUG_MSG1(erip, PHY_MSG, 51286833Sgd78059 "eri_mif_check: MIF data link up"); 51296833Sgd78059 /* 51306833Sgd78059 * Program Lu3X31T for minimum transition 51316833Sgd78059 */ 51326833Sgd78059 if (eri_phy_mintrans) { 51336833Sgd78059 eri_mii_write(erip, 31, 0x8000); 51346833Sgd78059 (void) eri_mii_read(erip, 0, 51356833Sgd78059 &old_mintrans); 51366833Sgd78059 eri_mii_write(erip, 0, 0x00F1); 51376833Sgd78059 eri_mii_write(erip, 31, 0x0000); 51386833Sgd78059 } 51396833Sgd78059 /* 51406833Sgd78059 * The link is up. 51416833Sgd78059 */ 51426833Sgd78059 eri_init_txmac(erip); 51436833Sgd78059 51446833Sgd78059 param_linkup = 1; 51456833Sgd78059 erip->stats.link_up = LINK_STATE_UP; 51466833Sgd78059 if (param_mode) 51476833Sgd78059 erip->stats.link_duplex = 51486833Sgd78059 LINK_DUPLEX_FULL; 51496833Sgd78059 else 51506833Sgd78059 erip->stats.link_duplex = 51516833Sgd78059 LINK_DUPLEX_HALF; 51526833Sgd78059 51536833Sgd78059 retv = LINK_STATE_UP; 51546833Sgd78059 } 51556833Sgd78059 } else if (param_linkup) { 51566833Sgd78059 /* 51576833Sgd78059 * The link is down now. 51586833Sgd78059 */ 51596833Sgd78059 ERI_DEBUG_MSG1(erip, PHY_MSG, 51606833Sgd78059 "eri_mif_check:Link was up and went down"); 51616833Sgd78059 param_linkup = 0; 51626833Sgd78059 erip->stats.link_up = LINK_STATE_DOWN; 51636833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN; 51646833Sgd78059 retv = LINK_STATE_DOWN; 51656833Sgd78059 if (param_autoneg) 51666833Sgd78059 restart_autoneg = 1; 51676833Sgd78059 } 51686833Sgd78059 } 51696833Sgd78059 if (restart_autoneg) { 51706833Sgd78059 /* 51716833Sgd78059 * Restart normal auto-negotiation. 51726833Sgd78059 */ 51736833Sgd78059 ERI_DEBUG_MSG1(erip, PHY_MSG, 51746833Sgd78059 "eri_mif_check:Restart AUto Negotiation"); 51756833Sgd78059 erip->openloop_autoneg = 0; 51766833Sgd78059 param_mode = 0; 51776833Sgd78059 param_speed = 0; 51786833Sgd78059 param_anlpar_100T4 = 0; 51796833Sgd78059 param_anlpar_100fdx = 0; 51806833Sgd78059 param_anlpar_100hdx = 0; 51816833Sgd78059 param_anlpar_10fdx = 0; 51826833Sgd78059 param_anlpar_10hdx = 0; 51836833Sgd78059 param_aner_lpancap = 0; 51846833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_BMCR, &control); 51856833Sgd78059 control |= (PHY_BMCR_ANE | PHY_BMCR_RAN); 51866833Sgd78059 eri_mii_write(erip, ERI_PHY_BMCR, control); 51876833Sgd78059 } 51886833Sgd78059 if (mif_ints & PHY_BMSR_JABDET) { 51896833Sgd78059 if (mif_data & PHY_BMSR_JABDET) { 51906833Sgd78059 ERI_DEBUG_MSG1(erip, PHY_MSG, "Jabber detected."); 51916833Sgd78059 HSTAT(erip, jab); 51926833Sgd78059 /* 51936833Sgd78059 * Reset the new PHY and bring up the link 51946833Sgd78059 * (Check for failure?) 51956833Sgd78059 */ 51966833Sgd78059 (void) eri_reset_xcvr(erip); 51976833Sgd78059 } 51986833Sgd78059 } 51996833Sgd78059 return (retv); 52006833Sgd78059 } 52016833Sgd78059 52026833Sgd78059 #define PHYRST_PERIOD 500 52036833Sgd78059 static int 52046833Sgd78059 eri_reset_xcvr(struct eri *erip) 52056833Sgd78059 { 52066833Sgd78059 uint16_t stat; 52076833Sgd78059 uint16_t anar; 52086833Sgd78059 uint16_t control; 52096833Sgd78059 uint16_t idr1; 52106833Sgd78059 uint16_t idr2; 52116833Sgd78059 uint16_t nicr; 52126833Sgd78059 uint32_t speed_100; 52136833Sgd78059 uint32_t speed_10; 52146833Sgd78059 int n; 52156833Sgd78059 52166833Sgd78059 #ifdef ERI_10_10_FORCE_SPEED_WORKAROUND 52176833Sgd78059 erip->ifspeed_old = erip->stats.ifspeed; 52186833Sgd78059 #endif 52196833Sgd78059 /* 52206833Sgd78059 * Reset Open loop auto-negotiation this means you can try 52216833Sgd78059 * Normal auto-negotiation, until you get a Multiple Link fault 52226833Sgd78059 * at which point you try 100M half duplex then 10M half duplex 52236833Sgd78059 * until you get a Link up. 52246833Sgd78059 */ 52256833Sgd78059 erip->openloop_autoneg = 0; 52266833Sgd78059 52276833Sgd78059 /* 52286833Sgd78059 * Reset the xcvr. 52296833Sgd78059 */ 52306833Sgd78059 eri_mii_write(erip, ERI_PHY_BMCR, PHY_BMCR_RESET); 52316833Sgd78059 52326833Sgd78059 /* Check for transceiver reset completion */ 52336833Sgd78059 52346833Sgd78059 n = 1000; 52356833Sgd78059 while (--n > 0) { 52366833Sgd78059 drv_usecwait((clock_t)PHYRST_PERIOD); 52376833Sgd78059 if (eri_mii_read(erip, ERI_PHY_BMCR, &control) == 1) { 52386833Sgd78059 /* Transceiver does not talk MII */ 52396833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, 52406833Sgd78059 "eri_reset_xcvr: no mii"); 52416833Sgd78059 } 52426833Sgd78059 if ((control & PHY_BMCR_RESET) == 0) 52436833Sgd78059 goto reset_done; 52446833Sgd78059 } 52456833Sgd78059 ERI_FAULT_MSG2(erip, SEVERITY_NONE, ERI_VERB_MSG, 52466833Sgd78059 "eri_reset_xcvr:reset_failed n == 0, control %x", control); 52476833Sgd78059 goto eri_reset_xcvr_failed; 52486833Sgd78059 52496833Sgd78059 reset_done: 52506833Sgd78059 52516833Sgd78059 ERI_DEBUG_MSG2(erip, AUTOCONFIG_MSG, 52526833Sgd78059 "eri_reset_xcvr: reset complete in %d us", 52536833Sgd78059 (1000 - n) * PHYRST_PERIOD); 52546833Sgd78059 52556833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat); 52566833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_ANAR, &anar); 52576833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_IDR1, &idr1); 52586833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_IDR2, &idr2); 52596833Sgd78059 52606833Sgd78059 ERI_DEBUG_MSG4(erip, XCVR_MSG, 52616833Sgd78059 "eri_reset_xcvr: control %x stat %x anar %x", control, stat, anar); 52626833Sgd78059 52636833Sgd78059 /* 52646833Sgd78059 * Initialize the read only transceiver ndd information 52656833Sgd78059 * the values are either 0 or 1. 52666833Sgd78059 */ 52676833Sgd78059 param_bmsr_ancap = 1 && (stat & PHY_BMSR_ACFG); 52686833Sgd78059 param_bmsr_100T4 = 1 && (stat & PHY_BMSR_100T4); 52696833Sgd78059 param_bmsr_100fdx = 1 && (stat & PHY_BMSR_100FDX); 52706833Sgd78059 param_bmsr_100hdx = 1 && (stat & PHY_BMSR_100HDX); 52716833Sgd78059 param_bmsr_10fdx = 1 && (stat & PHY_BMSR_10FDX); 52726833Sgd78059 param_bmsr_10hdx = 1 && (stat & PHY_BMSR_10HDX); 52736833Sgd78059 52746833Sgd78059 /* 52756833Sgd78059 * Match up the ndd capabilities with the transceiver. 52766833Sgd78059 */ 52776833Sgd78059 param_autoneg &= param_bmsr_ancap; 52786833Sgd78059 param_anar_100fdx &= param_bmsr_100fdx; 52796833Sgd78059 param_anar_100hdx &= param_bmsr_100hdx; 52806833Sgd78059 param_anar_10fdx &= param_bmsr_10fdx; 52816833Sgd78059 param_anar_10hdx &= param_bmsr_10hdx; 52826833Sgd78059 52836833Sgd78059 /* 52846833Sgd78059 * Select the operation mode of the transceiver. 52856833Sgd78059 */ 52866833Sgd78059 if (param_autoneg) { 52876833Sgd78059 /* 52886833Sgd78059 * Initialize our auto-negotiation capabilities. 52896833Sgd78059 */ 52906833Sgd78059 anar = PHY_SELECTOR; 52916833Sgd78059 if (param_anar_100T4) 52926833Sgd78059 anar |= PHY_ANAR_T4; 52936833Sgd78059 if (param_anar_100fdx) 52946833Sgd78059 anar |= PHY_ANAR_TXFDX; 52956833Sgd78059 if (param_anar_100hdx) 52966833Sgd78059 anar |= PHY_ANAR_TX; 52976833Sgd78059 if (param_anar_10fdx) 52986833Sgd78059 anar |= PHY_ANAR_10FDX; 52996833Sgd78059 if (param_anar_10hdx) 53006833Sgd78059 anar |= PHY_ANAR_10; 53016833Sgd78059 ERI_DEBUG_MSG2(erip, XCVR_MSG, "anar = %x", anar); 53026833Sgd78059 eri_mii_write(erip, ERI_PHY_ANAR, anar); 53036833Sgd78059 } 53046833Sgd78059 53056833Sgd78059 /* Place the Transceiver in normal operation mode */ 53066833Sgd78059 if ((control & PHY_BMCR_ISOLATE) || (control & PHY_BMCR_LPBK)) { 53076833Sgd78059 control &= ~(PHY_BMCR_ISOLATE | PHY_BMCR_LPBK); 53086833Sgd78059 eri_mii_write(erip, ERI_PHY_BMCR, 53096833Sgd78059 (control & ~PHY_BMCR_ISOLATE)); 53106833Sgd78059 } 53116833Sgd78059 53126833Sgd78059 /* 53136833Sgd78059 * If Lu3X31T then allow nonzero eri_phy_mintrans 53146833Sgd78059 */ 53156833Sgd78059 if (eri_phy_mintrans && 53166833Sgd78059 (idr1 != 0x43 || (idr2 & 0xFFF0) != 0x7420)) { 53176833Sgd78059 eri_phy_mintrans = 0; 53186833Sgd78059 } 53196833Sgd78059 /* 53206833Sgd78059 * Initialize the mif interrupt mask. 53216833Sgd78059 */ 53226833Sgd78059 erip->mif_mask = (uint16_t)(~PHY_BMSR_RES1); 53236833Sgd78059 53246833Sgd78059 /* 53256833Sgd78059 * Establish link speeds and do necessary special stuff based 53266833Sgd78059 * in the speed. 53276833Sgd78059 */ 53286833Sgd78059 speed_100 = param_anar_100fdx | param_anar_100hdx; 53296833Sgd78059 speed_10 = param_anar_10fdx | param_anar_10hdx; 53306833Sgd78059 53316833Sgd78059 ERI_DEBUG_MSG5(erip, XCVR_MSG, "eri_reset_xcvr: %d %d %d %d", 53326833Sgd78059 param_anar_100fdx, param_anar_100hdx, param_anar_10fdx, 53336833Sgd78059 param_anar_10hdx); 53346833Sgd78059 53356833Sgd78059 ERI_DEBUG_MSG3(erip, XCVR_MSG, 53366833Sgd78059 "eri_reset_xcvr: speed_100 %d speed_10 %d", speed_100, speed_10); 53376833Sgd78059 53386833Sgd78059 if ((!speed_100) && (speed_10)) { 53396833Sgd78059 erip->mif_mask &= ~PHY_BMSR_JABDET; 53406833Sgd78059 if (!(param_anar_10fdx) && 53416833Sgd78059 (param_anar_10hdx) && 53426833Sgd78059 (erip->link_pulse_disabled)) { 53436833Sgd78059 param_speed = 0; 53446833Sgd78059 param_mode = 0; 53456833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_NICR, &nicr); 53466833Sgd78059 nicr &= ~PHY_NICR_LD; 53476833Sgd78059 eri_mii_write(erip, ERI_PHY_NICR, nicr); 53486833Sgd78059 param_linkup = 1; 53496833Sgd78059 erip->stats.link_up = LINK_STATE_UP; 53506833Sgd78059 if (param_mode) 53516833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_FULL; 53526833Sgd78059 else 53536833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_HALF; 53546833Sgd78059 } 53556833Sgd78059 } 53566833Sgd78059 53576833Sgd78059 /* 53586833Sgd78059 * Clear the autonegotitation before re-starting 53596833Sgd78059 */ 53606833Sgd78059 control = PHY_BMCR_100M | PHY_BMCR_FDX; 53616833Sgd78059 /* eri_mii_write(erip, ERI_PHY_BMCR, control); */ 53626833Sgd78059 if (param_autoneg) { 53636833Sgd78059 /* 53646833Sgd78059 * Setup the transceiver for autonegotiation. 53656833Sgd78059 */ 53666833Sgd78059 erip->mif_mask &= ~PHY_BMSR_ANC; 53676833Sgd78059 53686833Sgd78059 /* 53696833Sgd78059 * Clear the Auto-negotiation before re-starting 53706833Sgd78059 */ 53716833Sgd78059 eri_mii_write(erip, ERI_PHY_BMCR, control & ~PHY_BMCR_ANE); 53726833Sgd78059 53736833Sgd78059 /* 53746833Sgd78059 * Switch on auto-negotiation. 53756833Sgd78059 */ 53766833Sgd78059 control |= (PHY_BMCR_ANE | PHY_BMCR_RAN); 53776833Sgd78059 53786833Sgd78059 eri_mii_write(erip, ERI_PHY_BMCR, control); 53796833Sgd78059 } else { 53806833Sgd78059 /* 53816833Sgd78059 * Force the transceiver. 53826833Sgd78059 */ 53836833Sgd78059 erip->mif_mask &= ~PHY_BMSR_LNKSTS; 53846833Sgd78059 53856833Sgd78059 /* 53866833Sgd78059 * Switch off auto-negotiation. 53876833Sgd78059 */ 53886833Sgd78059 control &= ~(PHY_BMCR_FDX | PHY_BMCR_ANE | PHY_BMCR_RAN); 53896833Sgd78059 53906833Sgd78059 if (speed_100) { 53916833Sgd78059 control |= PHY_BMCR_100M; 53926833Sgd78059 param_aner_lpancap = 0; /* Clear LP nway */ 53936833Sgd78059 param_anlpar_10fdx = 0; 53946833Sgd78059 param_anlpar_10hdx = 0; 53956833Sgd78059 param_anlpar_100T4 = param_anar_100T4; 53966833Sgd78059 param_anlpar_100fdx = param_anar_100fdx; 53976833Sgd78059 param_anlpar_100hdx = param_anar_100hdx; 53986833Sgd78059 param_speed = 1; 53996833Sgd78059 erip->stats.ifspeed = 100; 54006833Sgd78059 param_mode = param_anar_100fdx; 54016833Sgd78059 if (param_mode) { 54026833Sgd78059 param_anlpar_100hdx = 0; 54036833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_FULL; 54046833Sgd78059 } else { 54056833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_HALF; 54066833Sgd78059 } 54076833Sgd78059 } else if (speed_10) { 54086833Sgd78059 control &= ~PHY_BMCR_100M; 54096833Sgd78059 param_aner_lpancap = 0; /* Clear LP nway */ 54106833Sgd78059 param_anlpar_100fdx = 0; 54116833Sgd78059 param_anlpar_100hdx = 0; 54126833Sgd78059 param_anlpar_100T4 = 0; 54136833Sgd78059 param_anlpar_10fdx = param_anar_10fdx; 54146833Sgd78059 param_anlpar_10hdx = param_anar_10hdx; 54156833Sgd78059 param_speed = 0; 54166833Sgd78059 erip->stats.ifspeed = 10; 54176833Sgd78059 param_mode = param_anar_10fdx; 54186833Sgd78059 if (param_mode) { 54196833Sgd78059 param_anlpar_10hdx = 0; 54206833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_FULL; 54216833Sgd78059 } else { 54226833Sgd78059 erip->stats.link_duplex = LINK_DUPLEX_HALF; 54236833Sgd78059 } 54246833Sgd78059 } else { 54256833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, 54266833Sgd78059 "Transceiver speed set incorrectly."); 54276833Sgd78059 } 54286833Sgd78059 54296833Sgd78059 if (param_mode) { 54306833Sgd78059 control |= PHY_BMCR_FDX; 54316833Sgd78059 } 54326833Sgd78059 54336833Sgd78059 ERI_DEBUG_MSG4(erip, PHY_MSG, 54346833Sgd78059 "control = %x status = %x param_mode %d", 54356833Sgd78059 control, stat, param_mode); 54366833Sgd78059 54376833Sgd78059 eri_mii_write(erip, ERI_PHY_BMCR, control); 54386833Sgd78059 /* 54396833Sgd78059 * if (param_mode) { 54406833Sgd78059 * control |= PHY_BMCR_FDX; 54416833Sgd78059 * } 54426833Sgd78059 * control &= ~(PHY_BMCR_FDX | PHY_BMCR_ANE | PHY_BMCR_RAN); 54436833Sgd78059 * eri_mii_write(erip, ERI_PHY_BMCR, control); 54446833Sgd78059 */ 54456833Sgd78059 } 54466833Sgd78059 54476833Sgd78059 #ifdef DEBUG 54486833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_BMCR, &control); 54496833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_BMSR, &stat); 54506833Sgd78059 (void) eri_mii_read(erip, ERI_PHY_ANAR, &anar); 54516833Sgd78059 #endif 54526833Sgd78059 ERI_DEBUG_MSG4(erip, PHY_MSG, 54536833Sgd78059 "control %X status %X anar %X", control, stat, anar); 54546833Sgd78059 54556833Sgd78059 eri_reset_xcvr_exit: 54566833Sgd78059 return (0); 54576833Sgd78059 54586833Sgd78059 eri_reset_xcvr_failed: 54596833Sgd78059 return (1); 54606833Sgd78059 } 54616833Sgd78059 54626833Sgd78059 #ifdef ERI_10_10_FORCE_SPEED_WORKAROUND 54636833Sgd78059 54646833Sgd78059 static void 54656833Sgd78059 eri_xcvr_force_mode(struct eri *erip, uint32_t *link_timeout) 54666833Sgd78059 { 54676833Sgd78059 54686833Sgd78059 if (!param_autoneg && !param_linkup && (erip->stats.ifspeed == 10) && 54696833Sgd78059 (param_anar_10fdx | param_anar_10hdx)) { 54706833Sgd78059 *link_timeout = SECOND(1); 54716833Sgd78059 return; 54726833Sgd78059 } 54736833Sgd78059 54746833Sgd78059 if (!param_autoneg && !param_linkup && (erip->ifspeed_old == 10) && 54756833Sgd78059 (param_anar_100fdx | param_anar_100hdx)) { 54766833Sgd78059 /* 54776833Sgd78059 * May have to set link partner's speed and mode. 54786833Sgd78059 */ 54796833Sgd78059 ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_LOG_MSG, 54806833Sgd78059 "May have to set link partner's speed and duplex mode."); 54816833Sgd78059 } 54826833Sgd78059 } 54836833Sgd78059 #endif 54846833Sgd78059 54856833Sgd78059 static void 54866833Sgd78059 eri_mif_poll(struct eri *erip, soft_mif_enable_t enable) 54876833Sgd78059 { 54886833Sgd78059 if (enable == MIF_POLL_START) { 54896833Sgd78059 if (erip->mifpoll_enable && !erip->openloop_autoneg) { 54906833Sgd78059 erip->mif_config |= ERI_MIF_CFGPE; 54916833Sgd78059 PUT_MIFREG(mif_cfg, erip->mif_config); 54926833Sgd78059 drv_usecwait(ERI_MIF_POLL_DELAY); 54936833Sgd78059 PUT_GLOBREG(intmask, GET_GLOBREG(intmask) & 54946833Sgd78059 ~ERI_G_MASK_MIF_INT); 54956833Sgd78059 PUT_MIFREG(mif_imask, erip->mif_mask); 54966833Sgd78059 } 54976833Sgd78059 } else if (enable == MIF_POLL_STOP) { 54986833Sgd78059 erip->mif_config &= ~ERI_MIF_CFGPE; 54996833Sgd78059 PUT_MIFREG(mif_cfg, erip->mif_config); 55006833Sgd78059 drv_usecwait(ERI_MIF_POLL_DELAY); 55016833Sgd78059 PUT_GLOBREG(intmask, GET_GLOBREG(intmask) | 55026833Sgd78059 ERI_G_MASK_MIF_INT); 55036833Sgd78059 PUT_MIFREG(mif_imask, ERI_MIF_INTMASK); 55046833Sgd78059 } 55056833Sgd78059 ERI_DEBUG_MSG2(erip, XCVR_MSG, "MIF Config = 0x%X", 55066833Sgd78059 GET_MIFREG(mif_cfg)); 55076833Sgd78059 ERI_DEBUG_MSG2(erip, XCVR_MSG, "MIF imask = 0x%X", 55086833Sgd78059 GET_MIFREG(mif_imask)); 55096833Sgd78059 ERI_DEBUG_MSG2(erip, XCVR_MSG, "INT imask = 0x%X", 55106833Sgd78059 GET_GLOBREG(intmask)); 55116833Sgd78059 ERI_DEBUG_MSG1(erip, XCVR_MSG, "<== mif_poll"); 55126833Sgd78059 } 55136833Sgd78059 55146833Sgd78059 /* Decide if transmitter went dead and reinitialize everything */ 55156833Sgd78059 #ifdef ERI_TX_HUNG 55166833Sgd78059 static int eri_txhung_limit = 2; 55176833Sgd78059 static int 55186833Sgd78059 eri_check_txhung(struct eri *erip) 55196833Sgd78059 { 55206833Sgd78059 boolean_t macupdate = B_FALSE; 55216833Sgd78059 55226833Sgd78059 mutex_enter(&erip->xmitlock); 55236833Sgd78059 if (erip->flags & ERI_RUNNING) 55246833Sgd78059 erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) & 55256833Sgd78059 ETX_COMPLETION_MASK); 55266833Sgd78059 macupdate |= eri_reclaim(erip, erip->tx_completion); 55276833Sgd78059 55286833Sgd78059 /* Something needs to be sent out but it is not going out */ 55296833Sgd78059 if ((erip->tcurp != erip->tnextp) && 55306833Sgd78059 (erip->stats.opackets64 == erip->erisave.reclaim_opackets) && 55316833Sgd78059 (erip->stats.collisions == erip->erisave.starts)) 55326833Sgd78059 erip->txhung++; 55336833Sgd78059 else 55346833Sgd78059 erip->txhung = 0; 55356833Sgd78059 55366833Sgd78059 erip->erisave.reclaim_opackets = erip->stats.opackets64; 55376833Sgd78059 erip->erisave.starts = erip->stats.collisions; 55386833Sgd78059 mutex_exit(&erip->xmitlock); 55396833Sgd78059 55406833Sgd78059 if (macupdate) 55416833Sgd78059 mac_tx_update(erip->mh); 55426833Sgd78059 55436833Sgd78059 return (erip->txhung >= eri_txhung_limit); 55446833Sgd78059 } 55456833Sgd78059 #endif 5546